private void AnalyzeOperation(OperationAnalysisContext context)
        {
            IArrayCreationExpression arrayCreationExpression = context.Operation as IArrayCreationExpression;

            // We can't replace array allocations in attributes, as they're persisted to metadata
            // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check.
            if (arrayCreationExpression.Syntax.Ancestors().Any(IsAttributeSyntax))
            {
                return;
            }

            if (arrayCreationExpression.DimensionSizes.Length == 1)
            {
                var dimensionSize = arrayCreationExpression.DimensionSizes[0];

                if (dimensionSize.ConstantValue.HasValue && (int)dimensionSize.ConstantValue.Value == 0)
                {
                    // pointers can't be used as generic arguments
                    if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer)
                    {
                        context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor));
                    }
                }
            }
        }
        private static void AnalyzeOperation(OperationAnalysisContext context, ImmutableArray<INamedTypeSymbol> taskTypes)
        {
            IAwaitExpression awaitExpression = context.Operation as IAwaitExpression;

            // Get the type of the expression being awaited and check it's a task type.
            ITypeSymbol typeOfAwaitedExpression = awaitExpression?.AwaitedValue?.Type;
            if (typeOfAwaitedExpression != null && taskTypes.Contains(typeOfAwaitedExpression.OriginalDefinition))
            {
                context.ReportDiagnostic(awaitExpression.AwaitedValue.Syntax.CreateDiagnostic(Rule));
            }
        }
 private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol containingType)
 {
     var operation = context.Operation as IInvocationExpression;
     var method = operation.TargetMethod;
     if (method != null &&
         (method.IsAbstract || method.IsVirtual) &&
         method.ContainingType == containingType)
     {
         context.ReportDiagnostic(operation.Syntax.CreateDiagnostic(Rule));
     }
 }
 /// <summary>
 /// Check to see if we have an invocation to string.Equals that has an empty string as an argument.
 /// </summary>
 private static void AnalyzeInvocationExpression(OperationAnalysisContext context)
 {
     var invocationOperation = (IInvocationExpression)context.Operation;
     if (invocationOperation.ArgumentsInSourceOrder.Length > 0)
     {
         IMethodSymbol methodSymbol = invocationOperation.TargetMethod;
         if (methodSymbol != null &&
             IsStringEqualsMethod(methodSymbol) &&
             HasAnEmptyStringArgument(invocationOperation))
         {
             context.ReportDiagnostic(invocationOperation.Syntax.CreateDiagnostic(s_rule));
         }
     }
 }
        /// <summary>
        /// Check to see if we have a equals or not equals expression where an empty string is being
        /// compared.
        /// </summary>
        private static void AnalyzeBinaryExpression(OperationAnalysisContext context)
        {
            var binaryOperation = (IBinaryOperatorExpression)context.Operation;

            if (binaryOperation.BinaryOperationKind != BinaryOperationKind.StringEquals &&
                binaryOperation.BinaryOperationKind != BinaryOperationKind.StringNotEquals)
            {
                return;
            }

            if (IsEmptyString(binaryOperation.LeftOperand) || IsEmptyString(binaryOperation.RightOperand))
            {
                context.ReportDiagnostic(binaryOperation.Syntax.CreateDiagnostic(s_rule));
            }
        }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var switchOperation = (ISwitchStatement)context.Operation;
            var switchBlock = switchOperation.Syntax;
            var tree = switchBlock.SyntaxTree;

            if (SwitchIsIncomplete(switchOperation, out var missingCases, out var missingDefaultCase) &&
                !tree.OverlapsHiddenPosition(switchBlock.Span, context.CancellationToken))
            {
                Debug.Assert(missingCases || missingDefaultCase);
                var properties = ImmutableDictionary<string, string>.Empty
                    .Add(PopulateSwitchHelpers.MissingCases, missingCases.ToString())
                    .Add(PopulateSwitchHelpers.MissingDefaultCase, missingDefaultCase.ToString());

                var diagnostic = Diagnostic.Create(
                    HiddenDescriptor, switchBlock.GetLocation(), properties: properties);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;
            var cancellationToken = context.CancellationToken;
            var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferExplicitTupleNames, context.Compilation.Language);
            var severity = option.Notification.Value;
            if (severity == DiagnosticSeverity.Hidden)
            {
                return;
            }

            var fieldReferenceOperation = (IFieldReferenceExpression)context.Operation;

            var field = fieldReferenceOperation.Field;
            if (field.ContainingType.IsTupleType)
            {
                if (field.CorrespondingTupleField.Equals(field))
                {
                    var namedField = GetNamedField(field.ContainingType, field, cancellationToken);
                    if (namedField != null)
                    {
                        var memberAccessSyntax = fieldReferenceOperation.Syntax;
                        var nameNode = memberAccessSyntax.ChildNodesAndTokens().Reverse().FirstOrDefault();
                        if (nameNode != null)
                        {
                            var properties = ImmutableDictionary<string, string>.Empty.Add(
                                nameof(ElementName), namedField.Name);
                            context.ReportDiagnostic(Diagnostic.Create(
                                GetDescriptorWithSeverity(severity),
                                nameNode.GetLocation(),
                                properties));
                        }
                    }
                }
            }
        }
 private static void ReportDiagnostic(
     OperationAnalysisContext oaContext,
     IInvocationExpression invocationExpression,
     IMethodSymbol targetMethod,
     IMethodSymbol correctOverload)
 {
     oaContext.ReportDiagnostic(
         invocationExpression.Syntax.CreateDiagnostic(
             Rule,
             targetMethod.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat),
             oaContext.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat),
             correctOverload.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)));
 }
Exemple #9
0
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            if (context.ContainingSymbol.IsStatic)
            {
                return;
            }

            var memberReference = (IMemberReferenceExpression)context.Operation;

            // this is a static reference so we don't care if it's qualified
            if (memberReference.Instance == null)
            {
                return;
            }

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

            // If we can't be qualified (e.g., because we're already qualified with `base.`), we're done.
            if (!CanMemberAccessBeQualified(context.ContainingSymbol, memberReference.Instance.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 (memberReference.Member == null ||
                memberReference.Member.IsStatic)
            {
                return;
            }

            var syntaxTree        = context.Operation.Syntax.SyntaxTree;
            var cancellationToken = context.CancellationToken;
            var optionSet         = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var language         = context.Operation.Syntax.Language;
            var applicableOption = GetApplicableOptionFromSymbolKind(memberReference.Member.Kind);
            var optionValue      = optionSet.GetOption(applicableOption, language);

            var shouldOptionBePresent  = optionValue.Value;
            var isQualificationPresent = IsAlreadyQualifiedMemberAccess(memberReference.Instance.Syntax);

            if (shouldOptionBePresent && !isQualificationPresent)
            {
                var severity = optionValue.Notification.Value;
                if (severity != DiagnosticSeverity.Hidden)
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 GetDescriptorWithSeverity(severity),
                                                 context.Operation.Syntax.GetLocation()));
                }
            }
        }
Exemple #10
0
 /// <summary>Reports a diagnostic warning for an array creation that should be replaced.</summary>
 /// <param name="context">The context.</param>
 /// <param name="arrayCreationExpression">The array creation expression to be replaced.</param>
 internal void Report(OperationAnalysisContext context, SyntaxNode arrayCreationExpression)
 {
     context.ReportDiagnostic(Diagnostic.Create(UseArrayEmptyDescriptor, arrayCreationExpression.GetLocation()));
 }
 private static void Report(OperationAnalysisContext context, SyntaxNode syntax, DiagnosticDescriptor descriptor)
 {
     context.ReportDiagnostic(Diagnostic.Create(descriptor, syntax.GetLocation()));
 }
            public void Analyze(OperationAnalysisContext context, ISymbol owningSymbol)
            {
                if (context.Operation.IsInvalid)
                {
                    // not interested in invalid expression
                    return;
                }

                var invocation = (IInvocationExpression)context.Operation;
                var method = invocation.TargetMethod;

                // check basic stuff that FxCop checks. 
                if (method.IsFromMscorlib(_compilation))
                {
                    // Methods defined within mscorlib are excluded from this rule,
                    // since mscorlib cannot depend on System.Uri, which is defined 
                    // in System.dll
                    return;
                }

                if (method.GetResultantVisibility() != SymbolVisibility.Public)
                {
                    // only apply to methods that are exposed outside
                    return;
                }

                var node = _expressionGetter(context.Operation.Syntax);
                if (node == null)
                {
                    // we don't have right expression node to check overloads
                    return;
                }

                // REVIEW: why IOperation doesn't contain things like compilation and semantic model?
                //         it seems wierd that I need to do this to get thsoe.
                var model = _compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree);

                var stringParameters = method.Parameters.GetParametersOfType(_string);
                if (!stringParameters.Any())
                {
                    // no string parameter. not interested.
                    return;
                }

                // now do cheap string check whether those string parameter contains uri word list we are looking for.
                if (!stringParameters.ParameterNamesContainUriWordSubstring(context.CancellationToken))
                {
                    // no string parameter that contains what we are looking for.
                    return;
                }

                // now we make sure we actually have overloads that contains uri type parameter
                var overloads = model.GetMemberGroup(node, context.CancellationToken).OfType<IMethodSymbol>();
                if (!overloads.HasOverloadWithParameterOfType(method, _uri, context.CancellationToken))
                {
                    // no overload that contains uri as parameter
                    return;
                }

                // now we do more expensive word parsing to find exact parameter that contains url in parameter name
                var indicesSet = new HashSet<int>(method.GetParameterIndices(stringParameters.GetParametersThatContainUriWords(context.CancellationToken), context.CancellationToken));

                // now we search exact match. this is exactly same behavior as old FxCop
                foreach (IMethodSymbol overload in overloads)
                {
                    context.CancellationToken.ThrowIfCancellationRequested();

                    if (method.Equals(overload) || overload.Parameters.Length != method.Parameters.Length)
                    {
                        // either itself, or signature is not same
                        continue;
                    }

                    if (!method.ParameterTypesAreSame(overload, Enumerable.Range(0, method.Parameters.Length).Where(i => !indicesSet.Contains(i)), context.CancellationToken))
                    {
                        // check whether remaining parameters match existing types, otherwise, we are not interested
                        continue;
                    }

                    // original FxCop implementation doesnt account for case where original method call contains 
                    // 2+ string uri parameters that has overload with matching uri parameters. original implementation works
                    // when there is exactly 1 parameter having matching uri overload. this implementation follow that.
                    foreach (int index in indicesSet)
                    {
                        // check other string uri parameters matches original type
                        if (!method.ParameterTypesAreSame(overload, indicesSet.Where(i => i != index), context.CancellationToken))
                        {
                            continue;
                        }

                        // okay all other type match. check the main one
                        if (overload.Parameters[index].Type?.Equals(_uri) == true)
                        {
                            context.ReportDiagnostic(
                                node.CreateDiagnostic(
                                    Rule,
                                    owningSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    overload.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    method.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));

                            // we no longer interested in this overload. there can be only 1 match
                            break;
                        }
                    }
                }
            }
            public void Analyze(OperationAnalysisContext analysisContext)
            {
                var invocationExpression = (IInvocationExpression)analysisContext.Operation;
                if (invocationExpression.TargetMethod.OriginalDefinition.Equals(_gcSuppressFinalizeMethodSymbol))
                {
                    _suppressFinalizeCalled = true;

                    if (_semanticModel == null)
                    {
                        _semanticModel = analysisContext.Compilation.GetSemanticModel(analysisContext.Operation.Syntax.SyntaxTree);
                    }

                    // Check for GC.SuppressFinalize outside of IDisposable.Dispose()
                    if (_expectedUsage == SuppressFinalizeUsage.MustNotCall)
                    {
                        analysisContext.ReportDiagnostic(invocationExpression.Syntax.CreateDiagnostic(
                            OutsideDisposeRule,
                            _containingMethodSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                            _gcSuppressFinalizeMethodSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));
                    }

                    // Checks for GC.SuppressFinalize(this)
                    if (invocationExpression.ArgumentsInSourceOrder.Count() != 1)
                    {
                        return;
                    }

                    var parameterSymbol = _semanticModel.GetSymbolInfo(invocationExpression.ArgumentsInSourceOrder.Single().Syntax).Symbol as IParameterSymbol;
                    if (parameterSymbol == null || !parameterSymbol.IsThis)
                    {
                        analysisContext.ReportDiagnostic(invocationExpression.Syntax.CreateDiagnostic(
                            NotPassedThisRule,
                            _containingMethodSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                            _gcSuppressFinalizeMethodSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));
                    }
                }
            }
