private void GetSymbolAndIndicesForMemberReference(IMemberReferenceOperation memberReference, ref ISymbol symbolOpt, ref ImmutableArray <AbstractIndex> indices)
        {
            switch (memberReference)
            {
            case IFieldReferenceOperation fieldReference:
                symbolOpt = fieldReference.Member;
                break;

            case IEventReferenceOperation eventReference:
                symbolOpt = eventReference.Member;
                break;

            case IPropertyReferenceOperation propertyReference:
                // We are only tracking:
                // 1) Indexers
                // 2) Read-only properties.
                // 3) Properties with a backing field (auto-generated properties)
                if (propertyReference.Arguments.Length > 0 ||
                    propertyReference.Property.IsReadOnly ||
                    propertyReference.Property.IsPropertyWithBackingField())
                {
                    symbolOpt = propertyReference.Property;
                    indices   = propertyReference.Arguments.Length > 0 ?
                                CreateAbstractIndices(propertyReference.Arguments.Select(a => a.Value).ToImmutableArray()) :
                                ImmutableArray <AbstractIndex> .Empty;
                }
                break;
            }
        }
        private void UpdateLocation(
            SemanticModel semanticModel, INamedTypeSymbol interfaceType,
            SyntaxEditor editor, ISyntaxFactsService syntaxFacts,
            Location location, CancellationToken cancellationToken)
        {
            var identifierName = location.FindNode(getInnermostNodeForTie: true, cancellationToken);

            if (identifierName == null || !syntaxFacts.IsIdentifierName(identifierName))
            {
                return;
            }

            var node = syntaxFacts.IsNameOfMemberAccessExpression(identifierName) || syntaxFacts.IsMemberBindingExpression(identifierName.Parent)
                ? identifierName.Parent
                : identifierName;

            if (syntaxFacts.IsInvocationExpression(node.Parent))
            {
                node = node.Parent;
            }

            var operation = semanticModel.GetOperation(node);
            var instance  = operation switch
            {
                IMemberReferenceOperation memberReference => memberReference.Instance,
                IInvocationOperation invocation => invocation.Instance,
                _ => null,
            };

            if (instance == null)
            {
                return;
            }

            if (instance.IsImplicit)
            {
                if (instance is IInstanceReferenceOperation instanceReference &&
                    instanceReference.ReferenceKind != InstanceReferenceKind.ContainingTypeInstance)
                {
                    return;
                }

                // Accessing the member not off of <dot>.  i.e just plain `Goo()`.  Replace with
                // ((IGoo)this).Goo();
                var generator = editor.Generator;
                editor.ReplaceNode(
                    identifierName,
                    generator.MemberAccessExpression(
                        generator.AddParentheses(generator.CastExpression(interfaceType, generator.ThisExpression())),
                        identifierName.WithoutTrivia()).WithTriviaFrom(identifierName));
            }
            else
            {
                // Accessing the member like `x.Goo()`.  Replace with `((IGoo)x).Goo()`
                editor.ReplaceNode(
                    instance.Syntax, (current, g) =>
                    g.AddParentheses(
                        g.CastExpression(interfaceType, current.WithoutTrivia())).WithTriviaFrom(current));
            }
        }
示例#3
0
        private void AnalyzeAssignment(OperationAnalysisContext context)
        {
            var assignmentOperation = (ISimpleAssignmentOperation)context.Operation;

            // Check if there are more then one assignment in a statement
            if (assignmentOperation.Target is not IMemberReferenceOperation operationTarget)
            {
                return;
            }

            // This analyzer makes sense only for reference type objects
            if (operationTarget.Instance?.Type?.IsReferenceType != true)
            {
                return;
            }

            bool isViolationFound = operationTarget.Instance switch
            {
                ILocalReferenceOperation localInstance =>
                AnalyzeAssignmentToMember(assignmentOperation, localInstance, (a, b) => a.Local.Equals(b.Local)),
                IMemberReferenceOperation memberInstance =>
                AnalyzeAssignmentToMember(assignmentOperation, memberInstance, (a, b) => a.Member.Equals(b.Member) && a.Instance?.Syntax.ToString() == b.Instance?.Syntax.ToString()),
                IParameterReferenceOperation parameterInstance =>
                AnalyzeAssignmentToMember(assignmentOperation, parameterInstance, (a, b) => a.Parameter.Equals(b.Parameter)),
                _ => false,
            };

            if (isViolationFound)
            {
                var diagnostic = operationTarget.CreateDiagnostic(Rule, operationTarget.Instance.Syntax, operationTarget.Member.Name);
                context.ReportDiagnostic(diagnostic);
            }
        }
