private static bool IsNullCheck(
            StatementSyntax statement,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (statement.IsKind(SyntaxKind.IfStatement))
            {
                var ifStatement = (IfStatementSyntax)statement;

                var binaryExpression = ifStatement.Condition as BinaryExpressionSyntax;

                if (binaryExpression?.Right?.IsKind(SyntaxKind.NullLiteralExpression) == true)
                {
                    ExpressionSyntax left = binaryExpression.Left;

                    if (left.IsKind(SyntaxKind.IdentifierName))
                    {
                        var throwStatement = GetSingleStatementOrDefault(ifStatement) as ThrowStatementSyntax;

                        if (throwStatement?.Expression?.IsKind(SyntaxKind.ObjectCreationExpression) == true)
                        {
                            var objectCreation = (ObjectCreationExpressionSyntax)throwStatement.Expression;

                            INamedTypeSymbol exceptionType = semanticModel.GetTypeByMetadataName(MetadataNames.System_ArgumentNullException);

                            ISymbol type = semanticModel.GetSymbol(objectCreation.Type, cancellationToken);

                            return(type?.Equals(exceptionType) == true);
                        }
                    }
                }
            }

            return(false);
        }
        private static bool CheckSpeculativeSymbol(
            AnonymousFunctionExpressionSyntax anonymousFunction,
            ExpressionSyntax expression,
            IMethodSymbol methodSymbol,
            SemanticModel semanticModel)
        {
            SymbolInfo symbolInfo = semanticModel.GetSpeculativeSymbolInfo(anonymousFunction.SpanStart, expression, SpeculativeBindingOption.BindAsExpression);

            ISymbol symbol = symbolInfo.Symbol;

            if (symbol?.Equals(methodSymbol) == true)
                return true;

            ImmutableArray<ISymbol> candidateSymbols = symbolInfo.CandidateSymbols;

            if (candidateSymbols.Any())
            {
                if (candidateSymbols.Length == 1)
                {
                    if (candidateSymbols[0].Equals(methodSymbol))
                        return true;
                }
                else if (!anonymousFunction.WalkUpParentheses().IsParentKind(SyntaxKind.Argument, SyntaxKind.AttributeArgument))
                {
                    foreach (ISymbol candidateSymbol in candidateSymbols)
                    {
                        if (candidateSymbol.Equals(methodSymbol))
                            return true;
                    }
                }
            }

            return false;
        }
 private static bool HasCheckForNullThatReturns(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol)
 {
     var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration) as MethodDeclarationSyntax;
     if (method != null && method.Body != null)
     {
         var ifs = method.Body.Statements.OfKind(SyntaxKind.IfStatement);
         foreach (IfStatementSyntax @if in ifs)
         {
             if ([email protected]?.IsKind(SyntaxKind.EqualsExpression) ?? true) continue;
             var equals = (BinaryExpressionSyntax)@if.Condition;
             if (equals.Left == null || equals.Right == null) continue;
             if (@if.GetLocation().SourceSpan.Start > invocation.GetLocation().SourceSpan.Start) return false;
             ISymbol identifierSymbol;
             if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName))
                 identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol;
             else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName))
                 identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol;
             else continue;
             if (!symbol.Equals(identifierSymbol)) continue;
             if (@if.Statement == null) continue;
             if (@if.Statement.IsKind(SyntaxKind.Block))
             {
                 var ifBlock = (BlockSyntax)@if.Statement;
                 if (ifBlock.Statements.OfKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement).Any()) return true;
             }
             else
             {
                 if (@if.Statement.IsAnyKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement)) return true;
             }
         }
     }
     return false;
 }