Exemple #14
0
 public static void ReportDiagnostic(this OperationAnalysisContext context, DiagnosticDescriptor descriptor, ImmutableDictionary <string, string>?properties, IOperation operation, params string[] messageArgs)
 {
     context.ReportDiagnostic(CreateDiagnostic(descriptor, operation.Syntax.GetLocation(), properties, messageArgs));
 }
Exemple #15
0
 /// <summary>Reports a diagnostic warning for an array creation that should be replaced.</summary>
 /// <param name="context">The context.</param>
 /// <param name="arrayCreationExpression">The array creation expression to be replaced.</param>
 internal void Report(OperationAnalysisContext context, SyntaxNode arrayCreationExpression)
 {
     context.ReportDiagnostic(Diagnostic.Create(UseArrayEmptyDescriptor, arrayCreationExpression.GetLocation()));
 }
    private static void AnalyzeConstructorBody(OperationAnalysisContext context)
    {
        IConstructorBodyOperation operation = ((IConstructorBodyOperation)context.Operation);
        Compilation compilation             = context.Compilation;

        TypeSet exceptions = GetIgnoredExceptionSet(compilation);

        IMethodSymbol symbol = operation.GetSymbol();

        if (symbol.IsStatic)
        {
            foreach (CrefSyntax cref in operation.GetDeclarationSyntax().GetDocumentedExceptions())
            {
                Diagnostic diagnostic = Diagnostic.Create(
                    descriptor: Descriptors.StaticConstructorsShouldNotThrowExceptions,
                    location: cref.Ancestors().OfType <XmlNodeSyntax>().FirstOrDefault()?.GetLocation()
                    );

                context.ReportDiagnostic(diagnostic);
            }

            context.ReportUndocumentedExceptions(
                descriptorForThrow: Descriptors.StaticConstructorsShouldNotThrowExceptions,
                descriptorForInvocation: Descriptors.StaticConstructorsShouldCatchCalleeExceptions,
                documented: exceptions,
                exceptions: operation.GetExceptionalOperations(compilation)
                );
        }
        else
        {
            exceptions = exceptions.Add(operation.GetDocumentedExceptions());

            context.ReportUndocumentedExceptions(
                descriptorForThrow: Descriptors.DocumentThrownExceptions,
                descriptorForInvocation: Descriptors.DocumentCalleeExceptions,
                documented: exceptions,
                exceptions: operation.GetExceptionalOperations(compilation)
                );

            if (operation.Initializer is null)
            {
                //
                // HACK: Implicit/compiler-generated calls to parameterless base-class constructors are
                //       not included in the operation hierarchy and need to be handled explicitly.
                //
                if (
                    (symbol is IMethodSymbol constructor) && !constructor.IsStatic &&
                    (constructor.ContainingType is INamedTypeSymbol type) && (type.TypeKind == TypeKind.Class) &&
                    (type.BaseType is INamedTypeSymbol baseType) &&
                    (baseType.GetParameterlessInstanceConstructor() is IMethodSymbol baseParameterlessConstructor)
                    )
                {
                    Location location = operation.GetDeclarationSyntax().GetIdentifierLocations().First();

                    //
                    // TODO: better diagnostic message which refers to the implicit parameterless constructor call
                    //
                    context.ReportUndocumentedExceptions(
                        descriptorForThrow: Descriptors.DocumentThrownExceptions,
                        descriptorForInvocation: Descriptors.DocumentCalleeExceptions,
                        documented: exceptions,
                        exceptions: baseParameterlessConstructor
                        .GetDocumentedExceptions(compilation)
                        .Select(exception => new ExceptionalOperation(location, baseParameterlessConstructor, exception))
                        );
                }
            }
        }
    }
    private void AnalyzeSymbolInitializer(OperationAnalysisContext context)
    {
        ISymbolInitializerOperation operation = ((ISymbolInitializerOperation)context.Operation);
        Compilation compilation = context.Compilation;

        ISymbol initializedMember = operation.GetInitializedMembers().First();
        IEnumerable <ExceptionalOperation> initializerExceptions = operation.GetExceptionalOperations(compilation);

        if (initializedMember.IsStatic)
        {
            foreach (ExceptionalOperation initializerException in initializerExceptions)
            {
                context.ReportDiagnostic(Diagnostic.Create(
                                             Descriptors.StaticInitializersShouldNotThrowExceptions,
                                             initializerException.Location
                                             ));
            }
        }
        else
        {
            IEnumerable <IMethodSymbol> initializationConstructors = operation.GetInitializationConstructors();

            TypeSet documentedExceptionsInAllInitializationConstructors = TypeSet.Universal;

            foreach (IMethodSymbol constructor in initializationConstructors)
            {
                TypeSet documentedExceptions = constructor.GetDocumentedExceptionSet(compilation);

                documentedExceptionsInAllInitializationConstructors &= documentedExceptions;

                foreach (ExceptionalOperation exception in initializerExceptions)
                {
                    ITypeSymbol exceptionType = exception.Type;

                    if (!documentedExceptions.Contains(exceptionType))
                    {
                        foreach (Location location in constructor.Locations)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(
                                                         Descriptors.DocumentInstanceMemberInitializerExceptions,
                                                         location,
                                                         exceptionType.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat),
                                                         initializedMember.Name
                                                         ));
                        }
                    }
                }
            }

            // For each exception that isn't documented in all the right places, add an additional diagnostic at the throw/invocation site
            foreach (ExceptionalOperation exception in initializerExceptions)
            {
                Boolean documentedInAllInitializationConstructors =
                    documentedExceptionsInAllInitializationConstructors.Contains(exception.Type);

                if (!documentedInAllInitializationConstructors)
                {
                    context.ReportUndocumentedException(
                        descriptorForThrow: Descriptors.DocumentInstanceMemberInitializerThrownExceptions,
                        descriptorForInvocation: Descriptors.DocumentInstanceMemberInitializerCalleeExceptions,
                        exception: exception
                        );
                }
            }
        }
    }
Exemple #18
0
        static void CheckSegments(OperationAnalysisContext ctx, IList <IFormatStringSegment> segments, int formatStart, IList <IArgumentOperation> formatArguments)
        {
            if (segments.Count == 0)
            {
                return;
            }

            SyntaxTree syntaxTree = ctx.Operation.Syntax.SyntaxTree;

            var outOfBoundsFormat = GettextCatalog.GetString("The index '{0}' is out of bounds of the passed arguments");
            var multipleFormat    = GettextCatalog.GetString("Multiple:\n{0}");

            int argumentCount = formatArguments.Count;

            foreach (var segment in segments)
            {
                var errors = segment.Errors.ToList();
                if (segment is FormatItem formatItem)
                {
                    var location = Location.Create(syntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(formatStart + segment.StartLocation, segment.EndLocation - segment.StartLocation));

                    if (formatItem.Index >= argumentCount)
                    {
                        ctx.ReportDiagnostic(Diagnostic.Create(
                                                 descriptor,
                                                 location,
                                                 string.Format(outOfBoundsFormat, formatItem.Index)
                                                 ));
                    }

                    if (formatItem.HasErrors)
                    {
                        var    errorMessage = string.Join(Environment.NewLine, errors.Select(error => error.Message).ToArray());
                        string messageFormat;
                        if (errors.Count > 1)
                        {
                            messageFormat = multipleFormat;
                        }
                        else
                        {
                            messageFormat = "{0}";
                        }
                        ctx.ReportDiagnostic(Diagnostic.Create(
                                                 descriptor,
                                                 location,
                                                 string.Format(messageFormat, errorMessage)
                                                 ));
                    }
                }
                else if (segment.HasErrors)
                {
                    foreach (var error in errors)
                    {
                        ctx.ReportDiagnostic(Diagnostic.Create(
                                                 descriptor,
                                                 Location.Create(syntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(formatStart + error.StartLocation, error.EndLocation - error.StartLocation)),
                                                 error.Message
                                                 ));
                    }
                }
            }
        }
