Wednesday 17 July 2013

Roslyn - The June and Sept 2012 releases broke some of the examples and updates were not provided

Arg! As the title says, the June and September 2012 releases of Roslyn made some API changes which meant that some of the published examples, even ones on the Roslyn page itself, no longer compile. Of particular note is this example, wherein the author shows us how to highlight broken usages of Enumerable.Count(). If you're not aware, Enumerable.Count() will almost certainly enumerate the entire sequence. The broken usage is illustrated by code like this
var l = < some enumerable > ;
return l.Count()>0;
Nooooo! Don't do it! Use Any()! Anyway, the code example given by the Roslyn peeps no longer compiles because the GetSemanticInfo() function has been removed and replaced with a host of other, context-specific, functions. If you want the example to compile, these changes will fix it up for you.
        private bool IsCallToEnumerableCount(IDocument document, ExpressionSyntax expression, CancellationToken cancellationToken)
        {
            var invocation = expression as InvocationExpressionSyntax;
            if (invocation == null) return false;
            var call = invocation.Expression as MemberAccessExpressionSyntax;
            if (call == null) return false;

            var semanticModel = document.GetSemanticModel(cancellationToken);
            var methodSymbol = semanticModel.GetSymbolInfo(expression).Symbol as MethodSymbol;
            if (methodSymbol == null || methodSymbol.Name != "Count" || methodSymbol.ConstructedFrom == null) return false;

            var enumerable = semanticModel.Compilation.GetTypeByMetadataName(typeof(Enumerable).FullName);
            if (enumerable == null || !methodSymbol.ConstructedFrom.ContainingType.Equals(enumerable)) return false;

            return true;
        }
and
        private bool IsRelevantRightSideComparison(IDocument document, ExpressionSyntax expression, SyntaxKind kind, CancellationToken cancellationToken)
        {
            var constant = document.GetSemanticModel(cancellationToken).GetConstantValue(expression);
            int? value;
            if(!constant.HasValue || (value = constant.Value as int?) == null) return false;

            if (kind == SyntaxKind.GreaterThanExpression && value == 0 || kind == SyntaxKind.GreaterThanOrEqualExpression && value == 1) return true;

            return false;
        }
Obviously you will have to make the same changes to IsRelevantLeftSideComparison but I'll leave that to you, the diligent reader ;-) In case you are wondering, the changes are to replace GetSemanticInfo() with GetSymbolInfo().Symbol in the initial check function and then with GetConstantValue() in the comparison checking function. Easy, but it took me an hour or two to track it down because all I could find on t'internet were comments saying that GetSemanticInfo() had been removed but not how to use the replacements. Doh!

No comments:

Post a Comment