Ejemplo n.º 4
0
        public static bool IsStaticClassInScope(
            SyntaxNode node,
            INamedTypeSymbol staticClassSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (staticClassSymbol == null)
            {
                throw new ArgumentNullException(nameof(staticClassSymbol));
            }

            if (semanticModel == null)
            {
                throw new ArgumentNullException(nameof(semanticModel));
            }

            foreach (NameSyntax name in StaticClassesInScope(node))
            {
                ISymbol symbol = semanticModel.GetSymbol(name, cancellationToken);

                if (symbol?.Equals(staticClassSymbol) == true)
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 5
0
        public static ISymbol FindImplementationForAbstractMember(this INamedTypeSymbol type, ISymbol symbol)
        {
            if (symbol.IsAbstract)
            {
                return type.GetBaseTypesAndThis().SelectMany(t => t.GetMembers(symbol.Name))
                                                 .FirstOrDefault(s => symbol.Equals(GetOverriddenMember(s)));
            }

            return null;
        }
Ejemplo n.º 6
0
        //XPERF:
        private static bool IsReferencedAsMethodGroup(SyntaxNodeAnalysisContext context, MethodDeclarationSyntax methodDeclaration)
        {
            ISymbol methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken);

            string methodName = methodSymbol.Name;

            foreach (SyntaxReference syntaxReference in methodSymbol.ContainingType.DeclaringSyntaxReferences)
            {
                SyntaxNode typeDeclaration = syntaxReference.GetSyntax(context.CancellationToken);

                SemanticModel semanticModel = null;

                foreach (SyntaxNode node in typeDeclaration.DescendantNodes())
                {
                    if (node.IsKind(SyntaxKind.IdentifierName))
                    {
                        var identifierName = (IdentifierNameSyntax)node;

                        if (string.Equals(methodName, identifierName.Identifier.ValueText, StringComparison.Ordinal) &&
                            !IsInvoked(identifierName))
                        {
                            if (semanticModel == null)
                            {
                                semanticModel = (context.SemanticModel.SyntaxTree == typeDeclaration.SyntaxTree)
                                    ? context.SemanticModel
                                    : context.Compilation.GetSemanticModel(typeDeclaration.SyntaxTree);
                            }

                            if (methodSymbol.Equals(semanticModel.GetSymbol(identifierName, context.CancellationToken)))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 7
0
        protected bool ExpressionContainsValuePatternOrReferencesInitializedSymbol(SyntaxNode expression)
        {
            foreach (var subExpression in expression.DescendantNodesAndSelf().OfType <TExpressionSyntax>())
            {
                if (!_syntaxFacts.IsNameOfMemberAccessExpression(subExpression))
                {
                    if (ValuePatternMatches(subExpression))
                    {
                        return(true);
                    }
                }

                if (_initializedSymbol != null &&
                    _initializedSymbol.Equals(
                        _semanticModel.GetSymbolInfo(subExpression, _cancellationToken).GetAnySymbol()))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 8
0
        private static bool IsDangerousMemberSymbol(
            ISymbol memberSymbol,
            IImmutableSet <ISymbol> dangerousMembers
            )
        {
            ISymbol originalDefinition = memberSymbol.OriginalDefinition;

            if (dangerousMembers.Contains(originalDefinition))
            {
                return(true);
            }

            if (!memberSymbol.Equals(originalDefinition, SymbolEqualityComparer.Default))
            {
                if (dangerousMembers.Contains(memberSymbol))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 9
0
        internal static async Task <bool> OriginalSymbolsMatchAsync(
            Solution solution,
            ISymbol searchSymbol,
            ISymbol?symbolToMatch,
            CancellationToken cancellationToken)
        {
            if (ReferenceEquals(searchSymbol, symbolToMatch))
            {
                return(true);
            }

            if (searchSymbol == null || symbolToMatch == null)
            {
                return(false);
            }

            // Avoid the expensive checks if we can fast path when the compiler just says these are equal. Also, for the
            // purposes of symbol finding nullability of symbols doesn't affect things, so just use the default
            // comparison.
            if (searchSymbol.Equals(symbolToMatch))
            {
                return(true);
            }

            if (await OriginalSymbolsMatchCoreAsync(solution, searchSymbol, symbolToMatch, cancellationToken).ConfigureAwait(false))
            {
                return(true);
            }

            if (searchSymbol.Kind == SymbolKind.Namespace && symbolToMatch.Kind == SymbolKind.Namespace)
            {
                // if one of them is a merged namespace symbol and other one is its constituent namespace symbol, they are equivalent.
                var namespace1      = (INamespaceSymbol)searchSymbol;
                var namespace2      = (INamespaceSymbol)symbolToMatch;
                var namespace1Count = namespace1.ConstituentNamespaces.Length;
                var namespace2Count = namespace2.ConstituentNamespaces.Length;
                if (namespace1Count != namespace2Count)
                {
                    if ((namespace1Count > 1 && await namespace1.ConstituentNamespaces.AnyAsync(static (n, arg) => NamespaceSymbolsMatchAsync(arg.solution, n, arg.namespace2, arg.cancellationToken), (solution, namespace2, cancellationToken)).ConfigureAwait(false)) ||
Ejemplo n.º 10
0
        private void CheckDefiniteAssignment(
            SemanticModel semanticModel, ISymbol localVariable, SyntaxNode node,
            out bool isAssigned, out bool isAccessedBeforeAssignment,
            CancellationToken cancellationToken)
        {
            if (node != null)
            {
                foreach (var id in node.DescendantNodes().OfType <IdentifierNameSyntax>())
                {
                    var symbol = semanticModel.GetSymbolInfo(id, cancellationToken).GetAnySymbol();
                    if (localVariable.Equals(symbol))
                    {
                        isAssigned = id.IsOnlyWrittenTo();
                        isAccessedBeforeAssignment = !isAssigned;
                        return;
                    }
                }
            }

            isAssigned = false;
            isAccessedBeforeAssignment = false;
        }
        private void InspectMemberAccess(
            SyntaxNodeAnalysisContext context,
            MemberAccessExpressionSyntax memberAccessSyntax,
            IEnumerable <CommonInterest.SyncBlockingMethod> problematicMethods,
            INamedTypeSymbol taskSymbol)
        {
            // Are we in the context of an anonymous function that is passed directly in as an argument to another method?
            var anonymousFunctionSyntax     = context.Node.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>();
            var anonFuncAsArgument          = anonymousFunctionSyntax?.Parent as ArgumentSyntax;
            var invocationPassingExpression = anonFuncAsArgument?.Parent?.Parent as InvocationExpressionSyntax;
            var invokedMemberAccess         = invocationPassingExpression?.Expression as MemberAccessExpressionSyntax;

            if (invokedMemberAccess?.Name != null)
            {
                // Does the anonymous function appear as the first argument to Task.ContinueWith?
                var invokedMemberSymbol = context.SemanticModel.GetSymbolInfo(invokedMemberAccess.Name).Symbol as IMethodSymbol;
                if (invokedMemberSymbol?.Name == nameof(Task.ContinueWith) &&
                    Utils.IsEqualToOrDerivedFrom(invokedMemberSymbol?.ContainingType, taskSymbol) &&
                    invocationPassingExpression?.ArgumentList?.Arguments.FirstOrDefault() == anonFuncAsArgument)
                {
                    // Does the member access being analyzed belong to the Task that just completed?
                    var firstParameter = GetFirstParameter(anonymousFunctionSyntax);
                    if (firstParameter != null)
                    {
                        // Are we accessing a member of the completed task?
                        ISymbol          invokedObjectSymbol = context.SemanticModel.GetSymbolInfo(memberAccessSyntax?.Expression).Symbol;
                        IParameterSymbol completedTask       = context.SemanticModel.GetDeclaredSymbol(firstParameter);
                        if (invokedObjectSymbol.Equals(completedTask))
                        {
                            // Skip analysis since Task.Result (et. al) of a completed Task is fair game.
                            return;
                        }
                    }
                }
            }

            CommonInterest.InspectMemberAccess(context, memberAccessSyntax, Descriptor, problematicMethods);
        }
        protected bool NameBoundSuccessfullyToSameSymbol(INamedTypeSymbol symbol)
        {
            ImmutableArray <ISymbol> normalSymbols = ShouldRestrictMinimallyQualifyLookupToNamespacesAndTypes()
                ? semanticModelOpt.LookupNamespacesAndTypes(positionOpt, name: symbol.Name)
                : semanticModelOpt.LookupSymbols(positionOpt, name: symbol.Name);
            ISymbol normalSymbol = SingleSymbolWithArity(normalSymbols, symbol.Arity);

            if (normalSymbol == null)
            {
                return(false);
            }

            // Binding normally ended up with the right symbol.  We can definitely use the
            // simplified name.
            if (normalSymbol.Equals(symbol.OriginalDefinition))
            {
                return(true);
            }

            // Binding normally failed.  We may be in a "Color Color" situation where 'Color'
            // will bind to the field, but we could still allow simplification here.
            ImmutableArray <ISymbol> typeOnlySymbols = semanticModelOpt.LookupNamespacesAndTypes(positionOpt, name: symbol.Name);
            ISymbol typeOnlySymbol = SingleSymbolWithArity(typeOnlySymbols, symbol.Arity);

            if (typeOnlySymbol == null)
            {
                return(false);
            }

            var type1 = GetSymbolType(normalSymbol);
            var type2 = GetSymbolType(typeOnlySymbol);

            return
                (type1 != null &&
                 type2 != null &&
                 type1.Equals(type2) &&
                 typeOnlySymbol.Equals(symbol.OriginalDefinition));
        }
        public static bool CanRefactor(
            AwaitExpressionSyntax awaitExpression,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (awaitExpression == null)
            {
                throw new ArgumentNullException(nameof(awaitExpression));
            }

            if (semanticModel == null)
            {
                throw new ArgumentNullException(nameof(semanticModel));
            }

            if (awaitExpression.Expression?.IsKind(SyntaxKind.InvocationExpression) == true &&
                ReturnsTask((InvocationExpressionSyntax)awaitExpression.Expression, semanticModel, cancellationToken))
            {
                ISymbol symbol = semanticModel
                                 .GetSymbolInfo(awaitExpression.Expression, cancellationToken)
                                 .Symbol;

                if (symbol?.IsErrorType() == false)
                {
                    INamedTypeSymbol configuredTaskSymbol = semanticModel
                                                            .Compilation
                                                            .GetTypeByMetadataName("System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1");

                    if (configuredTaskSymbol != null &&
                        !symbol.Equals(configuredTaskSymbol))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 14
0
        public override void VisitIdentifierName(IdentifierNameSyntax node)
        {
            _cancellationToken.ThrowIfCancellationRequested();

            if (string.Equals(node.Identifier.ValueText, _name))
            {
                if (_symbol == null)
                {
                    _symbol = _semanticModel.GetSymbol(_identifierName, _cancellationToken);

                    if (_symbol?.IsErrorType() != false)
                    {
                        IsFixable = false;
                        return;
                    }
                }

                if (_symbol.Equals(_semanticModel.GetSymbol(node, _cancellationToken)))
                {
                    ExpressionSyntax n = node;

                    if (n.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) &&
                        ((MemberAccessExpressionSyntax)n.Parent).Expression.IsKind(SyntaxKind.ThisExpression))
                    {
                        n = (ExpressionSyntax)n.Parent;
                    }

                    if (!n.WalkUpParentheses().IsParentKind(SyntaxKind.CastExpression))
                    {
                        IsFixable = false;
                        return;
                    }

                    IsFixable = true;
                }
            }
        }
        private static bool IsDisposedBefore(ISymbol symbol, ExpressionSyntax assignment, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            using (var pooled = InvocationWalker.Create(assignment.FirstAncestorOrSelf <MemberDeclarationSyntax>()))
            {
                foreach (var invocation in pooled.Item.Invocations)
                {
                    if (invocation.IsBeforeInScope(assignment) != Result.Yes)
                    {
                        continue;
                    }

                    var invokedSymbol = semanticModel.GetSymbolSafe(invocation, cancellationToken);
                    if (invokedSymbol?.Name != "Dispose")
                    {
                        continue;
                    }

                    var statement = invocation.FirstAncestorOrSelf <StatementSyntax>();
                    if (statement != null)
                    {
                        using (var pooledNames = IdentifierNameWalker.Create(statement))
                        {
                            foreach (var identifierName in pooledNames.Item.IdentifierNames)
                            {
                                var otherSymbol = semanticModel.GetSymbolSafe(identifierName, cancellationToken);
                                if (symbol.Equals(otherSymbol))
                                {
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 16
0
        private static bool IsElementAccess(
            SyntaxNode node,
            ISymbol symbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (node.IsKind(SyntaxKind.IdentifierName))
            {
                SyntaxNode parent = node.Parent;

                if (parent?.IsKind(SyntaxKind.Argument) == true)
                {
                    parent = parent.Parent;

                    if (parent?.IsKind(SyntaxKind.BracketedArgumentList) == true)
                    {
                        parent = parent.Parent;

                        if (parent?.IsKind(SyntaxKind.ElementAccessExpression) == true)
                        {
                            var elementAccess = (ElementAccessExpressionSyntax)parent;

                            ExpressionSyntax expression = elementAccess.Expression;

                            if (expression != null)
                            {
                                ISymbol expressionSymbol = semanticModel.GetSymbol(expression, cancellationToken);

                                return(symbol.Equals(expressionSymbol));
                            }
                        }
                    }
                }
            }

            return(false);
        }
        public static bool IsValidAssignmentStatement(
            StatementSyntax statement,
            ISymbol symbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (statement.IsKind(SyntaxKind.ExpressionStatement))
            {
                var expressionStatement = (ExpressionStatementSyntax)statement;

                if (expressionStatement.Expression?.IsKind(SyntaxKind.SimpleAssignmentExpression) == true)
                {
                    var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

                    if (assignment.Left?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true)
                    {
                        var memberAccess = (MemberAccessExpressionSyntax)assignment.Left;

                        ISymbol expressionSymbol = semanticModel
                                                   .GetSymbolInfo(memberAccess.Expression, cancellationToken)
                                                   .Symbol;

                        if (symbol.Equals(expressionSymbol))
                        {
                            ISymbol leftSymbol = semanticModel.GetSymbolInfo(assignment.Left, cancellationToken).Symbol;

                            if (leftSymbol?.IsProperty() == true)
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
        private static bool IsNullCheck(
            StatementSyntax statement,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!(statement is IfStatementSyntax ifStatement))
            {
                return(false);
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull);

            if (!nullCheck.Success)
            {
                return(false);
            }

            if (nullCheck.Expression.Kind() != SyntaxKind.IdentifierName)
            {
                return(false);
            }

            var throwStatement = ifStatement.SingleNonBlockStatementOrDefault() as ThrowStatementSyntax;

            if (throwStatement?.Expression?.Kind() != SyntaxKind.ObjectCreationExpression)
            {
                return(false);
            }

            var objectCreation = (ObjectCreationExpressionSyntax)throwStatement.Expression;

            INamedTypeSymbol exceptionType = semanticModel.GetTypeByMetadataName(MetadataNames.System_ArgumentNullException);

            ISymbol type = semanticModel.GetSymbol(objectCreation.Type, cancellationToken);

            return(type?.Equals(exceptionType) == true);
        }
        private static bool IsLocalVariableReferenced(
            ISymbol symbol,
            string name,
            SyntaxNode node,
            TextSpan span,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            foreach (SyntaxNode descendant in node.DescendantNodesAndSelf(span))
            {
                if (descendant.IsKind(SyntaxKind.IdentifierName))
                {
                    var identifierName = (IdentifierNameSyntax)descendant;

                    if (string.Equals(identifierName.Identifier.ValueText, name, StringComparison.Ordinal) &&
                        symbol.Equals(semanticModel.GetSymbol(identifierName, cancellationToken)))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 20
0
        public static bool IsInterfaceImplementationOrMemberOverride(this ISymbol symbol)
        {
            if (symbol == null)
            {
                return(false);
            }

            if (!(symbol is IMethodSymbol) &&
                !(symbol is IPropertySymbol))
            {
                return(false);
            }

            if (symbol.IsOverride)
            {
                return(true);
            }

            return(symbol.ContainingType
                   .AllInterfaces
                   .SelectMany(@interface => @interface.GetMembers())
                   .Where(member => member is IMethodSymbol || member is IPropertySymbol)
                   .Any(member => symbol.Equals(symbol.ContainingType.FindImplementationForInterfaceMember(member))));
        }
Ejemplo n.º 21
0
            protected bool IsInstructionOnThisAndMatchesDeclaringSymbol(SyntaxNode node)
            {
                var expression = node as ExpressionSyntax;

                if (expression == null)
                {
                    return(false);
                }

                NameSyntax name = expression as NameSyntax;

                var memberAccess = expression as MemberAccessExpressionSyntax;

                if (memberAccess != null &&
                    memberAccess.Expression.IsKind(SyntaxKind.ThisExpression))
                {
                    name = memberAccess.Name as IdentifierNameSyntax;
                }

                var conditionalAccess = expression as ConditionalAccessExpressionSyntax;

                if (conditionalAccess != null &&
                    conditionalAccess.Expression.IsKind(SyntaxKind.ThisExpression))
                {
                    name = (conditionalAccess.WhenNotNull as MemberBindingExpressionSyntax)?.Name as IdentifierNameSyntax;
                }

                if (name == null)
                {
                    return(false);
                }

                var assignedSymbol = semanticModel.GetSymbolInfo(name).Symbol;

                return(declaringSymbol.Equals(assignedSymbol));
            }
        private static ISymbol GetBackingFieldSymbol(
            SyntaxNodeAnalysisContext context,
            AccessorDeclarationSyntax getter,
            AccessorDeclarationSyntax setter)
        {
            NameSyntax getterIdentifier = GetIdentifierFromGetter(getter);

            if (getterIdentifier != null)
            {
                NameSyntax setterIdentifier = GetIdentifierFromSetter(setter);

                if (setterIdentifier != null)
                {
                    ISymbol symbol = context
                                     .SemanticModel
                                     .GetSymbolInfo(getterIdentifier, context.CancellationToken)
                                     .Symbol;

                    if (symbol?.Kind == SymbolKind.Field &&
                        symbol.DeclaredAccessibility == Accessibility.Private)
                    {
                        ISymbol symbol2 = context
                                          .SemanticModel
                                          .GetSymbolInfo(setterIdentifier, context.CancellationToken)
                                          .Symbol;

                        if (symbol.Equals(symbol2))
                        {
                            return(symbol);
                        }
                    }
                }
            }

            return(null);
        }
        private static bool IsConditionThatChecksForNull(ExpressionSyntax condition, SemanticModel semanticModel, ISymbol symbol, SyntaxKind binarySyntaxKind)
        {
            if (condition == null)
            {
                return(false);
            }
            if (!condition.IsKind(binarySyntaxKind))
            {
                return(false);
            }
            var equals = (BinaryExpressionSyntax)condition;

            if (equals.Left == null || equals.Right == null)
            {
                return(false);
            }
            ISymbol identifierSymbol;

            if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName))
            {
                identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol;
            }
            else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName))
            {
                identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol;
            }
            else
            {
                return(false);
            }
            if (symbol.Equals(identifierSymbol))
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 24
0
        private static IFieldSymbol GetBackingFieldSymbol(
            SyntaxNodeAnalysisContext context,
            AccessorDeclarationSyntax getter,
            AccessorDeclarationSyntax setter)
        {
            NameSyntax getterIdentifier = GetIdentifierFromGetter(getter);

            if (getterIdentifier != null)
            {
                NameSyntax setterIdentifier = GetIdentifierFromSetter(setter);

                if (setterIdentifier != null)
                {
                    ISymbol symbol = context
                                     .SemanticModel
                                     .GetSymbolInfo(getterIdentifier, context.CancellationToken)
                                     .Symbol;

                    if (symbol?.IsField() == true &&
                        symbol.IsPrivate())
                    {
                        ISymbol symbol2 = context
                                          .SemanticModel
                                          .GetSymbolInfo(setterIdentifier, context.CancellationToken)
                                          .Symbol;

                        if (symbol.Equals(symbol2))
                        {
                            return((IFieldSymbol)symbol);
                        }
                    }
                }
            }

            return(null);
        }
        private static int IncludeAllReferencesOfSymbol(
            ISymbol symbol,
            SyntaxKind kind,
            SyntaxList<StatementSyntax> statements,
            int lastStatementIndex,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            for (int i = statements.Count - 1; i >= lastStatementIndex; i--)
            {
                foreach (SyntaxNode node in statements[i].DescendantNodes())
                {
                    if (node.IsKind(kind))
                    {
                        ISymbol symbol2 = semanticModel.GetSymbol(node, cancellationToken);

                        if (symbol.Equals(symbol2))
                            return i;
                    }
                }
            }

            return -1;
        }
Ejemplo n.º 26
0
        /// <summary>
        /// This does not handle the case where a method in a base type implicitly implements an
        /// interface method on behalf of one of its derived types.
        /// </summary>
        private bool IsInterfaceImplementation(ISymbol symbol)
        {
            if (symbol.DeclaredAccessibility != Accessibility.Public)
            {
                return(false);
            }

            var containingType        = symbol.ContainingType;
            var implementedInterfaces = containingType.AllInterfaces;

            foreach (var implementedInterface in implementedInterfaces)
            {
                var implementedInterfaceMembersWithSameName = implementedInterface.GetMembers(symbol.Name);
                foreach (var implementedInterfaceMember in implementedInterfaceMembersWithSameName)
                {
                    if (symbol.Equals(containingType.FindImplementationForInterfaceMember(implementedInterfaceMember)))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 27
0
        private void VerifyEquality(
            ISymbol symbol1,
            ISymbol symbol2,
            bool expectedIncludeNullability
            )
        {
            // Symbol.Equals
            Assert.True(symbol1.Equals(symbol1));
            Assert.True(symbol2.Equals(symbol2));
            Assert.True(symbol1.Equals(symbol2));
            Assert.True(symbol2.Equals(symbol1));

            // TypeSymbol.Equals - Default
            Assert.True(symbol1.Equals(symbol1, SymbolEqualityComparer.Default));
            Assert.True(symbol2.Equals(symbol2, SymbolEqualityComparer.Default));
            Assert.True(symbol1.Equals(symbol2, SymbolEqualityComparer.Default));
            Assert.True(symbol2.Equals(symbol1, SymbolEqualityComparer.Default));

            // TypeSymbol.Equals - IncludeNullability
            Assert.True(symbol1.Equals(symbol1, SymbolEqualityComparer.IncludeNullability));
            Assert.True(symbol2.Equals(symbol2, SymbolEqualityComparer.IncludeNullability));
            Assert.Equal(
                expectedIncludeNullability,
                symbol1.Equals(symbol2, SymbolEqualityComparer.IncludeNullability)
                );
            Assert.Equal(
                expectedIncludeNullability,
                symbol2.Equals(symbol1, SymbolEqualityComparer.IncludeNullability)
                );

            // GetHashCode
            Assert.Equal(symbol1.GetHashCode(), symbol2.GetHashCode());
            Assert.Equal(
                SymbolEqualityComparer.Default.GetHashCode(symbol1),
                SymbolEqualityComparer.Default.GetHashCode(symbol2)
                );
            Assert.Equal(
                SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol1),
                SymbolEqualityComparer.IncludeNullability.GetHashCode(symbol2)
                );
        }
            internal static async Task<IEnumerable<RenameLocation>> GetRenamableReferenceLocationsAsync(ISymbol referencedSymbol, ISymbol originalSymbol, ReferenceLocation location, Solution solution, CancellationToken cancellationToken)
            {
                var shouldIncludeSymbol = await ShouldIncludeSymbolAsync(referencedSymbol, originalSymbol, solution, true, cancellationToken).ConfigureAwait(false);
                if (!shouldIncludeSymbol)
                {
                    return SpecializedCollections.EmptyEnumerable<RenameLocation>();
                }

                // Implicit references are things like a foreach referencing GetEnumerator. We don't
                // want to consider those as part of the set
                if (location.IsImplicit)
                {
                    return SpecializedCollections.EmptyEnumerable<RenameLocation>();
                }

                var results = new List<RenameLocation>();

                // If we were originally naming an alias, then we'll only use the location if was
                // also bound through the alias
                if (originalSymbol.Kind == SymbolKind.Alias)
                {
                    if (originalSymbol.Equals(location.Alias))
                    {
                        results.Add(new RenameLocation(location, location.Document.Id));

                        // We also need to add the location of the alias
                        // itself
                        var aliasLocation = location.Alias.Locations.Single();
                        results.Add(new RenameLocation(aliasLocation, solution.GetDocument(aliasLocation.SourceTree).Id));
                    }
                }
                else
                {
                    // If we bound through an alias, we'll only rename if the alias's name matches
                    // the name of symbol it points to. We do this because it's common to see things
                    // like "using Foo = System.Foo" where people want to import a single type
                    // rather than a whole namespace of stuff.
                    if (location.Alias != null)
                    {
                        if (location.Alias.Name == referencedSymbol.Name)
                        {
                            results.Add(new RenameLocation(location.Location, location.Document.Id,
                                isCandidateLocation: location.IsCandidateLocation, isRenamableAliasUsage: true, isWrittenTo: location.IsWrittenTo));

                            // We also need to add the location of the alias itself
                            var aliasLocation = location.Alias.Locations.Single();
                            results.Add(new RenameLocation(aliasLocation, solution.GetDocument(aliasLocation.SourceTree).Id));
                        }
                    }
                    else
                    {
                        // The simple case, so just the single location and we're done
                        results.Add(new RenameLocation(
                            location.Location,
                            location.Document.Id,
                            isWrittenTo: location.IsWrittenTo,
                            isCandidateLocation: location.IsCandidateLocation,
                            isMethodGroupReference: location.IsCandidateLocation && location.CandidateReason == CandidateReason.MemberGroup,
                            isRenamableAccessor: await IsPropertyAccessorOrAnOverride(referencedSymbol, solution, cancellationToken).ConfigureAwait(false)));
                    }
                }

                return results;
            }
Ejemplo n.º 29
0
        private static bool SymbolsAreCompatibleCore(ISymbol symbol, ISymbol newSymbol, bool performEquivalenceCheck, bool requireNonNullSymbols = false)
        {
            if (symbol == null && newSymbol == null)
            {
                return(!requireNonNullSymbols);
            }

            if (symbol == null || newSymbol == null)
            {
                return(false);
            }

            if (symbol.IsReducedExtension())
            {
                symbol = ((IMethodSymbol)symbol).GetConstructedReducedFrom();
            }

            if (newSymbol.IsReducedExtension())
            {
                newSymbol = ((IMethodSymbol)newSymbol).GetConstructedReducedFrom();
            }

            // TODO: Lambda function comparison performs syntax equality, hence is non-trivial to compare lambda methods across different compilations.
            // For now, just assume they are equal.
            if (symbol.IsAnonymousFunction())
            {
                return(newSymbol.IsAnonymousFunction());
            }

            if (performEquivalenceCheck)
            {
                // We are comparing symbols across two semantic models (where neither is the speculative model of other one).
                // We will use the SymbolEquivalenceComparer to check if symbols are equivalent.

                switch (symbol.Kind)
                {
                // SymbolEquivalenceComparer performs Location equality checks for Locals, Labels and RangeVariables.
                // As we are comparing symbols from different semantic models, locations will differ.
                // Hence perform minimal checks for these symbol kinds.
                case SymbolKind.Local:
                    return(newSymbol.Kind == SymbolKind.Local &&
                           newSymbol.IsImplicitlyDeclared == symbol.IsImplicitlyDeclared &&
                           string.Equals(symbol.Name, newSymbol.Name, StringComparison.Ordinal) &&
                           ((ILocalSymbol)newSymbol).Type.Equals(((ILocalSymbol)symbol).Type));

                case SymbolKind.Label:
                case SymbolKind.RangeVariable:
                    return(newSymbol.Kind == symbol.Kind && string.Equals(newSymbol.Name, symbol.Name, StringComparison.Ordinal));

                case SymbolKind.Parameter:
                    if (newSymbol.Kind == SymbolKind.Parameter && symbol.ContainingSymbol.IsAnonymousFunction())
                    {
                        var param    = (IParameterSymbol)symbol;
                        var newParam = (IParameterSymbol)newSymbol;
                        return(param.IsRefOrOut() == newParam.IsRefOrOut() &&
                               param.Name == newParam.Name &&
                               SymbolEquivalenceComparer.Instance.Equals(param.Type, newParam.Type) &&
                               newSymbol.ContainingSymbol.IsAnonymousFunction());
                    }

                    goto default;

                default:
                    return(SymbolEquivalenceComparer.Instance.Equals(symbol, newSymbol));
                }
            }

            if (symbol.Equals(newSymbol))
            {
                return(true);
            }

            // Handle equivalence of special built-in comparison operators between enum types and it's underlying enum type.
            if (symbol.Kind == SymbolKind.Method && newSymbol.Kind == SymbolKind.Method)
            {
                var methodSymbol    = (IMethodSymbol)symbol;
                var newMethodSymbol = (IMethodSymbol)newSymbol;

                PredefinedOperator originalOp, newOp;
                if (methodSymbol.TryGetPredefinedComparisonOperator(out originalOp) &&
                    newMethodSymbol.TryGetPredefinedComparisonOperator(out newOp) &&
                    originalOp == newOp)
                {
                    var type    = methodSymbol.ContainingType;
                    var newType = newMethodSymbol.ContainingType;
                    if ((type != null && type.IsEnumType() &&
                         type.EnumUnderlyingType != null && type.EnumUnderlyingType.SpecialType == newType.SpecialType) ||
                        (newType != null && newType.IsEnumType() &&
                         newType.EnumUnderlyingType != null && newType.EnumUnderlyingType.SpecialType == type.SpecialType))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 30
0
        private bool IsCompatibleInterfaceMemberImplementation(
            ISymbol symbol,
            ISymbol newSymbol,
            TExpressionSyntax originalInvocationExpression,
            TExpressionSyntax newInvocationExpression,
            TSemanticModel speculativeSemanticModel)
        {
            // If this is an interface member, we have to be careful. In general,
            // we have to treat an interface member as incompatible with the new member
            // due to virtual dispatch. I.e. A member in a sub class may be preferred
            // at runtime and we have no way of knowing that at compile-time.
            //
            // However, there are special circumstances where we can be sure
            // that the interface member won't result in virtual dispatch:
            //
            //     * The new member is on an effectively sealed class, i.e. at least one of the following is true for the containing type:
            //          (a) It is a sealed class.
            //          (b) It has no nested classes and no accessible instance constructors.
            //          (c) It is a private class with no nested or sibling classes.
            //     * The new member is on System.Array.
            //     * The new member is on System.Delegate.
            //     * The new member is on System.Enum.
            //     * The member is on a struct that we are sure we have a unique copy
            //       of (for example, if it's returned to us by an invocation,
            //       object-creation, element-access or member-access expression.

            INamedTypeSymbol newSymbolContainingType = newSymbol.ContainingType;

            if (newSymbolContainingType == null)
            {
                return(false);
            }

            var         newReceiver     = GetReceiver(newInvocationExpression);
            ITypeSymbol newReceiverType = newReceiver != null?
                                          speculativeSemanticModel.GetTypeInfo(newReceiver).ConvertedType:
                                          newSymbolContainingType;

            if (newReceiverType == null)
            {
                return(false);
            }

            if (newReceiverType.IsReferenceType &&
                !IsEffectivelySealedClass(newReceiverType) &&
                newSymbolContainingType.SpecialType != SpecialType.System_Array &&
                newSymbolContainingType.SpecialType != SpecialType.System_Delegate &&
                newSymbolContainingType.SpecialType != SpecialType.System_Enum &&
                !IsReceiverUniqueInstance(newReceiver, speculativeSemanticModel))
            {
                return(false);
            }

            if (newReceiverType.IsValueType && newReceiverType.SpecialType == SpecialType.None)
            {
                if (newReceiver == null ||
                    !IsReceiverUniqueInstance(newReceiver, speculativeSemanticModel))
                {
                    return(false);
                }
            }

            var implementationMember = newSymbolContainingType.FindImplementationForInterfaceMember(symbol);

            if (implementationMember == null)
            {
                return(false);
            }

            if (!newSymbol.Equals(implementationMember))
            {
                return(false);
            }

            return(SymbolsHaveCompatibleParameterLists(symbol, implementationMember, originalInvocationExpression));
        }
        private static bool HasCheckForNullThatReturns(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol)
        {
            var method = invocation.FirstAncestorOfKind(SyntaxKind.MethodDeclaration) as MethodDeclarationSyntax;

            if (method != null && method.Body != null)
            {
                var ifs = method.Body.Statements.OfKind(SyntaxKind.IfStatement);
                foreach (IfStatementSyntax @if in ifs)
                {
                    if ([email protected]?.IsKind(SyntaxKind.EqualsExpression) ?? true)
                    {
                        continue;
                    }
                    var equals = (BinaryExpressionSyntax)@if.Condition;
                    if (equals.Left == null || equals.Right == null)
                    {
                        continue;
                    }
                    if (@if.GetLocation().SourceSpan.Start > invocation.GetLocation().SourceSpan.Start)
                    {
                        return(false);
                    }
                    ISymbol identifierSymbol;
                    if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName))
                    {
                        identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol;
                    }
                    else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName))
                    {
                        identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol;
                    }
                    else
                    {
                        continue;
                    }
                    if (!symbol.Equals(identifierSymbol))
                    {
                        continue;
                    }
                    if (@if.Statement == null)
                    {
                        continue;
                    }
                    if (@if.Statement.IsKind(SyntaxKind.Block))
                    {
                        var ifBlock = (BlockSyntax)@if.Statement;
                        if (ifBlock.Statements.OfKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement).Any())
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        if (@if.Statement.IsAnyKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
 private static bool IsInsideANullCheck(InvocationExpressionSyntax invocation, SemanticModel semanticModel, ISymbol symbol)
 {
     var ifs = invocation.Ancestors().OfType<IfStatementSyntax>();
     foreach (IfStatementSyntax @if in ifs)
     {
         if ([email protected]?.IsKind(SyntaxKind.NotEqualsExpression) ?? true) continue;
         var equals = (BinaryExpressionSyntax)@if.Condition;
         if (equals.Left == null || equals.Right == null) continue;
         ISymbol identifierSymbol;
         if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName))
             identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol;
         else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName))
             identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol;
         else continue;
         if (symbol.Equals(identifierSymbol)) return true;
     }
     return false;
 }
Ejemplo n.º 33
0
        /// <summary>
        /// Returns whether or not a member is implementing an interface member.
        /// </summary>
        /// <remarks>
        /// This method does only check the interfaces the containing type is implementing directly.
        /// If a derived class is implementing an interface and this member is required for it
        /// this method will still return false.
        /// </remarks>
        /// <param name="memberSymbol">The member symbol that should be analyzed.</param>
        /// <returns>true if the member is implementing an interface member, otherwise false.</returns>
        internal static bool IsImplementingAnInterfaceMember(ISymbol memberSymbol)
        {
            if (memberSymbol.IsStatic)
            {
                return false;
            }

            IMethodSymbol methodSymbol;
            IPropertySymbol propertySymbol;
            IEventSymbol eventSymbol;
            bool isImplementingExplicitly;

            // Only methods, properties and events can implement an interface member
            if ((methodSymbol = memberSymbol as IMethodSymbol) != null)
            {
                // Check if the member is implementing an interface explicitly
                isImplementingExplicitly = methodSymbol.ExplicitInterfaceImplementations.Any();
            }
            else if ((propertySymbol = memberSymbol as IPropertySymbol) != null)
            {
                // Check if the member is implementing an interface explicitly
                isImplementingExplicitly = propertySymbol.ExplicitInterfaceImplementations.Any();
            }
            else if ((eventSymbol = memberSymbol as IEventSymbol) != null)
            {
                // Check if the member is implementing an interface explicitly
                isImplementingExplicitly = eventSymbol.ExplicitInterfaceImplementations.Any();
            }
            else
            {
                return false;
            }

            if (isImplementingExplicitly)
            {
                return true;
            }

            var typeSymbol = memberSymbol.ContainingType;

            return typeSymbol != null && typeSymbol.AllInterfaces
                .SelectMany(m => m.GetMembers(memberSymbol.Name))
                .Select(typeSymbol.FindImplementationForInterfaceMember)
                .Any(x => memberSymbol.Equals(x));
        }
        private bool IsAccessed(
            SemanticModel semanticModel,
            ISymbol outSymbol, 
            BlockSyntax enclosingBlockOfLocalStatement,
            LocalDeclarationStatementSyntax localStatement, 
            ArgumentSyntax argumentNode,
            CancellationToken cancellationToken)
        {
            var localStatementStart = localStatement.Span.Start;
            var argumentNodeStart = argumentNode.Span.Start;
            var variableName = outSymbol.Name;

            // Walk the block that the local is declared in looking for accesses.
            // We can ignore anything prior to the actual local declaration point,
            // and we only need to check up until we reach the out-argument.
            foreach (var descendentNode in enclosingBlockOfLocalStatement.DescendantNodes())
            {
                var descendentStart = descendentNode.Span.Start;
                if (descendentStart <= localStatementStart)
                {
                    // This node is before the local declaration.  Can ignore it entirely as it could
                    // not be an access to the local.
                    continue;
                }

                if (descendentStart >= argumentNodeStart)
                {
                    // We reached the out-var.  We can stop searching entirely.
                    break;
                }

                if (descendentNode.IsKind(SyntaxKind.IdentifierName))
                {
                    // See if this looks like an accessor to the local variable syntactically.
                    var identifierName = (IdentifierNameSyntax)descendentNode;
                    if (identifierName.Identifier.ValueText == variableName)
                    {
                        // Confirm that it is a access of the local.
                        var symbol = semanticModel.GetSymbolInfo(identifierName, cancellationToken).Symbol;
                        if (outSymbol.Equals(symbol))
                        {
                            // We definitely accessed the local before the out-argument.  We 
                            // can't inline this local.
                            return true;
                        }
                    }
                }
            }

            // No accesses detected
            return false;
        }
 public static bool IsImplementationOfInterfaceMember(this ISymbol symbol, ISymbol interfaceMember)
 {
     return(interfaceMember != null &&
            symbol.Equals(symbol.ContainingType.FindImplementationForInterfaceMember(interfaceMember)));
 }
        private static void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context)
        {
            var usingStatement = (UsingStatementSyntax)context.Node;

            StatementSyntax statement = usingStatement.Statement;

            if (statement?.Kind() != SyntaxKind.Block)
            {
                return;
            }

            var block = (BlockSyntax)statement;

            StatementSyntax lastStatement = block.Statements.LastOrDefault();

            if (lastStatement == null)
            {
                return;
            }

            if (lastStatement.SpanContainsDirectives())
            {
                return;
            }

            SimpleMemberInvocationStatementInfo info = SyntaxInfo.SimpleMemberInvocationStatementInfo(lastStatement);

            if (!info.Success)
            {
                return;
            }

            if (info.Arguments.Any())
            {
                return;
            }

            string methodName = info.NameText;

            if (methodName != "Dispose" && methodName != "Close")
            {
                return;
            }

            ExpressionSyntax usingExpression = usingStatement.Expression;

            if (usingExpression != null)
            {
                if (CSharpFactory.AreEquivalent(info.Expression, usingExpression))
                {
                    ReportDiagnostic(context, info.Statement, methodName);
                }
            }
            else
            {
                VariableDeclarationSyntax usingDeclaration = usingStatement.Declaration;

                if (usingDeclaration != null &&
                    info.Expression.Kind() == SyntaxKind.IdentifierName)
                {
                    var identifierName = (IdentifierNameSyntax)info.Expression;

                    VariableDeclaratorSyntax declarator = usingDeclaration.Variables.LastOrDefault();

                    if (declarator != null &&
                        declarator.Identifier.ValueText == identifierName.Identifier.ValueText)
                    {
                        ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken);

                        if (symbol?.Equals(context.SemanticModel.GetSymbol(identifierName, context.CancellationToken)) == true)
                        {
                            ReportDiagnostic(context, info.Statement, methodName);
                        }
                    }
                }
            }
        }
Ejemplo n.º 37
0
        /// <summary>
        /// Maps the given reference to the given symbol.
        /// </summary>
        /// <param name="reference">Reference</param>
        /// <param name="symbol">Symbol</param>
        /// <param name="syntaxNode">SyntaxNode</param>
        /// <param name="cfgNode">CfgNode</param>
        /// <param name="markReset">Should mark symbol as reset</param>
        internal void MapRefToSymbol(ISymbol reference, ISymbol symbol, SyntaxNode syntaxNode,
            ControlFlowGraphNode cfgNode, bool markReset = true)
        {
            if (!this.Map.ContainsKey(cfgNode))
            {
                this.Map.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>());
                this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>());
            }
            else if (!this.Map[cfgNode].ContainsKey(syntaxNode))
            {
                this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>());
            }

            HashSet<ISymbol> additionalRefs = new HashSet<ISymbol>();
            if (this.Map[cfgNode][syntaxNode].ContainsKey(reference))
            {
                foreach (var r in this.Map[cfgNode][syntaxNode][reference])
                {
                    if (!reference.Equals(r))
                    {
                        additionalRefs.Add(r);
                    }
                }
            }

            if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol) && additionalRefs.Count > 0)
            {
                this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol>();
            }
            else if (additionalRefs.Count > 0)
            {
                this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol>());
            }
            else if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol))
            {
                this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol> { reference };
            }
            else
            {
                this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol> { reference });
            }

            foreach (var r in additionalRefs)
            {
                this.Map[cfgNode][syntaxNode][symbol].Add(r);
            }

            if (markReset)
            {
                this.MarkSymbolReassignment(symbol, syntaxNode, cfgNode);
            }
        }
Ejemplo n.º 38
0
        /// <summary>
        /// Returns true if the given symbol flows into the target symbol.
        /// </summary>
        /// <param name="symbol">Symbol</param>
        /// <param name="target">Target</param>
        /// <param name="syntaxNode">SyntaxNode</param>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="targetSyntaxNode">Target syntaxNode</param>
        /// <param name="targetCfgNode">Target controlFlowGraphNode</param>
        /// <returns>Boolean</returns>
        internal static bool FlowsIntoTarget(ISymbol symbol, ISymbol target, SyntaxNode syntaxNode,
            ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode)
        {
            Dictionary<ISymbol, HashSet<ISymbol>> dataFlowMap = null;
            if (!targetCfgNode.Summary.DataFlowMap.TryGetMapForSyntaxNode(targetSyntaxNode,
                targetCfgNode, out dataFlowMap) || !dataFlowMap.ContainsKey(symbol))
            {
                return false;
            }

            if (symbol.Equals(target) && cfgNode.Summary.DataFlowMap.DoesSymbolReset(
                symbol, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode))
            {
                return false;
            }

            Dictionary<ISymbol, HashSet<ISymbol>> reachabilityMap = null;
            if (targetCfgNode.Summary.DataFlowMap.TryGetReachabilityMapForSyntaxNode(targetSyntaxNode,
                targetCfgNode, out reachabilityMap) && reachabilityMap.ContainsKey(symbol))
            {
                foreach (var field in reachabilityMap[symbol])
                {
                    foreach (var reference in dataFlowMap[field])
                    {
                        dataFlowMap[symbol].Add(reference);
                    }
                }
            }

            foreach (var reference in dataFlowMap[symbol])
            {
                if (reference.Equals(target))
                {
                    return true;
                }
            }

            if (dataFlowMap.ContainsKey(target))
            {
                foreach (var reference in dataFlowMap[target])
                {
                    if (!cfgNode.Summary.DataFlowMap.DoesSymbolReset(symbol, syntaxNode,
                        cfgNode, targetSyntaxNode, targetCfgNode))
                    {
                        if (reference.Equals(symbol))
                        {
                            return true;
                        }

                        foreach (var symbolRef in dataFlowMap[symbol])
                        {
                            if (reference.Equals(symbolRef))
                            {
                                return true;
                            }
                        }
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// This method can be used to determine if the specified block of
        /// statements contains an initializer for the specified symbol.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="symbol">The symbol.</param>
        /// <param name="statements">The statements.</param>
        /// <returns>
        /// The initializer state found
        /// </returns>
        /// <remarks>
        /// Code blocks that might not always be called are:
        /// - An if or else statement.
        /// - The body of a for, while or for-each loop.
        /// - Switch statements
        ///
        /// The following exceptions are taken into account:
        /// - If both if and else statements contain a certain initialization.
        /// - If all cases in a switch contain a certain initialization (this means a default case must exist as well).
        ///
        /// Please note that this is a recursive function so we can check a block of code in an if statement for example.
        /// </remarks>
        private static InitializerState DoesBlockContainCertainInitializer(SyntaxNodeAnalysisContext context, ISymbol symbol, IEnumerable<StatementSyntax> statements)
        {
            // Keep track of the current initializer state. This can only be None
            // or Initializer, WayToSkipInitializer will always be returned immediately.
            // Only way to go back from Initializer to None is if there is an assignment
            // to null after a previous assignment to a non-null value.
            var currentState = InitializerState.None;

            foreach (var statement in statements)
            {
                if (statement.IsKind(SyntaxKind.ReturnStatement) && currentState == InitializerState.None)
                {
                    return InitializerState.WayToSkipInitializer;
                }
                else if (statement.IsKind(SyntaxKind.Block))
                {
                    var blockResult = DoesBlockContainCertainInitializer(context, symbol, ((BlockSyntax)statement).Statements);
                    if (CanSkipInitializer(blockResult, currentState))
                        return InitializerState.WayToSkipInitializer;
                    if (blockResult == InitializerState.Initializer)
                        currentState = blockResult;
                }
                else if (statement.IsKind(SyntaxKind.UsingStatement))
                {
                    var blockResult = DoesBlockContainCertainInitializer(context, symbol, new[] { ((UsingStatementSyntax)statement).Statement });
                    if (CanSkipInitializer(blockResult, currentState))
                        return InitializerState.WayToSkipInitializer;
                    if (blockResult == InitializerState.Initializer)
                        currentState = blockResult;
                }
                else if (statement.IsKind(SyntaxKind.ExpressionStatement))
                {
                    var expression = ((ExpressionStatementSyntax)statement).Expression;
                    if (expression.IsKind(SyntaxKind.SimpleAssignmentExpression))
                    {
                        var assignmentExpression = (AssignmentExpressionSyntax)expression;
                        var identifier = assignmentExpression.Left;
                        if (identifier != null)
                        {
                            var right = assignmentExpression.Right;
                            if (right != null)
                            {
                                if (right.IsKind(SyntaxKind.NullLiteralExpression))
                                    currentState = InitializerState.None;
                                else if (symbol.Equals(context.SemanticModel.GetSymbolInfo(identifier).Symbol))
                                    currentState = InitializerState.Initializer;
                            }
                        }
                    }
                }
                else if (statement.IsKind(SyntaxKind.SwitchStatement))
                {
                    var switchStatement = (SwitchStatementSyntax)statement;
                    if (switchStatement.Sections.Any(s => s.Labels.Any(l => l.IsKind(SyntaxKind.DefaultSwitchLabel))))
                    {
                        var sectionInitializerStates = switchStatement.Sections.Select(s => DoesBlockContainCertainInitializer(context, symbol, s.Statements)).ToList();
                        if (sectionInitializerStates.All(sectionInitializerState => sectionInitializerState == InitializerState.Initializer))
                            currentState = InitializerState.Initializer;
                        else if (sectionInitializerStates.Any(sectionInitializerState => CanSkipInitializer(sectionInitializerState, currentState)))
                            return InitializerState.WayToSkipInitializer;
                    }
                }
                else if (statement.IsKind(SyntaxKind.IfStatement))
                {
                    var ifStatement = (IfStatementSyntax)statement;

                    var ifResult = DoesBlockContainCertainInitializer(context, symbol, new[] { ifStatement.Statement });
                    if (ifStatement.Else != null)
                    {
                        var elseResult = DoesBlockContainCertainInitializer(context, symbol, new[] { ifStatement.Else.Statement });

                        if (ifResult == InitializerState.Initializer && elseResult == InitializerState.Initializer)
                            currentState = InitializerState.Initializer;
                        if (CanSkipInitializer(elseResult, currentState))
                            return InitializerState.WayToSkipInitializer;
                    }
                    if (CanSkipInitializer(ifResult, currentState))
                    {
                        return InitializerState.WayToSkipInitializer;
                    }
                }
            }
            return currentState;
        }
            private static async Task<bool> ShouldIncludeSymbolAsync(
                ISymbol referencedSymbol, ISymbol originalSymbol, Solution solution, bool considerSymbolReferences, CancellationToken cancellationToken)
            {
                if (referencedSymbol.IsPropertyAccessor())
                {
                    return considerSymbolReferences;
                }

                if (referencedSymbol.Equals(originalSymbol))
                {
                    return true;
                }

                // Parameters of properties and methods can cascade to each other in
                // indexer scenarios.
                if (originalSymbol.Kind == SymbolKind.Parameter && referencedSymbol.Kind == SymbolKind.Parameter)
                {
                    return true;
                }

                // If the original symbol is a property, cascade to the backing field
                if (referencedSymbol.Kind == SymbolKind.Field && originalSymbol.Equals(((IFieldSymbol)referencedSymbol).AssociatedSymbol))
                {
                    return true;
                }

                // If the symbol doesn't actually exist in source, we never want to rename it
                if (referencedSymbol.IsImplicitlyDeclared)
                {
                    return considerSymbolReferences;
                }

                // We can cascade from members to other members only if the names match. The example
                // where the names might be different is explicit interface implementations in
                // Visual Basic and VB's identifiers are case insensitive. 
                // Do not cascade to symbols that are defined only in metadata.
                if (referencedSymbol.Kind == originalSymbol.Kind &&
                    string.Compare(TrimNameToAfterLastDot(referencedSymbol.Name), TrimNameToAfterLastDot(originalSymbol.Name), StringComparison.OrdinalIgnoreCase) == 0 &&
                    referencedSymbol.Locations.Any(loc => loc.IsInSource))
                {
                    return true;
                }

                // If the original symbol is an alias, then the referenced symbol will be where we
                // actually see references.
                if (originalSymbol.Kind == SymbolKind.Alias)
                {
                    var target = ((IAliasSymbol)originalSymbol).Target;

                    return target.TypeSwitch(
                        (INamedTypeSymbol nt) => nt.ConstructedFrom.Equals(referencedSymbol),
                        (INamespaceOrTypeSymbol s) => s.Equals(referencedSymbol));
                }

                // cascade from property accessor to property (someone in C# renames base.get_X, or the accessor override)
                if (await IsPropertyAccessorOrAnOverride(referencedSymbol, solution, cancellationToken).ConfigureAwait(false) ||
                    await IsPropertyAccessorOrAnOverride(originalSymbol, solution, cancellationToken).ConfigureAwait(false))
                {
                    return true;
                }

                if (referencedSymbol.ContainingSymbol != null &&
                    referencedSymbol.ContainingSymbol.Kind == SymbolKind.NamedType &&
                    ((INamedTypeSymbol)referencedSymbol.ContainingSymbol).TypeKind == TypeKind.Interface &&
                    !originalSymbol.ExplicitInterfaceImplementations().Any(s => s.Equals(referencedSymbol)))
                {
                    return true;
                }

                return false;
            }
        private static bool IsInterfaceImplementation(ISymbol symbol)
        {
            var containingType = symbol.ContainingType;

            return containingType.AllInterfaces
                .SelectMany(interf => interf.GetMembers().OfType<IMethodSymbol>())
                .Any(interfaceMember => symbol.Equals(containingType.FindImplementationForInterfaceMember(interfaceMember)));
        }
        private void CheckDefiniteAssignment(
            SemanticModel semanticModel, ISymbol localVariable, SyntaxNode node,
            out bool isAssigned, out bool isAccessedBeforeAssignment,
            CancellationToken cancellationToken)
        {
            if (node != null)
            {
                foreach (var id in node.DescendantNodes().OfType<IdentifierNameSyntax>())
                {
                    var symbol = semanticModel.GetSymbolInfo(id, cancellationToken).GetAnySymbol();
                    if (localVariable.Equals(symbol))
                    {
                        isAssigned = id.IsOnlyWrittenTo();
                        isAccessedBeforeAssignment = !isAssigned;
                        return;
                    }
                }
            }

            isAssigned = false;
            isAccessedBeforeAssignment = false;
        }
        private bool WouldCauseDefiniteAssignmentErrors(
            SemanticModel semanticModel, VariableDeclaratorSyntax localDeclarator, 
            BlockSyntax enclosingBlock, ISymbol outSymbol, CancellationToken cancellationToken)
        {
            // See if we have something like:
            //
            //      int i = 0;
            //      if (Foo() || Bar(out i))
            //      {
            //          Console.WriteLine(i);
            //      }
            //
            // In this case, inlining the 'i' would cause it to longer be definitely
            // assigned in the WriteLine invocation.

            if (localDeclarator.Initializer == null)
            {
                // Don't need to examine this unless the variable has an initializer.
                return false;
            }

            // Find all the current read-references to the local.
            var query = from t in enclosingBlock.DescendantTokens()
                        where t.Kind() == SyntaxKind.IdentifierToken
                        where t.ValueText == outSymbol.Name
                        let id = t.Parent as IdentifierNameSyntax
                        where id != null
                        where !id.IsOnlyWrittenTo()
                        let symbol = semanticModel.GetSymbolInfo(id).GetAnySymbol()
                        where outSymbol.Equals(symbol)
                        select id;

            var references = query.ToImmutableArray<SyntaxNode>();

            var root = semanticModel.SyntaxTree.GetCompilationUnitRoot(cancellationToken);

            // Ensure we can track the references and the local variable as we make edits
            // to the tree.
            var rootWithTrackedNodes = root.TrackNodes(references.Concat(localDeclarator).Concat(enclosingBlock));

            // Now, take the local variable and remove it's initializer.  Then go to all
            // the locations where we read from it.  If they're definitely assigned, then
            // that means the out-var did it's work and assigned the variable across all
            // paths. If it's not definitely assigned, then we can't inline this variable.
            var currentLocalDeclarator = rootWithTrackedNodes.GetCurrentNode(localDeclarator);
            var rootWithoutInitializer = rootWithTrackedNodes.ReplaceNode(
                currentLocalDeclarator,
                currentLocalDeclarator.WithInitializer(null));

            // Fork the compilation so we can do this analysis.
            var newCompilation = semanticModel.Compilation.ReplaceSyntaxTree(
                root.SyntaxTree, rootWithoutInitializer.SyntaxTree);
            var newSemanticModel = newCompilation.GetSemanticModel(rootWithoutInitializer.SyntaxTree);

            // NOTE: there is no current compiler API to determine if a variable is definitely
            // assigned or not.  So, for now, we just get diagnostics for this block and see if
            // we get any definite assigment errors where we have a reference to the symbol. If
            // so, then we don't offer the fix.

            var currentBlock = rootWithoutInitializer.GetCurrentNode(enclosingBlock);
            var diagnostics = newSemanticModel.GetDiagnostics(currentBlock.Span, cancellationToken);

            var diagnosticSpans = diagnostics.Where(d => d.Id == CS0165)
                                             .Select(d => d.Location.SourceSpan)
                                             .Distinct();

            var newReferenceSpans = rootWithoutInitializer.GetCurrentNodes<SyntaxNode>(references)
                                                          .Select(n => n.Span)
                                                          .Distinct();

            return diagnosticSpans.Intersect(newReferenceSpans).Any();
        }
 private static bool IsConditionThatChecksForNull(ExpressionSyntax condition, SemanticModel semanticModel, ISymbol symbol, SyntaxKind binarySyntaxKind)
 {
     if (condition == null) return false;
     if (!condition.IsKind(binarySyntaxKind)) return false;
     var equals = (BinaryExpressionSyntax)condition;
     if (equals.Left == null || equals.Right == null) return false;
     ISymbol identifierSymbol;
     if (equals.Right.IsKind(SyntaxKind.NullLiteralExpression) && equals.Left.IsKind(SyntaxKind.IdentifierName))
         identifierSymbol = semanticModel.GetSymbolInfo(equals.Left).Symbol;
     else if (equals.Left.IsKind(SyntaxKind.NullLiteralExpression) && equals.Right.IsKind(SyntaxKind.IdentifierName))
         identifierSymbol = semanticModel.GetSymbolInfo(equals.Right).Symbol;
     else return false;
     if (symbol.Equals(identifierSymbol)) return true;
     return false;
 }
            bool IsAmbiguous(ISymbol typeSymbol, SyntaxNode initializer, ITypeSymbol initializerSymbol)
            {
                if (!typeSymbol.Equals(initializerSymbol))
                {
                    // An implicit conversion or something similar is at play - using an implicit declaration will
                    // have a semantic change.  Consequently, we consider the declaration ambiguous.
                    return true;
                }

                if (initializer is LiteralExpressionSyntax)
                {
                    // A literal initializer is not ambiguous per C# style guidelines.
                    return false;
                }

                var ambiguityDetector = new InitializerAmbiguityDetector(this.semanticModel, typeSymbol);
                ambiguityDetector.Visit(initializer);
                return ambiguityDetector.IsAmbiguous;
            }