Exemple #19
0
            public void Analyze(OperationAnalysisContext context)
            {
                var invocation = (IInvocationOperation)context.Operation;
                var method     = invocation.TargetMethod;

                // check basic stuff that FxCop checks.
                if (method.IsFromMscorlib(_compilation))
                {
                    // Methods defined within mscorlib are excluded from this rule,
                    // since mscorlib cannot depend on System.Uri, which is defined
                    // in System.dll
                    return;
                }

                if (!context.Options.MatchesConfiguredVisibility(Rule, method, context.ContainingSymbol, context.Compilation))
                {
                    // only apply to methods that are exposed outside by default
                    return;
                }

                var node = _expressionGetter(context.Operation.Syntax);

                if (node == null)
                {
                    // we don't have right expression node to check overloads
                    return;
                }

                var stringParameters = method.Parameters.GetParametersOfType(_string);

                if (!stringParameters.Any())
                {
                    // no string parameter. not interested.
                    return;
                }

                // now do cheap string check whether those string parameter contains uri word list we are looking for.
                if (!stringParameters.ParameterNamesContainUriWordSubstring(context.CancellationToken))
                {
                    // no string parameter that contains what we are looking for.
                    return;
                }

                // now we make sure we actually have overloads that contains uri type parameter
                var overloads = context.Operation.SemanticModel.GetMemberGroup(node, context.CancellationToken).OfType <IMethodSymbol>();

                if (!overloads.HasOverloadWithParameterOfType(method, _uri, context.CancellationToken))
                {
                    // no overload that contains uri as parameter
                    return;
                }

                // now we do more expensive word parsing to find exact parameter that contains url in parameter name
                var indicesSet = new HashSet <int>(method.GetParameterIndices(stringParameters.GetParametersThatContainUriWords(context.CancellationToken), context.CancellationToken));

                // now we search exact match. this is exactly same behavior as old FxCop
                foreach (IMethodSymbol overload in overloads)
                {
                    context.CancellationToken.ThrowIfCancellationRequested();

                    if (method.Equals(overload) || overload.Parameters.Length != method.Parameters.Length)
                    {
                        // either itself, or signature is not same
                        continue;
                    }

                    if (!method.ParameterTypesAreSame(overload, Enumerable.Range(0, method.Parameters.Length).Where(i => !indicesSet.Contains(i)), context.CancellationToken))
                    {
                        // check whether remaining parameters match existing types, otherwise, we are not interested
                        continue;
                    }

                    // original FxCop implementation doesn't account for case where original method call contains
                    // 2+ string uri parameters that has overload with matching uri parameters. original implementation works
                    // when there is exactly 1 parameter having matching uri overload. this implementation follow that.
                    foreach (int index in indicesSet)
                    {
                        // check other string uri parameters matches original type
                        if (!method.ParameterTypesAreSame(overload, indicesSet.Where(i => i != index), context.CancellationToken))
                        {
                            continue;
                        }

                        // okay all other type match. check the main one
                        if (overload.Parameters[index].Type?.Equals(_uri) == true &&
                            !Equals(overload, context.ContainingSymbol))
                        {
                            context.ReportDiagnostic(
                                node.CreateDiagnostic(
                                    Rule,
                                    context.ContainingSymbol.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    overload.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat),
                                    method.ToDisplayString(SymbolDisplayFormats.ShortSymbolDisplayFormat)));

                            // we no longer interested in this overload. there can be only 1 match
                            break;
                        }
                    }
                }
            }
        private static void AnalyzeRaiseEvent(OperationAnalysisContext context)
        {
            var operation    = (IInvocationOperation)context.Operation;
            var targetMethod = operation.TargetMethod;

            if (targetMethod.Name != nameof(EventHandler.Invoke))
            {
                return;
            }

            if (targetMethod.Parameters.Length != 2)
            {
                return;
            }

            if (!targetMethod.Parameters[0].Type.IsObject())
            {
                return;
            }

            var eventArgsSymbol = context.Compilation.GetTypeByMetadataName("System.EventArgs");

            if (!targetMethod.Parameters[1].Type.IsOrInheritFrom(eventArgsSymbol))
            {
                return;
            }

            var multicastDelegateSymbol = context.Compilation.GetTypeByMetadataName("System.MulticastDelegate");

            if (!targetMethod.ContainingType.IsOrInheritFrom(multicastDelegateSymbol))
            {
                return;
            }

            var instance = operation.Instance;

            if (instance == null)
            {
                return;
            }

            var ev = FindEvent(instance);

            if (ev == null)
            {
                return;
            }

            // Argument validation
            var senderArgument = operation.Arguments[0];

            if (ev.IsStatic)
            {
                if (!IsNull(senderArgument))
                {
                    context.ReportDiagnostic(s_senderStaticRule, senderArgument);
                }
            }
            else
            {
                if (!IsThis(senderArgument))
                {
                    context.ReportDiagnostic(s_senderInstanceRule, senderArgument);
                }
            }

            var eventArgsArgument = operation.Arguments[1];

            if (IsNull(eventArgsArgument))
            {
                context.ReportDiagnostic(s_eventArgsRule, eventArgsArgument);
            }
        }
 private static void ReportDiagnostic(OperationAnalysisContext context, LocalizableString format, params object[] args)
 {
     context.ReportDiagnostic(
         context.Operation.Syntax.CreateDiagnostic(
             Descriptor,
             string.Format(format.ToString(), args)));
 }
            private void AnalyzeObjectCreationForXmlDocument(OperationAnalysisContext context, ISymbol variable, IObjectCreationOperation objCreation)
            {
                if (variable == null || !_xmlDocumentEnvironments.TryGetValue(variable, out var xmlDocumentEnvironment))
                {
                    xmlDocumentEnvironment = new XmlDocumentEnvironment
                    {
                        IsSecureResolver = false,
                        IsXmlResolverSet = false
                    };
                }

                xmlDocumentEnvironment.XmlDocumentDefinition = objCreation.Syntax;
                SyntaxNode node = objCreation.Syntax;
                bool       isXmlDocumentSecureResolver = false;

                if (!Equals(objCreation.Constructor.ContainingType, _xmlTypes.XmlDocument))
                {
                    isXmlDocumentSecureResolver = true;
                }

                // propertyInitlizer is not returned any more
                // and no way to get propertysymbol
                if (objCreation.Initializer != null)
                {
                    foreach (IOperation init in objCreation.Initializer.Initializers)
                    {
                        if (init is IAssignmentOperation assign)
                        {
                            var propValue = assign.Value;
                            if (!(assign.Target is IPropertyReferenceOperation propertyReference))
                            {
                                continue;
                            }

                            var prop = propertyReference.Property;
                            if (prop.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, "XmlResolver"))
                            {
                                if (!(propValue is IConversionOperation operation))
                                {
                                    return;
                                }

                                if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes))
                                {
                                    isXmlDocumentSecureResolver = true;
                                }
                                else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand))
                                {
                                    isXmlDocumentSecureResolver = true;
                                }
                                else // Non secure resolvers
                                {
                                    context.ReportDiagnostic(assign.Syntax.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver));
                                    return;
                                }
                            }
                            else
                            {
                                AnalyzeNeverSetProperties(context, prop, assign.Syntax.GetLocation());
                            }
                        }
                    }
                }

                xmlDocumentEnvironment.IsSecureResolver = isXmlDocumentSecureResolver;

                if (variable != null)
                {
                    _xmlDocumentEnvironments[variable] = xmlDocumentEnvironment;
                }
                else if (!xmlDocumentEnvironment.IsSecureResolver) // Insecure temp object
                {
                    context.ReportDiagnostic(node.CreateDiagnostic(RuleXmlDocumentWithNoSecureResolver));
                }

                return;
            }