示例#4
0
        private void VisitMemberReference(IMemberReferenceOperation operation, IEnumerable <IOperation> additionalChildren)
        {
            Assert.NotNull(operation.Member);

            IEnumerable <IOperation> children;

            if (operation.Instance != null)
            {
                children = new[] { operation.Instance }.Concat(additionalChildren);

                // Make sure that all static member references or invocations of static methods do not have implicit IInstanceReferenceOperations
                // as their receivers
                if (operation.Member.IsStatic &&
                    operation.Instance is IInstanceReferenceOperation)
                {
                    Assert.False(operation.Instance.IsImplicit, $"Implicit {nameof(IInstanceReferenceOperation)} on {operation.Syntax}");
                }
            }
            else
            {
                children = additionalChildren;
            }

            AssertEx.Equal(children, operation.Children);
        }
示例#5
0
        private void OnCompilationStart(CompilationStartAnalysisContext compilationContext)
        {
            var restrictedInternalsVisibleToMap = GetRestrictedInternalsVisibleToMap(compilationContext.Compilation);
            if (restrictedInternalsVisibleToMap.IsEmpty)
            {
                return;
            }

            var namespaceToIsBannedMap = new ConcurrentDictionary<INamespaceSymbol, /*isBanned*/bool>();

            // Verify all explicit type name specifications in declarations and executable code.
            compilationContext.RegisterSyntaxNodeAction(
                context =>
                {
                    var name = (TNameSyntax)context.Node;
                    if (!IsInTypeOnlyContext(name) ||
                        name.Parent is TNameSyntax)
                    {
                        // Bail out if we are not in type only context or the parent is also a name
                        // which will be analyzed separately.
                        return;
                    }

                    var typeInfo = context.SemanticModel.GetTypeInfo(name, context.CancellationToken);
                    VerifySymbol(typeInfo.Type as INamedTypeSymbol, name,
                        context.ReportDiagnostic, restrictedInternalsVisibleToMap, namespaceToIsBannedMap);
                },
                NameSyntaxKinds);

            // Verify all member usages in executable code.
            compilationContext.RegisterOperationAction(
                context =>
                {
                    var symbol = context.Operation switch
                    {
                        IObjectCreationOperation objectCreation => objectCreation.Constructor,
                        IInvocationOperation invocation => invocation.TargetMethod,
                        IMemberReferenceOperation memberReference => memberReference.Member,
                        IConversionOperation conversion => conversion.OperatorMethod,
                        IUnaryOperation unary => unary.OperatorMethod,
                        IBinaryOperation binary => binary.OperatorMethod,
                        IIncrementOrDecrementOperation incrementOrDecrement => incrementOrDecrement.OperatorMethod,
                        _ => throw new NotImplementedException($"Unhandled OperationKind: {context.Operation.Kind}"),
                    };

                    VerifySymbol(symbol, context.Operation.Syntax,
                        context.ReportDiagnostic, restrictedInternalsVisibleToMap, namespaceToIsBannedMap);
                },
                OperationKind.ObjectCreation,
                OperationKind.Invocation,
                OperationKind.EventReference,
                OperationKind.FieldReference,
                OperationKind.MethodReference,
                OperationKind.PropertyReference,
                OperationKind.Conversion,
                OperationKind.UnaryOperator,
                OperationKind.BinaryOperator,
                OperationKind.Increment,
                OperationKind.Decrement);
        }
 public static string?GetName(this IOperation @this)
 {
     return(@this switch
     {
         IMemberReferenceOperation memberReference => memberReference.Member.Name,
         IInvocationOperation invocation => invocation.TargetMethod?.Name,
         _ => null
     });
 private static bool IsStaticMemberOrIsLocalFunction(IOperation operation)
 {
     return(operation switch
     {
         IMemberReferenceOperation memberReferenceOperation => IsStaticMemberOrIsLocalFunctionHelper(memberReferenceOperation.Member),
         IInvocationOperation invocationOperation => IsStaticMemberOrIsLocalFunctionHelper(invocationOperation.TargetMethod),
         _ => throw ExceptionUtilities.UnexpectedValue(operation),
     });
            private IdentifierInfo CreateForMemberReferenceExpression([NotNull] IMemberReferenceOperation operation,
                                                                      [NotNull] ITypeSymbol memberType)
            {
                var name = new IdentifierName(operation.Member.Name,
                                              operation.Member.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat));

                return(new IdentifierInfo(name, memberType, operation.Member.Kind.ToString()));
            }
示例#9
0
 internal static ISymbol?GetUnderlyingSymbol(IOperation?operation)
 {
     return(operation switch
     {
         IParameterReferenceOperation paramRef => paramRef.Parameter,
         ILocalReferenceOperation localRef => localRef.Local,
         IMemberReferenceOperation memberRef => memberRef.Member,
         _ => null,
     });
            private static bool IsHazardousIfNull(IOperation operation)
            {
                if (operation.Kind == OperationKind.ConditionalAccessInstance)
                {
                    return(false);
                }

                return(operation.Parent switch
                {
                    IMemberReferenceOperation memberReference => memberReference.Instance == operation,

                    IArrayElementReferenceOperation arrayElementReference => arrayElementReference.ArrayReference == operation,

                    IInvocationOperation invocation => invocation.Instance == operation,

                    _ => false,
                });
示例#11
0
        private void GetSymbolAndIndicesForMemberReference(IMemberReferenceOperation memberReference, ref ISymbol symbolOpt, ref ImmutableArray <AbstractIndex> indices)
        {
            switch (memberReference)
            {
            case IFieldReferenceOperation fieldReference:
                symbolOpt = fieldReference.Field;
                if (fieldReference.Field.CorrespondingTupleField != null)
                {
                    // For tuple fields, always use the CorrespondingTupleField (i.e. Item1, Item2, etc.) from the underlying value tuple type.
                    // This allows seamless operation between named tuple elements and use of Item1, Item2, etc. to access tuple elements.
                    var name = fieldReference.Field.CorrespondingTupleField.Name;
                    symbolOpt = fieldReference.Field.ContainingType.GetUnderlyingValueTupleTypeOrThis().GetMembers(name).OfType <IFieldSymbol>().FirstOrDefault()
                                ?? symbolOpt;
                }
                break;

            case IEventReferenceOperation eventReference:
                symbolOpt = eventReference.Member;
                break;

            case IPropertyReferenceOperation propertyReference:
                // We are only tracking:
                // 1) Indexers
                // 2) Read-only properties.
                // 3) Properties with a backing field (auto-generated properties)
                if (propertyReference.Arguments.Length > 0 ||
                    propertyReference.Property.IsReadOnly ||
                    propertyReference.Property.IsPropertyWithBackingField())
                {
                    symbolOpt = propertyReference.Property;
                    indices   = propertyReference.Arguments.Length > 0 ?
                                CreateAbstractIndices(propertyReference.Arguments.Select(a => a.Value).ToImmutableArray()) :
                                ImmutableArray <AbstractIndex> .Empty;
                }
                break;
            }
        }
示例#12
0
 protected virtual SyntaxNode GetSyntaxNodeToReplace(IMemberReferenceOperation memberReference)
 => memberReference.Syntax;
示例#13
0
 private void VisitMemberReference(IMemberReferenceOperation operation)
 {
     VisitMemberReference(operation, Array.Empty <IOperation>());
 }
        private void AnalyzeOperation(OperationAnalysisContext context, IOperation operation, IOperation?instanceOperation)
        {
            // this is a static reference so we don't care if it's qualified
            if (instanceOperation == null)
            {
                return;
            }

            // if we're not referencing `this.` or `Me.` (e.g., a parameter, local, etc.)
            if (instanceOperation.Kind != OperationKind.InstanceReference)
            {
                return;
            }

            // We shouldn't qualify if it is inside a property pattern
            if (context.Operation.Parent?.Kind == OperationKind.PropertySubpattern)
            {
                return;
            }

            // Initializer lists are IInvocationOperation which if passed to GetApplicableOptionFromSymbolKind
            // will incorrectly fetch the options for method call.
            // We still want to handle InstanceReferenceKind.ContainingTypeInstance
            if ((instanceOperation as IInstanceReferenceOperation)?.ReferenceKind == InstanceReferenceKind.ImplicitReceiver)
            {
                return;
            }

            // If we can't be qualified (e.g., because we're already qualified with `base.`), we're done.
            if (!CanMemberAccessBeQualified(context.ContainingSymbol, instanceOperation.Syntax))
            {
                return;
            }

            // if we can't find a member then we can't do anything.  Also, we shouldn't qualify
            // accesses to static members.
            if (IsStaticMemberOrIsLocalFunction(operation))
            {
                return;
            }

            if (instanceOperation.Syntax is not TSimpleNameSyntax simpleName)
            {
                return;
            }

            var symbolKind = operation switch
            {
                IMemberReferenceOperation memberReferenceOperation => memberReferenceOperation.Member.Kind,
                IInvocationOperation invocationOperation => invocationOperation.TargetMethod.Kind,
                _ => throw ExceptionUtilities.UnexpectedValue(operation),
            };

            var simplifierOptions = context.GetAnalyzerOptions().GetSimplifierOptions(Simplification);

            if (!simplifierOptions.TryGetQualifyMemberAccessOption(symbolKind, out var optionValue))
            {
                return;
            }

            var shouldOptionBePresent = optionValue.Value;
            var severity = optionValue.Notification.Severity;

            if (!shouldOptionBePresent || severity == ReportDiagnostic.Suppress)
            {
                return;
            }

            if (!IsAlreadyQualifiedMemberAccess(simpleName))
            {
                context.ReportDiagnostic(DiagnosticHelper.Create(
                                             Descriptor,
                                             GetLocation(operation),
                                             severity,
                                             additionalLocations: null,
                                             properties: null));
            }
        }