예제 #1
0
        private static void UpdateInvocationLocation(
            SyntaxNodeAnalysisContext context,
            ISymbol symbol,
            SimpleNameSyntax currentAccessNode,
            GetAccessInfoDelegate getAccessInfo)
        {
            var symbolInfo = _applicationBuilderSymbolInfos.GetOrCreateValue(symbol);

            var scopeEnclosingNode =
                currentAccessNode.FirstAncestorOrSelf <CSharpSyntaxNode>(IsScopeEnclosingNode);

            lock (symbolInfo)
            {
                if (!symbolInfo.Scopes.TryGetValue(scopeEnclosingNode, out var scopeInfo))
                {
                    symbolInfo.Scopes[scopeEnclosingNode] = scopeInfo = new ScopeInfo();
                }

                if (scopeInfo.DiagnosticReported)
                {
                    return;
                }

                ref var existingAccessInfo = ref getAccessInfo(scopeInfo);

                if (existingAccessInfo.location == null ||
                    currentAccessNode.GetLocation().SourceSpan.Start < existingAccessInfo.location.SourceSpan.Start)
                {
                    existingAccessInfo = (currentAccessNode.GetLocation(), currentAccessNode.ToString());
                    VerifyInvocationOrder(context, scopeInfo);
                }
            }
예제 #2
0
        private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            // Skip invocations that aren't made on member access expressions.
            // We want something like app.Xyz()
            var invocationNode = (InvocationExpressionSyntax)context.Node;

            if (!(invocationNode.Expression is MemberAccessExpressionSyntax memberAccess))
            {
                return;
            }

            var name = memberAccess.Name.ToString();
            GetAccessInfoDelegate getAccessInfo =
                name == UseGoogleTrace ? scopeInfo => ref scopeInfo.UseGoogleTraceAccessInfo :
                name.StartsWith(UseMvc) ? scopeInfo => ref scopeInfo.UseMvcAccessInfo :
                default(GetAccessInfoDelegate);

            if (getAccessInfo == null)
            {
                return;
            }

            // Walk up a chain of method calls on IApplicationBuilder (if there is one), and see if
            // there is a local/parameter/field/property symbol at the end of the chain. If so, record
            // the name access for that symbol.
            var nameAccessNode = memberAccess.Name;
            var semanticModel  = context.SemanticModel;

            do
            {
                var symbol = semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol;

                // TODO: Do we want to support things that are reference convertible to IApplicationBuilder as well?
                // All receivers of the method invocations must be of type IApplicationBuilder.
                if (symbol?.Type()?.ToDisplayString() != IApplicationBuilderFullName)
                {
                    break;
                }

                switch (symbol.Kind)
                {
                case SymbolKind.Local:
                case SymbolKind.Field:
                case SymbolKind.Parameter:
                case SymbolKind.Property:
                    UpdateInvocationLocation(context, symbol, nameAccessNode, getAccessInfo);
                    return;

                case SymbolKind.Method:
                    // Walk up the chain...
                    memberAccess =
                        (memberAccess.Expression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax;
                    break;
                }
            }while (memberAccess != null);
        }