Exemple #23
0
            public void AnalyzeInvocation(OperationAnalysisContext ctx)
            {
                var operation = (IInvocationOperation)ctx.Operation;

                if (HasEqualityComparerArgument(operation.Arguments))
                {
                    return;
                }

                var method = operation.TargetMethod;

                if (method.HasOverloadWithAdditionalParameterOfType(ctx.Compilation, EqualityComparerStringType) ||
                    method.HasOverloadWithAdditionalParameterOfType(ctx.Compilation, ComparerStringType))
                {
                    ctx.ReportDiagnostic(s_rule, operation);
                    return;
                }

                if (EnumerableType != null)
                {
                    if (!method.ContainingType.IsEqualTo(EnumerableType))
                    {
                        return;
                    }

                    if (method.Arity == 0)
                    {
                        return;
                    }

                    if (method.Arity == 1)
                    {
                        if (!s_enumerableMethods.Contains(method.Name, StringComparer.Ordinal))
                        {
                            return;
                        }

                        if (!method.TypeArguments[0].IsString())
                        {
                            return;
                        }
                    }
                    else
                    {
                        if (!s_arityIndex.TryGetValue(method.Name, out var arityIndex))
                        {
                            return;
                        }

                        if (arityIndex >= method.Arity)
                        {
                            return;
                        }

                        if (!method.TypeArguments[arityIndex].IsString())
                        {
                            return;
                        }
                    }

                    if (!HasEqualityComparerArgument(operation.Arguments))
                    {
                        ctx.ReportDiagnostic(s_rule, operation);
                    }
                }
            }
            private void AnalyzeMethodOverloads(OperationAnalysisContext context, IMethodSymbol method, IHasArgumentsExpression expression)
            {
                if (method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.Load) ||                                    //FxCop CA3056
                    method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.LoadXml) ||                                 //FxCop CA3057
                    method.MatchMethodDerivedByName(_xmlTypes.XPathDocument, WellKnownMemberNames.InstanceConstructorName) ||         //FxCop CA3059
                    method.MatchMethodDerivedByName(_xmlTypes.XmlSchema, SecurityMemberNames.Read) ||                                      //FxCop CA3060
                    method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXml) ||                                     //FxCop CA3063
                    method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXmlSchema) ||                               //FxCop CA3064
                    method.MatchMethodDerivedByName(_xmlTypes.XmlSerializer, SecurityMemberNames.Deserialize) ||                           //FxCop CA3070
                    method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXml) ||                                   //FxCop CA3071
                    method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXmlSchema))                               //FxCop CA3072
                {
                    if (SecurityDiagnosticHelpers.HasXmlReaderParameter(method, _xmlTypes) < 0)
                    {
                        DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                rule,
                                expression.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.DoNotUseDtdProcessingOverloadsMessage),
                                    method.Name
                                )
                            )
                        );
                    }
                }
                else if (method.MatchMethodDerivedByName(_xmlTypes.XmlReader, SecurityMemberNames.Create))
                {
                    int xmlReaderSettingsIndex = SecurityDiagnosticHelpers.GetXmlReaderSettingsParameterIndex(method, _xmlTypes);

                    if (xmlReaderSettingsIndex < 0)
                    {
                        DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
                        Diagnostic diag = Diagnostic.Create(
                                RuleDoNotUseInsecureDtdProcessing,
                                expression.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.XmlReaderCreateWrongOverloadMessage)
                                )
                            );
                        context.ReportDiagnostic(diag);
                    }
                    else
                    {
                        SemanticModel model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree);
                        IArgument arg = expression.ArgumentsInParameterOrder[xmlReaderSettingsIndex];
                        ISymbol settingsSymbol = arg.Value.Syntax.GetDeclaredOrReferencedSymbol(model);
                        
                        if(settingsSymbol == null)
                        {
                            return;
                        }

                        XmlReaderSettingsEnvironment env;

                        if (!_xmlReaderSettingsEnvironments.TryGetValue(settingsSymbol, out env))
                        {
                            // symbol for settings is not found => passed in without any change => assume insecure
                            Diagnostic diag = Diagnostic.Create(
                                RuleDoNotUseInsecureDtdProcessing,
                                expression.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureInputMessage)
                                )
                            );
                            context.ReportDiagnostic(diag);
                        }
                        else if (!env.IsDtdProcessingDisabled && !(env.IsSecureResolver && env.IsMaxCharactersFromEntitiesLimited))
                        {
                            Diagnostic diag;
                            if (env.IsConstructedInCodeBlock)
                            {
                                diag = Diagnostic.Create(
                                    RuleDoNotUseInsecureDtdProcessing,
                                    expression.Syntax.GetLocation(),
                                    SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                        nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureConstructedMessage)
                                    )
                                );
                            }
                            else
                            {
                                diag = Diagnostic.Create(
                                    RuleDoNotUseInsecureDtdProcessing,
                                    expression.Syntax.GetLocation(),
                                    SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                        nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureInputMessage)
                                    )
                                );
                            }
                            context.ReportDiagnostic(diag);
                        }
                    }
                }
            }
        private void AnalyzeOperation(OperationAnalysisContext context, Func<SyntaxNode, bool> isAttributeSytnax)
        {
            IArrayCreationExpression arrayCreationExpression = (IArrayCreationExpression)context.Operation;

            // We can't replace array allocations in attributes, as they're persisted to metadata
            // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check.
            if (arrayCreationExpression.Syntax.Ancestors().Any(isAttributeSytnax))
            {
                return;
            }

            if (arrayCreationExpression.DimensionSizes.Length == 1)
            {
                IOperation dimensionSize = arrayCreationExpression.DimensionSizes[0];

                if (dimensionSize.HasConstantValue(0))
                {
                    // Workaround for https://github.com/dotnet/roslyn/issues/10214
                    // Bail out for compiler generated param array creation.
                    if (IsCompilerGeneratedParamsArray(arrayCreationExpression, context))
                    {
                        return;
                    }

                    // pointers can't be used as generic arguments
                    if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer)
                    {
                        var arrayType = context.Compilation.GetTypeByMetadataName(ArrayTypeName);
                        IMethodSymbol emptyMethod = (IMethodSymbol)arrayType.GetMembers(ArrayEmptyMethodName).First();
                        var constructed = emptyMethod.Construct(arrayCreationExpression.ElementType);

                        string typeName = constructed.ToDisplayString(ReportFormat);
                        context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor, typeName));
                    }
                }
            }
        }
            private void AnalyzeObjectCreationForXmlTextReader(OperationAnalysisContext context, ISymbol variable, IObjectCreationExpression objCreation)
            {
                XmlTextReaderEnvironment env;

                if (variable == null || !_xmlTextReaderEnvironments.TryGetValue(variable, out env))
                {
                    env = new XmlTextReaderEnvironment(_isFrameworkSecure)
                    {
                        XmlTextReaderDefinition = objCreation.Syntax
                    };
                }

                if (objCreation.Constructor.ContainingType != _xmlTypes.XmlTextReader)
                {
                    env.IsDtdProcessingDisabled = true;
                    env.IsSecureResolver = true;
                }

                foreach (ISymbolInitializer init in objCreation.MemberInitializers)
                {
                    var prop = init as IPropertyInitializer;

                    if (prop != null)
                    {
                        IConversionExpression operation = prop.Value as IConversionExpression;

                        if (operation != null && SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverPropertyDerived(prop.InitializedProperty, _xmlTypes))
                        {
                            env.IsXmlResolverSet = true;

                            if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes))
                            {
                                env.IsSecureResolver = true;
                            }
                            else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand))
                            {
                                env.IsSecureResolver = true;
                            }
                            else
                            {
                                env.IsSecureResolver = false;
                            }
                        }
                        else if (SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingPropertyDerived(prop.InitializedProperty, _xmlTypes))
                        {
                            env.IsDtdProcessingSet = true;
                            env.IsDtdProcessingDisabled = !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(prop.Value);
                        }
                    }
                }

                // if the XmlResolver or Dtdprocessing property is explicitly set when created, and is to an insecure value, generate a warning
                if ((env.IsXmlResolverSet && !env.IsSecureResolver) ||
                    (env.IsDtdProcessingSet && !env.IsDtdProcessingDisabled))
                {
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        env.XmlTextReaderDefinition.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlTextReaderSetInsecureResolutionMessage)
                        )
                    );
                    context.ReportDiagnostic(diag);
                }
                // if the XmlResolver or Dtdprocessing property is not explicitly set when constructed for a non-temp XmlTextReader object, add env to the dictionary.
                else if (variable != null && !(env.IsDtdProcessingSet && env.IsXmlResolverSet))
                {
                    _xmlTextReaderEnvironments[variable] = env;
                }
                // if the is not set or set to Parse for a temporary object, report right now.
                else if (variable == null && !(env.IsDtdProcessingSet && env.IsXmlResolverSet && env.IsDtdProcessingDisabled && env.IsSecureResolver))
                {
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        env.XmlTextReaderDefinition.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlTextReaderConstructedWithNoSecureResolutionMessage)
                        )
                    );
                    context.ReportDiagnostic(diag);
                }
            }
            private void AnalyzeXmlTextReaderProperties(OperationAnalysisContext context, ISymbol assignedSymbol, IAssignmentExpression expression, bool isXmlTextReaderXmlResolverProperty, bool isXmlTextReaderDtdProcessingProperty)
            {
                XmlTextReaderEnvironment env;

                if (!_xmlTextReaderEnvironments.TryGetValue(assignedSymbol, out env))
                {
                    env = new XmlTextReaderEnvironment(_isFrameworkSecure);
                }

                if (isXmlTextReaderXmlResolverProperty)
                {
                    env.IsXmlResolverSet = true;
                }
                else
                {
                    env.IsDtdProcessingSet = true;
                }

                IConversionExpression conv = expression.Value as IConversionExpression;
                
                if (isXmlTextReaderXmlResolverProperty && conv != null && SecurityDiagnosticHelpers.IsXmlSecureResolverType(conv.Operand.Type, _xmlTypes))
                {
                    env.IsSecureResolver = true;
                }
                else if (isXmlTextReaderXmlResolverProperty && conv != null && SecurityDiagnosticHelpers.IsExpressionEqualsNull(conv.Operand))
                {
                    env.IsSecureResolver = true;
                }
                else if (isXmlTextReaderDtdProcessingProperty && conv == null && !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(expression.Value))
                {
                    env.IsDtdProcessingDisabled = !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(expression.Value);
                }
                else
                {
                    // Generate a warning whenever the XmlResolver or DtdProcessing property is set to an insecure value
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        expression.Syntax.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlTextReaderSetInsecureResolutionMessage)
                        )
                    );
                    context.ReportDiagnostic(diag);
                }
            }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            IArrayCreationExpression arrayCreationExpression = context.Operation as IArrayCreationExpression;

            // We can't replace array allocations in attributes, as they're persisted to metadata
            // TODO: Once we have operation walkers, we can replace this syntactic check with an operation-based check.
            if (arrayCreationExpression.Syntax.Ancestors().Any(IsAttributeSyntax))
            {
                return;
            }

            if (arrayCreationExpression.DimensionSizes.Length == 1)
            {
                IOperation dimensionSize = arrayCreationExpression.DimensionSizes[0];

                if (dimensionSize.HasConstantValue(0))
                {
                    // Workaround for https://github.com/dotnet/roslyn/issues/10214
                    // Bail out for compiler generated param array creation.
                    if (IsCompilerGeneratedParamsArray(arrayCreationExpression, context))
                    {
                        return;
                    }

                    // pointers can't be used as generic arguments
                    if (arrayCreationExpression.ElementType.TypeKind != TypeKind.Pointer)
                    {
                        context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(UseArrayEmptyDescriptor));
                    }
                }
            }
        }
            public void AnalyzeInvocationOperation(OperationAnalysisContext context)
            {
                var operation = (IInvocationOperation)context.Operation;

                if (operation.TargetMethod.Name == nameof(ValueType.GetHashCode))
                {
                    var actualType = operation.Children.FirstOrDefault()?.GetActualType();
                    if (actualType == null)
                    {
                        return;
                    }

                    if (IsStruct(actualType) && HasDefaultEqualsOrHashCodeImplementations(actualType))
                    {
                        context.ReportDiagnostic(s_rule, operation);
                    }
                }
                else if (operation.TargetMethod.Name == nameof(ValueType.Equals))
                {
                    var actualType = operation.Children.FirstOrDefault()?.GetActualType();
                    if (actualType == null)
                    {
                        return;
                    }

                    if (IsStruct(actualType) && HasDefaultEqualsOrHashCodeImplementations(actualType))
                    {
                        context.ReportDiagnostic(s_rule, operation);
                    }
                }
                else if (IsImmutableCreateMethod(operation.TargetMethod))
                {
                    var type = operation.TargetMethod.TypeArguments[0];
                    if (IsStruct(type) && HasDefaultEqualsOrHashCodeImplementations(type))
                    {
                        if (operation.TargetMethod.ContainingType.IsEqualTo(ImmutableSortedDictionarySymbol))
                        {
                            if (operation.TargetMethod.Parameters.Any(arg => arg.Type.IsEqualTo(IComparerSymbol?.Construct(type))))
                            {
                                return;
                            }
                        }
                        else
                        {
                            if (operation.TargetMethod.Parameters.Any(arg => arg.Type.IsEqualTo(IEqualityComparerSymbol?.Construct(type))))
                            {
                                return;
                            }
                        }

                        context.ReportDiagnostic(s_rule2, operation);
                    }
                }

                bool IsImmutableCreateMethod(IMethodSymbol methodSymbol)
                {
                    var names = new[]
                    {
                        "Create",
                        "CreateBuilder",
                        "CreateRange",
                    };

                    var builderTypes = new[]
                    {
                        ImmutableDictionarySymbol,
                        ImmutableHashSetSymbol,
                        ImmutableSortedDictionarySymbol,
                    };

                    return(methodSymbol.Arity >= 1 && names.Contains(methodSymbol.Name, StringComparer.Ordinal) && builderTypes.Any(type => type.IsEqualTo(methodSymbol.ContainingType.OriginalDefinition)));
                }
            }
            public void Analyze(OperationAnalysisContext context, ISymbol owningSymbol)
            {
                if (context.Operation.IsInvalid)
                {
                    // not interested in invalid expression
                    return;
                }

                var invocation = (IInvocationExpression)context.Operation;
                IMethodSymbol method = invocation.TargetMethod;

                SyntaxNode node = _expressionGetter(context.Operation.Syntax);
                if (node == null)
                {
                    // we don't have right expression node to check overloads
                    return;
                }

                // REVIEW: why IOperation doesn't contain things like compilation and semantic model?
                //         it seems wierd that I need to do this to get thsoe.
                SemanticModel model = _compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree);

                // due to limitation of using "this" in lambda in struct
                INamedTypeSymbol stringType = _string;
                IEnumerable<IParameterSymbol> stringParameters = method.Parameters.Where(p => p.Type?.Equals(stringType) == true);
                if (!stringParameters.Any())
                {
                    // no string parameter. not interested.
                    return;
                }

                // now do cheap string check whether those string parameter contains uri word list we are looking for.
                if (!CheckStringParametersContainUriWords(stringParameters, context.CancellationToken))
                {
                    // no string parameter that contains what we are looking for.
                    return;
                }

                // now we make sure we actually have overloads that contains uri type parameter
                if (!CheckOverloadsContainUriParameters(model, method, node, context.CancellationToken))
                {
                    // no overload that contains uri as parameter
                    return;
                }

                // now we do more expensive word parsing to find exact parameter that contains url in parameter name
                var indicesSet = new HashSet<int>(GetParameterIndices(method, GetStringParametersThatContainsUriWords(stringParameters, context.CancellationToken), context.CancellationToken));

                // now we search exact match. this is exactly same behavior as old FxCop
                foreach (IMethodSymbol overload in model.GetMemberGroup(node, context.CancellationToken).OfType<IMethodSymbol>())
                {
                    context.CancellationToken.ThrowIfCancellationRequested();

                    if (method.Equals(overload) || overload.Parameters.Length != method.Parameters.Length)
                    {
                        // either itself, or signature is not same
                        continue;
                    }

                    if (!CheckParameterTypes(method, overload, Enumerable.Range(0, method.Parameters.Length).Where(i => !indicesSet.Contains(i)), context.CancellationToken))
                    {
                        // check whether remaining parameters match existing types, otherwise, we are not interested
                        continue;
                    }

                    // original FxCop implementation doesnt account for case where original method call contains 
                    // 2+ string uri parameters that has overload with matching uri parameters. original implementation works
                    // when there is exactly 1 parameter having matching uri overload. this implementation follow that.
                    foreach (int index in indicesSet)
                    {
                        // check other string uri parameters matches original type
                        if (!CheckParameterTypes(method, overload, indicesSet.Where(i => i != index), context.CancellationToken))
                        {
                            continue;
                        }

                        // okay all other type match. check the main one
                        if (overload.Parameters[index].Type?.Equals(_uri) == true)
                        {
                            context.ReportDiagnostic(node.CreateDiagnostic(Rule, owningSymbol.ToDisplayString(s_symbolDisplayFormat), overload.ToDisplayString(s_symbolDisplayFormat), method.ToDisplayString(s_symbolDisplayFormat)));

                            // we no longer interested in this overload. there can be only 1 match
                            break;
                        }
                    }
                }
            }
            private void AnalyzeObjectCreationForXmlDocument(OperationAnalysisContext context, ISymbol variable, IObjectCreationExpression objCreation)
            {
                XmlDocumentEnvironment xmlDocumentEnvironment;

                if (variable == null || !_xmlDocumentEnvironments.ContainsKey(variable))
                {
                    xmlDocumentEnvironment = new XmlDocumentEnvironment
                    {
                        IsSecureResolver = false,
                        IsXmlResolverSet = false
                    };
                }
                else
                {
                    xmlDocumentEnvironment = _xmlDocumentEnvironments[variable];
                }

                xmlDocumentEnvironment.XmlDocumentDefinition = objCreation.Syntax;
                SyntaxNode node = objCreation.Syntax;
                bool isXmlDocumentSecureResolver = false;

                if (objCreation.Constructor.ContainingType != _xmlTypes.XmlDocument)
                {
                    isXmlDocumentSecureResolver = true;
                }

                foreach (ISymbolInitializer init in objCreation.MemberInitializers)
                {
                    var prop = init as IPropertyInitializer;

                    if (prop != null)
                    {
                        if (prop.InitializedProperty.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, "XmlResolver"))
                        {
                            IConversionExpression operation = prop.Value as IConversionExpression;

                            if (operation == null)
                            {
                                return;
                            }

                            if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes))
                            {
                                isXmlDocumentSecureResolver = true;
                            }
                            else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand))
                            {
                                isXmlDocumentSecureResolver = true;
                            }
                            else // Non secure resolvers
                            {
                                IObjectCreationExpression xmlResolverObjCreated = operation.Operand as IObjectCreationExpression;

                                if (xmlResolverObjCreated != null)
                                {
                                    Diagnostic diag = Diagnostic.Create(
                                        RuleDoNotUseInsecureDtdProcessing,
                                        prop.Syntax.GetLocation(),
                                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                            nameof(DesktopAnalyzersResources.XmlDocumentWithNoSecureResolverMessage)
                                        )
                                    );
                                    context.ReportDiagnostic(diag);
                                }

                                return;
                            }
                        }
                        else
                        {
                            AnalyzeNeverSetProperties(context, prop.InitializedProperty, prop.Syntax.GetLocation());
                        }
                    }
                }


                xmlDocumentEnvironment.IsSecureResolver = isXmlDocumentSecureResolver;

                if (variable != null)
                {
                    _xmlDocumentEnvironments[variable] = xmlDocumentEnvironment;
                }
                else if (!xmlDocumentEnvironment.IsSecureResolver) // Insecure temp object
                {
                    Diagnostic diag = Diagnostic.Create(
                                        RuleDoNotUseInsecureDtdProcessing,
                                        node.GetLocation(),
                                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                            nameof(DesktopAnalyzersResources.XmlDocumentWithNoSecureResolverMessage)
                                        )
                                    );
                    context.ReportDiagnostic(diag);
                }
            }
