tags:

views:

33

answers:

1

Due to certain reasons, in our ASP.NET web application, it is not recommended to use Response.Redirect("something", True). It should be used with False for the endResponse parameter. We want to enforce this with a custom FxCop rule. I've managed to find the usages of Response.Redirect, but now I want to find the value of the endResponse argument. How can I do this?

We're using the following code:

public override ProblemCollection Check(Member member)
{
    var method = member as Method;
    if (method != null)
    {
        foreach (var instruction in method.Instructions)
        {
            switch (instruction.OpCode)
            {
                case OpCode.Call:
                case OpCode.Callvirt:
                case OpCode.Newobj:
                    var call = (Method) instruction.Value;
                    if (call == null)
                    {
                        break;
                    }
                    if (call.Name.Name != "Redirect")
                    {
                        break;
                    }
                    if (call.Parameters.Count == 1)
                    {
                        //Redirect(url)
                        var resolution = GetResolution();
                        var problem = new Problem(resolution);
                        Problems.Add(problem);
                    }
                    if (call.Parameters.Count == 2)
                    {
                        VisitStatements(call.Body.Statements);
                    }
                    break;
                default:
                    break;
            }
        }
    }

    return Problems;
}

public override void VisitExpression(Expression expression)
{
    var methodCall = expression as MethodCall;
    if (methodCall == null)
    {
        return;
    }

    foreach (var operand in methodCall.Operands)
    {
        if (operand.Type.Name.Name == "Int16" || operand.Type.Name.Name == "Int32" || operand.Type.Name.Name == "Int64")
        {
            var literal = operand as Literal;
            if (literal != null && literal.Value is int)
            {
                var literalValue = (int)literal.Value;
                if (literalValue == 1)
                {
                    var resolution = GetResolution();
                    var problem = new Problem(resolution);
                    Problems.Add(problem);
                }
            }
        }
    }
}

I've used Introspector and thought the endResponse parameter was an integer behind the scenes, but I'm not so sure anymore. Anyway, there don't seem to be any booleans in the methodCall.Operands.

Has anyone ever had a similar situation, where you need to check the actual value of a parameter that's passed to a method?

+1  A: 

While the parameter type is actually a System.Boolean, the FxCop IL parser is treating it as an integer. Here's a simplified version of the rule that should work (assuming you want non-literal endResponse values to trigger a rule violation):

    public override ProblemCollection Check(Member member)
    {
        Method method = member as Method;
        if (method != null)
        {
            this.Visit(method.Body);
        }

        return this.Problems;
    }

    public override void VisitMethodCall(MethodCall call)
    {
        base.VisitMethodCall(call);

        Method targetMethod = (Method)((MemberBinding)call.Callee).BoundMember;
        if (targetMethod.DeclaringType.FullName.Equals("System.Web.HttpResponse", StringComparison.Ordinal) &&
            targetMethod.Name.Name.Equals("Redirect", StringComparison.Ordinal))
        {
            bool callIsAcceptable = false;

            if (targetMethod.Parameters.Count == 2)
            {
                Expression endResponseOperand = call.Operands[1];
                if (endResponseOperand.NodeType == NodeType.Literal)
                {
                    if ((int)((Literal)endResponseOperand).Value == 1)
                    {
                        callIsAcceptable = true;
                    }
                }
            }

            if (!callIsAcceptable)
            {
                this.Problems.Add(new Problem(this.GetResolution(), call));
            }
        }
    }
Nicole Calinoiu
This works, thanks! I changed it to .Value == 0 because that's what we want. Also, I noticed that if there are two vioaltions to this rule in one method, both are added to the Problems collection, but only one shows in FxCop. If I then fix the first violation, the second one will show when I do a new analysis.Other than that, it works, and we can use this code. Thanks.
Peter
The FxCop UI application groups violations by their target. If look at the issues list for a message, you'll see the full list of violations.
Nicole Calinoiu
Strange, I had this problem in a test project. When putting the code in the real project, I get all the correct errors. Thanks for all the help anyway!
Peter