Exemple #32
0
        private static void OptimizeCountUsage(OperationAnalysisContext context, IInvocationOperation operation, IReadOnlyCollection <INamedTypeSymbol> enumerableSymbols)
        {
            if (!string.Equals(operation.TargetMethod.Name, nameof(Enumerable.Count), StringComparison.Ordinal))
            {
                return;
            }

            var binaryOperation = GetParentBinaryOperation(operation, out var countOperand);

            if (binaryOperation == null)
            {
                return;
            }

            if (!IsSupportedOperator(binaryOperation.OperatorKind))
            {
                return;
            }

            if (!binaryOperation.LeftOperand.Type.IsInt32() || !binaryOperation.RightOperand.Type.IsInt32())
            {
                return;
            }

            var opKind       = NormalizeOperator();
            var otherOperand = binaryOperation.LeftOperand == countOperand ? binaryOperation.RightOperand : binaryOperation.LeftOperand;

            if (otherOperand == null)
            {
                return;
            }

            string message    = null;
            var    properties = ImmutableDictionary <string, string> .Empty;

            if (otherOperand.ConstantValue.HasValue && otherOperand.ConstantValue.Value is int value)
            {
                switch (opKind)
                {
                case BinaryOperatorKind.Equals:
                    if (value < 0)
                    {
                        // expr.Count() == -1
                        message    = "Expression is always false";
                        properties = CreateProperties(OptimizeLinqUsageData.UseFalse);
                    }
                    else if (value == 0)
                    {
                        // expr.Count() == 0
                        message    = "Replace 'Count() == 0' with 'Any() == false'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseNotAny);
                    }
                    else
                    {
                        // expr.Count() == 1
                        if (!HasTake())
                        {
                            message    = Invariant($"Replace 'Count() == {value}' with 'Take({value + 1}).Count() == {value}'");
                            properties = CreateProperties(OptimizeLinqUsageData.UseTakeAndCount);
                        }
                    }

                    break;

                case BinaryOperatorKind.NotEquals:
                    if (value < 0)
                    {
                        // expr.Count() != -1 is always true
                        message    = "Expression is always true";
                        properties = CreateProperties(OptimizeLinqUsageData.UseTrue);
                    }
                    else if (value == 0)
                    {
                        // expr.Count() != 0
                        message    = "Replace 'Count() != 0' with 'Any()'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseAny);
                    }
                    else
                    {
                        // expr.Count() != 1
                        if (!HasTake())
                        {
                            message    = Invariant($"Replace 'Count() != {value}' with 'Take({value + 1}).Count() != {value}'");
                            properties = CreateProperties(OptimizeLinqUsageData.UseTakeAndCount);
                        }
                    }

                    break;

                case BinaryOperatorKind.LessThan:
                    if (value <= 0)
                    {
                        // expr.Count() < 0
                        message    = "Expression is always false";
                        properties = CreateProperties(OptimizeLinqUsageData.UseFalse);
                    }
                    else if (value == 1)
                    {
                        // expr.Count() < 1 ==> expr.Count() == 0
                        message    = "Replace 'Count() < 1' with 'Any() == false'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseNotAny);
                    }
                    else
                    {
                        // expr.Count() < 10
                        message    = Invariant($"Replace 'Count() < {value}' with 'Skip({value - 1}).Any() == false'");
                        properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndNotAny)
                                     .Add("SkipMinusOne", null);
                    }

                    break;

                case BinaryOperatorKind.LessThanOrEqual:
                    if (value < 0)
                    {
                        // expr.Count() <= -1
                        message    = "Expression is always false";
                        properties = CreateProperties(OptimizeLinqUsageData.UseFalse);
                    }
                    else if (value == 0)
                    {
                        // expr.Count() <= 0
                        message    = "Replace 'Count() <= 0' with 'Any() == false'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseNotAny);
                    }
                    else
                    {
                        // expr.Count() < 10
                        message    = Invariant($"Replace 'Count() <= {value}' with 'Skip({value}).Any() == false'");
                        properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndNotAny);
                    }

                    break;

                case BinaryOperatorKind.GreaterThan:
                    if (value < 0)
                    {
                        // expr.Count() > -1
                        message    = "Expression is always true";
                        properties = CreateProperties(OptimizeLinqUsageData.UseTrue);
                    }
                    else if (value == 0)
                    {
                        // expr.Count() > 0
                        message    = "Replace 'Count() > 0' with 'Any()'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseAny);
                    }
                    else
                    {
                        // expr.Count() > 1
                        message    = Invariant($"Replace 'Count() > {value}' with 'Skip({value}).Any()'");
                        properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndAny);
                    }

                    break;

                case BinaryOperatorKind.GreaterThanOrEqual:
                    if (value <= 0)
                    {
                        // expr.Count() >= 0
                        message    = "Expression is always true";
                        properties = CreateProperties(OptimizeLinqUsageData.UseTrue);
                    }
                    else if (value == 1)
                    {
                        // expr.Count() >= 1
                        message    = "Replace 'Count() >= 1' with 'Any()'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseAny);
                    }
                    else
                    {
                        // expr.Count() >= 2
                        message    = Invariant($"Replace 'Count() >= {value}' with 'Skip({value - 1}).Any()'");
                        properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndAny)
                                     .Add("SkipMinusOne", null);
                    }

                    break;
                }
            }
            else
            {
                switch (opKind)
                {
                case BinaryOperatorKind.Equals:
                    // expr.Count() == 1
                    if (!HasTake())
                    {
                        message    = "Replace 'Count() == n' with 'Take(n + 1).Count() == n'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseTakeAndCount);
                    }

                    break;

                case BinaryOperatorKind.NotEquals:
                    // expr.Count() != 1
                    if (!HasTake())
                    {
                        message    = "Replace 'Count() != n' with 'Take(n + 1).Count() != n'";
                        properties = CreateProperties(OptimizeLinqUsageData.UseTakeAndCount);
                    }

                    break;

                case BinaryOperatorKind.LessThan:
                    // expr.Count() < 10
                    message    = "Replace 'Count() < n' with 'Skip(n - 1).Any() == false'";
                    properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndNotAny)
                                 .Add("SkipMinusOne", null);
                    break;

                case BinaryOperatorKind.LessThanOrEqual:
                    // expr.Count() <= 10
                    message    = "Replace 'Count() <= n' with 'Skip(n).Any() == false'";
                    properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndNotAny);
                    break;

                case BinaryOperatorKind.GreaterThan:
                    // expr.Count() > 1
                    message    = "Replace 'Count() > n' with 'Skip(n).Any()'";
                    properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndAny);
                    break;

                case BinaryOperatorKind.GreaterThanOrEqual:
                    // expr.Count() >= 2
                    message    = "Replace 'Count() >= n' with 'Skip(n - 1).Any()'";
                    properties = CreateProperties(OptimizeLinqUsageData.UseSkipAndAny)
                                 .Add("SkipMinusOne", null);
                    break;
                }
            }

            if (message != null)
            {
                properties = properties
                             .Add("OperandOperationStart", otherOperand.Syntax.Span.Start.ToString(CultureInfo.InvariantCulture))
                             .Add("OperandOperationLength", otherOperand.Syntax.Span.Length.ToString(CultureInfo.InvariantCulture))
                             .Add("CountOperationStart", operation.Syntax.Span.Start.ToString(CultureInfo.InvariantCulture))
                             .Add("CountOperationLength", operation.Syntax.Span.Length.ToString(CultureInfo.InvariantCulture));

                context.ReportDiagnostic(s_optimizeCountRule, properties, binaryOperation, message);
            }
            private void AnalyzeXmlResolverPropertyAssignmentForXmlDocument(OperationAnalysisContext context, ISymbol assignedSymbol, IAssignmentExpression expression)
            {
                bool isSecureResolver = false;
                IConversionExpression conv = expression.Value as IConversionExpression;

                if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(conv.Operand.Type, _xmlTypes))
                {
                    isSecureResolver = true;
                }
                else if (conv != null && SecurityDiagnosticHelpers.IsExpressionEqualsNull(conv.Operand))
                {
                    isSecureResolver = true;
                }
                else // Assigning XmlDocument's XmlResolver to an insecure value
                {
                    Diagnostic diag = Diagnostic.Create(
                                RuleDoNotUseInsecureDtdProcessing,
                                context.Operation.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.XmlDocumentWithNoSecureResolverMessage)
                                )
                            );
                    context.ReportDiagnostic(diag);
                }

                if (_xmlDocumentEnvironments.ContainsKey(assignedSymbol))
                {
                    XmlDocumentEnvironment xmlDocumentEnv = _xmlDocumentEnvironments[assignedSymbol];
                    xmlDocumentEnv.IsXmlResolverSet = true;
                    xmlDocumentEnv.IsSecureResolver = isSecureResolver;
                }
            }
        private static void LAA1002_DictionarySetEnumeration(OperationAnalysisContext context)
        {
            const string           ns           = "System.Collections";
            SymbolDisplayFormat    symbolFormat = SymbolDisplayFormat.CSharpErrorMessageFormat;
            Compilation            comp         = context.Compilation;
            SymbolEqualityComparer comparer     = SymbolEqualityComparer.Default;

            bool TypeEquals(ITypeSymbol?valType, string metadataName) => valType is ITypeSymbol a &&
            comp.GetTypeByMetadataName(metadataName) is INamedTypeSymbol b &&
            comparer.Equals(a, b);

            string[] dictOrSets =
            {
                $"{ns}.Generic.IDictionary`2",
                $"{ns}.Generic.IReadOnlyDictionary`2",
                $"{ns}.Immutable.IImmutableDictionary`2",
                $"{ns}.IDictionary",
                $"{ns}.Generic.ISet`1",
                $"{ns}.Immutable.IImmutableSet`1",
            };

            string[] sortedTypes =
            {
                $"{ns}.Generic.SortedDictionary`2",
                $"{ns}.Immutable.ImmutableSortedDictionary`2",
                $"{ns}.Generic.SortedSet`1",
                $"{ns}.Immutable.ImmutableSortedSet`1",
                "Bencodex.Types.Dictionary",
            };

            bool IsDictOrSet(ITypeSymbol?valType) =>
            valType is ITypeSymbol t && t.OriginalDefinition.AllInterfaces
            .OfType <ITypeSymbol>()
            .Select(ifce => ifce.OriginalDefinition)
            .OfType <ITypeSymbol>()
            .Any(i => dictOrSets.Any(dst => TypeEquals(i, dst)));

            bool IsUnordered(ITypeSymbol?valType) =>
            valType is ITypeSymbol t && IsDictOrSet(t) &&
            !sortedTypes.Any(sortedType => TypeEquals(t.OriginalDefinition, sortedType));

            switch (context.Operation)
            {
            case IConversionOperation conv:
            {
                ITypeSymbol?endType = conv.Type;
                if (!TypeEquals(endType?.OriginalDefinition, $"{ns}.Generic.IEnumerable`1") &&
                    !TypeEquals(endType, $"{ns}.IEnumerable"))
                {
                    return;
                }

                if (conv.Parent is IArgumentOperation arg &&
                    arg.Parent is IInvocationOperation invoke &&
                    invoke.TargetMethod.IsGenericMethod &&
                    invoke.TargetMethod.OriginalDefinition is IMethodSymbol proto)
                {
                    var method = invoke.TargetMethod.Name;
                    if (method.StartsWith("OrderBy") &&
                        TypeEquals(proto.ContainingType, "System.Linq.Enumerable") &&
                        TypeEquals(
                            proto.ReturnType.OriginalDefinition,
                            "System.Linq.IOrderedEnumerable`1"
                            ))
                    {
                        // Ignores Linq's .OrderBy()/OrderByDescending() methods.
                        return;
                    }
                    else if (method.StartsWith("To") &&
                             (method.EndsWith("Dictionary") || method.EndsWith("Set")) &&
                             IsDictOrSet(proto.ReturnType))
                    {
                        // Ignores .ToDictionary()/ToHashSet() etc.
                        return;
                    }
                }

                if (conv.Parent is IArgumentOperation arg1 &&
                    arg1.Parent is IObjectCreationOperation @new &&
                    IsDictOrSet(@new.Type))
                {
                    // Ignores new Dictionary()/new HashSet() etc.
                    return;
                }

                ITypeSymbol?valType = conv.Operand?.Type;
                if (IsUnordered(valType))
                {
                    string func = "enumerating";
                    if (conv.Parent is IArgumentOperation argConv)
                    {
                        func = argConv.Parent switch
                        {
                            IObjectCreationOperation c =>
                            $"passing to {c.Constructor.ToDisplayString(symbolFormat)} " +
                            "constructor",
                            IInvocationOperation m =>
                            $"passing to {m.TargetMethod.ToDisplayString(symbolFormat)} " +
                            "method",
                                                     _ => func,
                        };
                    }

                    Diagnostic diag = Diagnostic.Create(
                        Rules[$"{IdPrefix}1002"],
                        conv.Syntax.GetLocation(),
                        valType !.ToDisplayString(symbolFormat),
                        func
                        );
                    context.ReportDiagnostic(diag);
                }

                break;
            }

            case IForEachLoopOperation loop:
            {
                IOperation  collection = loop.Collection;
                ITypeSymbol?collType   = collection.Type;
                if (IsUnordered(collType))
                {
                    Diagnostic diag = Diagnostic.Create(
                        Rules[$"{IdPrefix}1002"],
                        collection.Syntax.GetLocation(),
                        collType.ToDisplayString(symbolFormat),
                        "iterating via foreach"
                        );
                    context.ReportDiagnostic(diag);
                }

                break;
            }
            }
        }
 private void AnalyzeNeverSetProperties(OperationAnalysisContext context, IPropertySymbol property, Location location)
 {
     if (property.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.InnerXml))
     {
         DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
         context.ReportDiagnostic(
             Diagnostic.Create(
                 rule,
                 location,
                 SecurityDiagnosticHelpers.GetLocalizableResourceString(
                     nameof(DesktopAnalyzersResources.DoNotUseSetInnerXmlMessage)
                 )
             )
         );
     }
     else if (property.MatchPropertyDerivedByName(_xmlTypes.DataViewManager, SecurityMemberNames.DataViewSettingCollectionString))
     {
         DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
         context.ReportDiagnostic(
             Diagnostic.Create(
                 rule,
                 location,
                 SecurityDiagnosticHelpers.GetLocalizableResourceString(
                     nameof(DesktopAnalyzersResources.ReviewDtdProcessingPropertiesMessage)
                 )
             )
         );
     }
 }
Exemple #36
0
        private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol?expressionTypeOpt)
        {
            var cancellationToken = context.CancellationToken;

            var throwOperation = (IThrowOperation)context.Operation;

            if (throwOperation.Exception == null)
            {
                return;
            }

            var throwStatementSyntax = throwOperation.Syntax;

            var semanticModel = context.Operation.SemanticModel;

            Contract.ThrowIfNull(semanticModel);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            if (ifOperation.WhenFalse != null)
            {
                // Can't offer this if the 'if-statement' has an 'else-clause'.
                return;
            }

            var option = context.GetOption(_preferThrowExpressionOption);

            if (!option.Value)
            {
                return;
            }

            if (IsInExpressionTree(semanticModel, throwStatementSyntax, expressionTypeOpt, cancellationToken))
            {
                return;
            }

            if (ifOperation.Parent is not IBlockOperation containingBlock)
            {
                return;
            }

            if (!TryDecomposeIfCondition(ifOperation, out var localOrParameter))
            {
                return;
            }

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                                             out var expressionStatement, out var assignmentExpression))
            {
                return;
            }

            if (!localOrParameter.GetSymbolType().CanAddNullCheck())
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening accesses between the check and the assignment.
            if (ValueIsAccessed(
                    semanticModel, ifOperation, containingBlock,
                    localOrParameter, expressionStatement, assignmentExpression))
            {
                return;
            }

            // Ok, there were no intervening writes or accesses.  This check+assignment can be simplified.
            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.Exception.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            context.ReportDiagnostic(
                DiagnosticHelper.Create(Descriptor, throwStatementSyntax.GetLocation(), option.Notification.Severity, additionalLocations: allLocations, properties: null));
        }
Exemple #37
0
        private void AnalyzeBinaryOperator(OperationAnalysisContext context)
        {
            var operation = (IBinaryOperation)context.Operation;

            if (operation.OperatorMethod is not null)
            {
                // We shouldn't report diagnostic on overloaded operator as the behavior can change.
                return;
            }

            if (
                operation.OperatorKind
                is not(BinaryOperatorKind.Equals or BinaryOperatorKind.NotEquals)
                )
            {
                return;
            }

            if (!_syntaxFacts.IsBinaryExpression(operation.Syntax))
            {
                return;
            }

            var rightOperand = operation.RightOperand;
            var leftOperand  = operation.LeftOperand;

            if (rightOperand.Type is null || leftOperand.Type is null)
            {
                return;
            }

            if (
                rightOperand.Type.SpecialType != SpecialType.System_Boolean ||
                leftOperand.Type.SpecialType != SpecialType.System_Boolean
                )
            {
                return;
            }

            var isOperatorEquals = operation.OperatorKind == BinaryOperatorKind.Equals;

            _syntaxFacts.GetPartsOfBinaryExpression(
                operation.Syntax,
                out _,
                out var operatorToken,
                out _
                );
            var properties = ImmutableDictionary.CreateBuilder <string, string?>();

            if (TryGetLiteralValue(rightOperand) == isOperatorEquals)
            {
                properties.Add(
                    RedundantEqualityConstants.RedundantSide,
                    RedundantEqualityConstants.Right
                    );
            }
            else if (TryGetLiteralValue(leftOperand) == isOperatorEquals)
            {
                properties.Add(
                    RedundantEqualityConstants.RedundantSide,
                    RedundantEqualityConstants.Left
                    );
            }

            if (properties.Count == 1)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(
                        Descriptor,
                        operatorToken.GetLocation(),
                        additionalLocations: new[] { operation.Syntax.GetLocation() },
                        properties: properties.ToImmutable()
                        )
                    );
            }

            return;
        private void OnOperation(OperationAnalysisContext operationContext)
        {
            var invocation = (IInvocationOperation)operationContext.Operation;

            if (!IsStringFormatMethod(invocation.TargetMethod, out ITypeSymbol returnType, out int formatStringParameterIndex))
            {
                return;
            }

            var argument = invocation.Arguments[formatStringParameterIndex].Value;

            switch (argument.Kind)
            {
            case OperationKind.Invocation:
                if (CheckForNestedStringFormat(operationContext, invocation, (IInvocationOperation)argument))
                {
                    return;
                }
                break;

            case OperationKind.InterpolatedString:
                operationContext.ReportDiagnostic(Diagnostic.Create(NestedRule, argument.Syntax.GetLocation(), "an interpolated string", invocation.TargetMethod.ToDisplayString()));
                break;
            }

            if (returnType.SpecialType == SpecialType.System_String || returnType.SpecialType == SpecialType.System_Void)
            {
                var paramsArguments = invocation.Arguments[formatStringParameterIndex + 1].Value;

                if (paramsArguments is IArrayCreationOperation arrayCreation)
                {
                    if (arrayCreation.Initializer.ElementValues.IsEmpty && returnType.SpecialType == SpecialType.System_String)
                    {
                        //string format with no arguments
                        operationContext.ReportDiagnostic(Diagnostic.Create(UnnecessaryRule, argument.Syntax.GetLocation()));
                        return;
                    }

                    if (argument.Kind == OperationKind.Literal && argument.Type.SpecialType == SpecialType.System_String)
                    {
                        string formatValue = (string)argument.ConstantValue.Value;

                        if (_formatRegex.IsMatch(formatValue))
                        {
                            if (arrayCreation.Initializer.ElementValues.Length == 0)
                            {
                                //string format ala string.format("{0}");
                                operationContext.ReportDiagnostic(Diagnostic.Create(UnnecessaryRule, argument.Syntax.GetLocation()));
                                return;
                            }

                            if (ArrayContainsString(0, arrayCreation))
                            {
                                //string format ala string.format("{0}", 3);
                                operationContext.ReportDiagnostic(Diagnostic.Create(UnnecessaryRule, argument.Syntax.GetLocation()));
                                return;
                            }
                        }
                    }
                }
                else if (paramsArguments is IConversionOperation conversion)
                {
                    if (argument.Kind == OperationKind.Literal && argument.Type.SpecialType == SpecialType.System_String)
                    {
                        if (((string)argument.ConstantValue.Value) == "{0}" && conversion.Operand.Type.SpecialType == SpecialType.System_String)
                        {
                            operationContext.ReportDiagnostic(Diagnostic.Create(UnnecessaryRule, argument.Syntax.GetLocation()));
                            return;
                        }
                    }
                }
            }
        }
Exemple #39
0
 private static void ReportDiagnostic(OperationAnalysisContext context, object messageArg)
 => context.ReportDiagnostic(Diagnostic.Create(_descriptor, NarrowDownSyntax(context.Operation.Syntax).GetLocation(), messageArg));
Exemple #40
0
            private void AnalyzeMethodOverloads(OperationAnalysisContext context, IMethodSymbol method, IHasArgumentsExpression expression)
            {
                if (method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.Load) ||                               //FxCop CA3056
                    method.MatchMethodDerivedByName(_xmlTypes.XmlDocument, SecurityMemberNames.LoadXml) ||                            //FxCop CA3057
                    method.MatchMethodDerivedByName(_xmlTypes.XPathDocument, WellKnownMemberNames.InstanceConstructorName) ||         //FxCop CA3059
                    method.MatchMethodDerivedByName(_xmlTypes.XmlSchema, SecurityMemberNames.Read) ||                                 //FxCop CA3060
                    method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXml) ||                                //FxCop CA3063
                    method.MatchMethodDerivedByName(_xmlTypes.DataSet, SecurityMemberNames.ReadXmlSchema) ||                          //FxCop CA3064
                    method.MatchMethodDerivedByName(_xmlTypes.XmlSerializer, SecurityMemberNames.Deserialize) ||                      //FxCop CA3070
                    method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXml) ||                              //FxCop CA3071
                    method.MatchMethodDerivedByName(_xmlTypes.DataTable, SecurityMemberNames.ReadXmlSchema))                          //FxCop CA3072
                {
                    if (SecurityDiagnosticHelpers.HasXmlReaderParameter(method, _xmlTypes) < 0)
                    {
                        DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                rule,
                                expression.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.DoNotUseDtdProcessingOverloadsMessage),
                                    method.Name
                                    )
                                )
                            );
                    }
                }
                else if (method.MatchMethodDerivedByName(_xmlTypes.XmlReader, SecurityMemberNames.Create))
                {
                    int xmlReaderSettingsIndex = SecurityDiagnosticHelpers.GetXmlReaderSettingsParameterIndex(method, _xmlTypes);

                    if (xmlReaderSettingsIndex < 0)
                    {
                        DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessing;
                        Diagnostic           diag = Diagnostic.Create(
                            RuleDoNotUseInsecureDtdProcessing,
                            expression.Syntax.GetLocation(),
                            SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                nameof(DesktopAnalyzersResources.XmlReaderCreateWrongOverloadMessage)
                                )
                            );
                        context.ReportDiagnostic(diag);
                    }
                    else
                    {
                        SemanticModel model          = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree);
                        IArgument     arg            = expression.ArgumentsInParameterOrder[xmlReaderSettingsIndex];
                        ISymbol       settingsSymbol = arg.Value.Syntax.GetDeclaredOrReferencedSymbol(model);

                        if (settingsSymbol == null)
                        {
                            return;
                        }

                        XmlReaderSettingsEnvironment env;

                        if (!_xmlReaderSettingsEnvironments.TryGetValue(settingsSymbol, out env))
                        {
                            // symbol for settings is not found => passed in without any change => assume insecure
                            Diagnostic diag = Diagnostic.Create(
                                RuleDoNotUseInsecureDtdProcessing,
                                expression.Syntax.GetLocation(),
                                SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                    nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureInputMessage)
                                    )
                                );
                            context.ReportDiagnostic(diag);
                        }
                        else if (!env.IsDtdProcessingDisabled && !(env.IsSecureResolver && env.IsMaxCharactersFromEntitiesLimited))
                        {
                            Diagnostic diag;
                            if (env.IsConstructedInCodeBlock)
                            {
                                diag = Diagnostic.Create(
                                    RuleDoNotUseInsecureDtdProcessing,
                                    expression.Syntax.GetLocation(),
                                    SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                        nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureConstructedMessage)
                                        )
                                    );
                            }
                            else
                            {
                                diag = Diagnostic.Create(
                                    RuleDoNotUseInsecureDtdProcessing,
                                    expression.Syntax.GetLocation(),
                                    SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                        nameof(DesktopAnalyzersResources.XmlReaderCreateInsecureInputMessage)
                                        )
                                    );
                            }
                            context.ReportDiagnostic(diag);
                        }
                    }
                }
            }
        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));
            }
        }
Exemple #42
0
            private void AnalyzeObjectCreationForXmlDocument(OperationAnalysisContext context, ISymbol variable, IObjectCreationExpression objCreation)
            {
                XmlDocumentEnvironment xmlDocumentEnvironment;

                if (variable == null || !_xmlDocumentEnvironments.ContainsKey(variable))
                {
                    xmlDocumentEnvironment = new XmlDocumentEnvironment
                    {
                        IsSecureResolver = false,
                        IsXmlResolverSet = false
                    };
                }
                else
                {
                    xmlDocumentEnvironment = _xmlDocumentEnvironments[variable];
                }

                xmlDocumentEnvironment.XmlDocumentDefinition = objCreation.Syntax;
                SyntaxNode node = objCreation.Syntax;
                bool       isXmlDocumentSecureResolver = false;

                if (objCreation.Constructor.ContainingType != _xmlTypes.XmlDocument)
                {
                    isXmlDocumentSecureResolver = true;
                }

                foreach (ISymbolInitializer init in objCreation.MemberInitializers)
                {
                    var prop = init as IPropertyInitializer;

                    if (prop != null)
                    {
                        if (prop.InitializedProperty.MatchPropertyDerivedByName(_xmlTypes.XmlDocument, "XmlResolver"))
                        {
                            IConversionExpression operation = prop.Value as IConversionExpression;

                            if (operation == null)
                            {
                                return;
                            }

                            if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes))
                            {
                                isXmlDocumentSecureResolver = true;
                            }
                            else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand))
                            {
                                isXmlDocumentSecureResolver = true;
                            }
                            else // Non secure resolvers
                            {
                                IObjectCreationExpression xmlResolverObjCreated = operation.Operand as IObjectCreationExpression;

                                if (xmlResolverObjCreated != null)
                                {
                                    Diagnostic diag = Diagnostic.Create(
                                        RuleDoNotUseInsecureDtdProcessing,
                                        prop.Syntax.GetLocation(),
                                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                            nameof(DesktopAnalyzersResources.XmlDocumentWithNoSecureResolverMessage)
                                            )
                                        );
                                    context.ReportDiagnostic(diag);
                                }

                                return;
                            }
                        }
                        else
                        {
                            AnalyzeNeverSetProperties(context, prop.InitializedProperty, prop.Syntax.GetLocation());
                        }
                    }
                }


                xmlDocumentEnvironment.IsSecureResolver = isXmlDocumentSecureResolver;

                if (variable != null)
                {
                    _xmlDocumentEnvironments[variable] = xmlDocumentEnvironment;
                }
                else if (!xmlDocumentEnvironment.IsSecureResolver) // Insecure temp object
                {
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        node.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlDocumentWithNoSecureResolverMessage)
                            )
                        );
                    context.ReportDiagnostic(diag);
                }
            }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;

            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwOperation = (IThrowStatement)context.Operation;
            var throwStatement = throwOperation.Syntax;

            var optionSet = context.Options.GetOptionSet();
            var option    = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatement.Language);

            if (!option.Value)
            {
                return;
            }

            var compilation   = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatement.SyntaxTree);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            var containingBlock = GetOperation(
                semanticModel, ifOperation.Syntax.Parent, cancellationToken) as IBlockStatement;

            if (containingBlock == null)
            {
                return;
            }

            ISymbol localOrParameter;

            if (!TryDecomposeIfCondition(ifOperation, out localOrParameter))
            {
                return;
            }

            IExpressionStatement  expressionStatement;
            IAssignmentExpression assignmentExpression;

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                                             out expressionStatement, out assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening writes between the check and the assignement.
            var dataFlow = semanticModel.AnalyzeDataFlow(
                ifOperation.Syntax, expressionStatement.Syntax);

            if (dataFlow.WrittenInside.Contains(localOrParameter))
            {
                return;
            }

            // Ok, there were no intervening writes.  This check+assignment can be simplified.

            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.ThrownObject.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = CreateDescriptor(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatement.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatement.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow  = throwStatement.GetLastToken().GetNextToken();

            context.ReportDiagnostic(
                Diagnostic.Create(s_unnecessaryCodeDescriptor,
                                  Location.Create(syntaxTree, TextSpan.FromBounds(
                                                      ifOperation.Syntax.SpanStart,
                                                      tokenBeforeThrow.Span.End)),
                                  additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(s_unnecessaryCodeDescriptor,
                                      Location.Create(syntaxTree, TextSpan.FromBounds(
                                                          tokenAfterThrow.Span.Start,
                                                          ifOperation.Syntax.Span.End)),
                                      additionalLocations: allLocations));
            }
        }
Exemple #44
0
            private void AnalyzeObjectCreationForXmlTextReader(OperationAnalysisContext context, ISymbol variable, IObjectCreationExpression objCreation)
            {
                XmlTextReaderEnvironment env;

                if (variable == null || !_xmlTextReaderEnvironments.TryGetValue(variable, out env))
                {
                    env = new XmlTextReaderEnvironment(_isFrameworkSecure)
                    {
                        XmlTextReaderDefinition = objCreation.Syntax
                    };
                }

                if (objCreation.Constructor.ContainingType != _xmlTypes.XmlTextReader)
                {
                    env.IsDtdProcessingDisabled = true;
                    env.IsSecureResolver        = true;
                }

                foreach (ISymbolInitializer init in objCreation.MemberInitializers)
                {
                    var prop = init as IPropertyInitializer;

                    if (prop != null)
                    {
                        IConversionExpression operation = prop.Value as IConversionExpression;

                        if (operation != null && SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverPropertyDerived(prop.InitializedProperty, _xmlTypes))
                        {
                            env.IsXmlResolverSet = true;

                            if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(operation.Operand.Type, _xmlTypes))
                            {
                                env.IsSecureResolver = true;
                            }
                            else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(operation.Operand))
                            {
                                env.IsSecureResolver = true;
                            }
                            else
                            {
                                env.IsSecureResolver = false;
                            }
                        }
                        else if (SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingPropertyDerived(prop.InitializedProperty, _xmlTypes))
                        {
                            env.IsDtdProcessingSet      = true;
                            env.IsDtdProcessingDisabled = !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(prop.Value);
                        }
                    }
                }

                // if the XmlResolver or Dtdprocessing property is explicitly set when created, and is to an insecure value, generate a warning
                if ((env.IsXmlResolverSet && !env.IsSecureResolver) ||
                    (env.IsDtdProcessingSet && !env.IsDtdProcessingDisabled))
                {
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        env.XmlTextReaderDefinition.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlTextReaderSetInsecureResolutionMessage)
                            )
                        );
                    context.ReportDiagnostic(diag);
                }
                // if the XmlResolver or Dtdprocessing property is not explicitly set when constructed for a non-temp XmlTextReader object, add env to the dictionary.
                else if (variable != null && !(env.IsDtdProcessingSet && env.IsXmlResolverSet))
                {
                    _xmlTextReaderEnvironments[variable] = env;
                }
                // if the is not set or set to Parse for a temporary object, report right now.
                else if (variable == null && !(env.IsDtdProcessingSet && env.IsXmlResolverSet && env.IsDtdProcessingDisabled && env.IsSecureResolver))
                {
                    Diagnostic diag = Diagnostic.Create(
                        RuleDoNotUseInsecureDtdProcessing,
                        env.XmlTextReaderDefinition.GetLocation(),
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(DesktopAnalyzersResources.XmlTextReaderConstructedWithNoSecureResolutionMessage)
                            )
                        );
                    context.ReportDiagnostic(diag);
                }
            }
Exemple #45
0
 /// <summary>Reports a diagnostic warning for a boxing operation.</summary>
 /// <param name="context">The context.</param>
 /// <param name="boxingExpression">The expression that produces the boxing.</param>
 internal void Report(OperationAnalysisContext context, SyntaxNode boxingExpression)
 {
     context.ReportDiagnostic(Diagnostic.Create(BoxingDescriptor, boxingExpression.GetLocation()));
 }
Exemple #46
0
        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 TSimpleNameSyntax simpleName))
            {
                return;
            }

            var syntaxTree        = context.Operation.Syntax.SyntaxTree;
            var cancellationToken = context.CancellationToken;
            var optionSet         = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var applicableOption = QualifyMembersHelpers.GetApplicableOptionFromSymbolKind(operation);
            var optionValue      = optionSet.GetOption(applicableOption, context.Operation.Syntax.Language);

            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));
            }
        }
 /// <summary>
 /// Creates a new instance of the <see cref="ContextualDiagnosticReceiver{T}"/> class that accepts only <see cref="OperationAnalysisContext"/>.
 /// </summary>
 /// <param name="context">Context of this <see cref="ContextualDiagnosticReceiver{T}"/>.</param>
 public static ContextualDiagnosticReceiver <OperationAnalysisContext> Operation(OperationAnalysisContext context)
 {
     return(new ContextualDiagnosticReceiver <OperationAnalysisContext>((context, diag) => context.ReportDiagnostic(diag), context));
 }
Exemple #48
0
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;

            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwOperation = (IThrowStatement)context.Operation;
            var throwStatement = throwOperation.Syntax;
            var options        = context.Options;
            var optionSet      = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatement.Language);

            if (!option.Value)
            {
                return;
            }

            var compilation   = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatement.SyntaxTree);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            var containingBlock = GetOperation(
                semanticModel, ifOperation.Syntax.Parent, cancellationToken) as IBlockStatement;

            if (containingBlock == null)
            {
                return;
            }

            if (!TryDecomposeIfCondition(ifOperation, out var localOrParameter))
            {
                return;
            }

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                                             out var expressionStatement, out var assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening accesses between the check and the assignment.
            var statements               = containingBlock.Statements;
            var ifOperationIndex         = statements.IndexOf(ifOperation);
            var expressionStatementIndex = statements.IndexOf(expressionStatement);

            if (expressionStatementIndex > ifOperationIndex + 1)
            {
                // There are intermediary statements between the check and the assignment.
                // Make sure they don't try to access the local.
                var dataFlow = semanticModel.AnalyzeDataFlow(
                    statements[ifOperationIndex + 1].Syntax,
                    statements[expressionStatementIndex - 1].Syntax);

                if (dataFlow.ReadInside.Contains(localOrParameter) ||
                    dataFlow.WrittenInside.Contains(localOrParameter))
                {
                    return;
                }
            }

            // Ok, there were no intervening writes or accesses.  This check+assignment can be simplified.

            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.ThrownObject.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = GetDescriptorWithSeverity(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatement.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatement.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow  = throwStatement.GetLastToken().GetNextToken();

            context.ReportDiagnostic(
                Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                  Location.Create(syntaxTree, TextSpan.FromBounds(
                                                      ifOperation.Syntax.SpanStart,
                                                      tokenBeforeThrow.Span.End)),
                                  additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                      Location.Create(syntaxTree, TextSpan.FromBounds(
                                                          tokenAfterThrow.Span.Start,
                                                          ifOperation.Syntax.Span.End)),
                                      additionalLocations: allLocations));
            }
        }
        private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol expressionTypeOpt)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;

            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwOperation       = (IThrowOperation)context.Operation;
            var throwStatementSyntax = throwOperation.Syntax;

            var compilation   = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatementSyntax.SyntaxTree);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            if (ifOperation.WhenFalse != null)
            {
                // Can't offer this if the 'if-statement' has an 'else-clause'.
                return;
            }

            var options   = context.Options;
            var optionSet = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatementSyntax.Language);

            if (!option.Value)
            {
                return;
            }

            var semanticFacts = GetSemanticFactsService();

            if (semanticFacts.IsInExpressionTree(semanticModel, throwStatementSyntax, expressionTypeOpt, cancellationToken))
            {
                return;
            }

            var containingBlock = semanticModel.GetOperation(ifOperation.Syntax.Parent, cancellationToken) as IBlockOperation;

            if (containingBlock == null)
            {
                return;
            }

            if (!TryDecomposeIfCondition(ifOperation, out var localOrParameter))
            {
                return;
            }

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                                             out var expressionStatement, out var assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening accesses between the check and the assignment.
            if (ValueIsAccessed(
                    semanticModel, ifOperation, containingBlock,
                    localOrParameter, expressionStatement, assignmentExpression))
            {
                return;
            }

            // Ok, there were no intervening writes or accesses.  This check+assignment can be simplified.
            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.Exception.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = GetDescriptorWithSeverity(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatementSyntax.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatementSyntax.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow  = throwStatementSyntax.GetLastToken().GetNextToken();

            context.ReportDiagnostic(
                Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                  Location.Create(syntaxTree, TextSpan.FromBounds(
                                                      ifOperation.Syntax.SpanStart,
                                                      tokenBeforeThrow.Span.End)),
                                  additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                      Location.Create(syntaxTree, TextSpan.FromBounds(
                                                          tokenAfterThrow.Span.Start,
                                                          ifOperation.Syntax.Span.End)),
                                      additionalLocations: allLocations));
            }
        }
 /// <summary>Reports a diagnostic warning for a boxing operation.</summary>
 /// <param name="context">The context.</param>
 /// <param name="boxingExpression">The expression that produces the boxing.</param>
 internal void Report(OperationAnalysisContext context, SyntaxNode boxingExpression)
 {
     context.ReportDiagnostic(Diagnostic.Create(BoxingDescriptor, boxingExpression.GetLocation()));
 }
Exemple #51
0
 private static void Report(OperationAnalysisContext context, SyntaxNode syntax, DiagnosticDescriptor descriptor)
 {
     context.ReportDiagnostic(Diagnostic.Create(descriptor, syntax.GetLocation()));
 }
Exemple #52
0
        protected override void AnalyzeAssertInvocation(OperationAnalysisContext context, IInvocationOperation assertOperation)
        {
            if (!AssertHelper.TryGetActualAndConstraintOperations(assertOperation,
                                                                  out var actualOperation, out var constraintExpression))
            {
                return;
            }

            if (actualOperation == null)
            {
                return;
            }

            var actualType = AssertHelper.GetUnwrappedActualType(actualOperation);

            if (actualType == null)
            {
                return;
            }

            foreach (var constraintPartExpression in constraintExpression.ConstraintParts)
            {
                if (constraintPartExpression.HasIncompatiblePrefixes() ||
                    HasCustomComparer(constraintPartExpression) ||
                    constraintPartExpression.HasUnknownExpressions())
                {
                    continue;
                }

                var constraintMethod = constraintPartExpression.GetConstraintMethod();
                if (constraintMethod == null)
                {
                    continue;
                }

                if (!SupportedConstraints.Contains(constraintMethod.Name))
                {
                    continue;
                }

                var expectedOperation = constraintPartExpression.GetExpectedArgument();
                if (expectedOperation == null)
                {
                    continue;
                }

                var expectedType = expectedOperation.Type;
                if (expectedType == null)
                {
                    continue;
                }

                if (actualType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                {
                    actualType = ((INamedTypeSymbol)actualType).TypeArguments[0];
                }

                if (expectedType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                {
                    expectedType = ((INamedTypeSymbol)expectedType).TypeArguments[0];
                }

                if (actualType.SpecialType == SpecialType.System_Object ||
                    expectedType.SpecialType == SpecialType.System_Object)
                {
                    // An instance of object might not implement IComparable resulting in runtime errors.
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 comparableOnObjectDescriptor,
                                                 expectedOperation.Syntax.GetLocation(),
                                                 constraintMethod.Name));
                }
                else if (!CanCompare(actualType, expectedType, context.Compilation))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 comparableTypesDescriptor,
                                                 expectedOperation.Syntax.GetLocation(),
                                                 constraintMethod.Name));
                }
            }
        }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;
            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwOperation = (IThrowStatement)context.Operation;
            var throwStatement = throwOperation.Syntax;
            var options = context.Options;
            var optionSet = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
            if (optionSet == null)
            {
                return;
            }
            
            var option = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatement.Language);
            if (!option.Value)
            {
                return;
            }

            var compilation = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatement.SyntaxTree);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            var containingBlock = GetOperation(
                semanticModel, ifOperation.Syntax.Parent, cancellationToken) as IBlockStatement;
            if (containingBlock == null)
            {
                return;
            }

            if (!TryDecomposeIfCondition(ifOperation, out var localOrParameter))
            {
                return;
            }

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                out var expressionStatement, out var assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening accesses between the check and the assignment.
            var statements = containingBlock.Statements;
            var ifOperationIndex = statements.IndexOf(ifOperation);
            var expressionStatementIndex = statements.IndexOf(expressionStatement);

            if (expressionStatementIndex > ifOperationIndex + 1)
            {
                // There are intermediary statements between the check and the assignment.
                // Make sure they don't try to access the local.
                var dataFlow = semanticModel.AnalyzeDataFlow(
                    statements[ifOperationIndex + 1].Syntax,
                    statements[expressionStatementIndex - 1].Syntax);

                if (dataFlow.ReadInside.Contains(localOrParameter) ||
                    dataFlow.WrittenInside.Contains(localOrParameter))
                {
                    return;
                }
            }

            // Ok, there were no intervening writes or accesses.  This check+assignment can be simplified.

            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.ThrownObject.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = CreateDescriptorWithSeverity(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatement.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatement.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow = throwStatement.GetLastToken().GetNextToken();
            context.ReportDiagnostic(
                Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                    Location.Create(syntaxTree, TextSpan.FromBounds(
                        ifOperation.Syntax.SpanStart,
                        tokenBeforeThrow.Span.End)),
                    additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                        Location.Create(syntaxTree, TextSpan.FromBounds(
                            tokenAfterThrow.Span.Start,
                            ifOperation.Syntax.Span.End)),
                        additionalLocations: allLocations));
            }
        }
Exemple #54
0
            static void AnalyzeOperation(OperationAnalysisContext context, IMethodSymbol containsKeyMethod, IMethodSymbol remove1Param, IMethodSymbol?remove2Param)
            {
                var conditionalOperation = (IConditionalOperation)context.Operation;

                IInvocationOperation?invocationOperation = null;

                switch (conditionalOperation.Condition)
                {
                case IInvocationOperation iOperation:
                    invocationOperation = iOperation;
                    break;

                case IUnaryOperation unaryOperation when unaryOperation.OperatorKind == UnaryOperatorKind.Not:
                    if (unaryOperation.Operand is IInvocationOperation operand)
                    {
                        invocationOperation = operand;
                    }
                    break;

                case IParenthesizedOperation parenthesizedOperation:
                    if (parenthesizedOperation.Operand is IInvocationOperation invocation)
                    {
                        invocationOperation = invocation;
                    }
                    break;

                default:
                    return;
                }

                if (invocationOperation == null || !invocationOperation.TargetMethod.OriginalDefinition.Equals(containsKeyMethod, SymbolEqualityComparer.Default))
                {
                    return;
                }

                if (conditionalOperation.WhenTrue.Children.Any())
                {
                    using var additionalLocation = ArrayBuilder <Location> .GetInstance(2);

                    additionalLocation.Add(conditionalOperation.Syntax.GetLocation());

                    switch (conditionalOperation.WhenTrue.Children.First())
                    {
                    case IInvocationOperation childInvocationOperation:
                        if (childInvocationOperation.TargetMethod.OriginalDefinition.Equals(remove1Param, SymbolEqualityComparer.Default) ||
                            childInvocationOperation.TargetMethod.OriginalDefinition.Equals(remove2Param, SymbolEqualityComparer.Default))
                        {
                            additionalLocation.Add(childInvocationOperation.Syntax.Parent.GetLocation());
                            context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule, additionalLocations: additionalLocation.ToImmutable(), null));
                        }

                        break;

                    case IExpressionStatementOperation childStatementOperation:
                        /*
                         * If the if statement contains a block, only proceed if one of the methods calls Remove.
                         * However, a fixer is only offered if there is a single method in the block.
                         */

                        var nestedInvocationOperation = childStatementOperation.Children.OfType <IInvocationOperation>()
                                                        .FirstOrDefault(op => op.TargetMethod.OriginalDefinition.Equals(remove1Param, SymbolEqualityComparer.Default) ||
                                                                        op.TargetMethod.OriginalDefinition.Equals(remove2Param, SymbolEqualityComparer.Default));

                        if (nestedInvocationOperation != null)
                        {
                            additionalLocation.Add(nestedInvocationOperation.Syntax.Parent.GetLocation());
                            context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule, additionalLocations: additionalLocation.ToImmutable(), null));
                        }

                        break;

                    default:
                        break;
                    }
                }
            }
        private static void AnalyzeObjectCreation(OperationAnalysisContext context, ISymbol owningSymbol)
        {
            var arrayCreationExpression = (IArrayCreationExpression)context.Operation;

            if (IsMultiDimensionalArray(arrayCreationExpression.Type))
            {
                context.ReportDiagnostic(arrayCreationExpression.Syntax.CreateDiagnostic(BodyRule, owningSymbol.Name, arrayCreationExpression.Type));
            }
        }
        private void AnalyzeOperation(OperationAnalysisContext context)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;
            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwOperation = (IThrowStatement)context.Operation;
            var throwStatement = throwOperation.Syntax;

            var optionSet = context.Options.GetOptionSet();
            var option = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatement.Language);
            if (!option.Value)
            {
                return;
            }

            var compilation = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatement.SyntaxTree);

            var ifOperation = GetContainingIfOperation(
                semanticModel, throwOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            var containingBlock = GetOperation(
                semanticModel, ifOperation.Syntax.Parent, cancellationToken) as IBlockStatement;
            if (containingBlock == null)
            {
                return;
            }

            ISymbol localOrParameter;
            if (!TryDecomposeIfCondition(ifOperation, out localOrParameter))
            {
                return;
            }

            IExpressionStatement expressionStatement;
            IAssignmentExpression assignmentExpression;
            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                out expressionStatement, out assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening writes between the check and the assignement.
            var dataFlow = semanticModel.AnalyzeDataFlow(
                ifOperation.Syntax, expressionStatement.Syntax);

            if (dataFlow.WrittenInside.Contains(localOrParameter))
            {
                return;
            }

            // Ok, there were no intervening writes.  This check+assignment can be simplified.

            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwOperation.ThrownObject.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = CreateDescriptor(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatement.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatement.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow = throwStatement.GetLastToken().GetNextToken();
            context.ReportDiagnostic(
                Diagnostic.Create(s_unnecessaryCodeDescriptor,
                    Location.Create(syntaxTree, TextSpan.FromBounds(
                        ifOperation.Syntax.SpanStart,
                        tokenBeforeThrow.Span.End)),
                    additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(s_unnecessaryCodeDescriptor,
                        Location.Create(syntaxTree, TextSpan.FromBounds(
                            tokenAfterThrow.Span.Start,
                            ifOperation.Syntax.Span.End)),
                        additionalLocations: allLocations));
            }
        }