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 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));
                    }
                }
            }
        }
        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));
     }
 }
 private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol stringComparisonType)
 {
     OperationKind kind = context.Operation.Kind;
     if (kind == OperationKind.InvocationExpression)
     {
         AnalyzeInvocationExpression((IInvocationExpression)context.Operation, stringComparisonType, context.ReportDiagnostic);
     }
     else
     {
         AnalyzeBinaryExpression((IBinaryOperatorExpression)context.Operation, context.ReportDiagnostic);
     }
 }
        private static void AnalyzeNode(OperationAnalysisContext context)
        {
            switch (context.Operation.Kind)
            {
                case OperationKind.InvocationExpression:
                    AnalyzeInvocationExpression(context);
                    break;

                default:
                    AnalyzeBinaryExpression(context);
                    break;
            }
        }
 /// <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 AnalyzeObjectCreation(
            OperationAnalysisContext context,
            ISymbol owningSymbol,
            ITypeSymbol argumentExceptionType)
        {
            var creation = (IObjectCreationExpression)context.Operation;
            if (!creation.Type.Inherits(argumentExceptionType))
            {
                return;
            }

            if (creation.ArgumentsInParameterOrder.Length == 0)
            {
                if (HasMessageOrParameterNameConstructor(creation.Type))
                {
                    // Call the {0} constructor that contains a message and/ or paramName parameter
                    ReportDiagnostic(context, s_localizableMessageNoArguments, creation.Type.Name);
                }
            }
            else
            {
                foreach (IArgument argument in creation.ArgumentsInParameterOrder)
                {
                    if (argument.Parameter.Type.SpecialType != SpecialType.System_String)
                    {
                        continue;
                    }

                    string value = argument.Value.ConstantValue.HasValue ? argument.Value.ConstantValue.Value as string : null;
                    if (value == null)
                    {
                        continue;
                    }

                    CheckArgument(owningSymbol, creation.Type, argument.Parameter, value, context);
                }
            }
        }
            private void AnalyzeInvocation(OperationAnalysisContext context)
            {
                IInvocationExpression invocationExpression = context.Operation as IInvocationExpression;

                if(invocationExpression == null)
                {
                    return;
                }

                IMethodSymbol method = invocationExpression.TargetMethod;

                if(method == null)
                {
                    return;
                }

                AnalyzeMethodOverloads(context, method, invocationExpression);
            }
示例#13
0
 private static void Report(OperationAnalysisContext context, SyntaxNode syntax, DiagnosticDescriptor descriptor)
 {
     context.ReportDiagnostic(Diagnostic.Create(descriptor, syntax.GetLocation()));
 }
示例#14
0
            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)));
                }
            }
 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)
                 )
             )
         );
     }
 }
 private void AnalyzeVariableDeclaration(OperationAnalysisContext context)
 {
     IVariableDeclaration declare = context.Operation as IVariableDeclaration;
     AnalyzeObjectCreationInternal(context, declare.Variable, declare.InitialValue);
 }
        private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol expressionTypeOpt)
        {
            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 semanticFacts = GetSemanticFactsService();

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

            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.IfFalseStatement != null)
            {
                // Can't offer this if the 'if-statement' has an 'else-clause'.
                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 static bool ShouldSkipAnalyzing(OperationAnalysisContext operationContext, INamedTypeSymbol expectedExceptionType, INamedTypeSymbol xunitAssertType, INamedTypeSymbol nunitAssertType)
        {
            bool IsThrowsArgument(IParameterSymbol parameterSymbol, string argumentName, ImmutableHashSet <string> methodNames, INamedTypeSymbol assertSymbol)
            {
                return(parameterSymbol.Name == argumentName &&
                       parameterSymbol.ContainingSymbol is IMethodSymbol methodSymbol &&
                       methodNames.Contains(methodSymbol.Name) &&
                       methodSymbol.ContainingSymbol == assertSymbol);
            }

            bool IsNUnitThrowsArgument(IParameterSymbol parameterSymbol)
            {
                return(IsThrowsArgument(parameterSymbol, "code", s_nUnitMethodNames, nunitAssertType));
            }

            bool IsXunitThrowsArgument(IParameterSymbol parameterSymbol)
            {
                return(IsThrowsArgument(parameterSymbol, "testCode", s_xUnitMethodNames, xunitAssertType));
            }

            // We skip analysis for the last statement in a lambda passed to Assert.Throws/ThrowsAsync (xUnit and NUnit), or the last
            // statement in a method annotated with [ExpectedException] (MSTest)

            if (expectedExceptionType == null && xunitAssertType == null && nunitAssertType == null)
            {
                return(false);
            }

            // Note: We do not attempt to account for a synchronously-running ThrowsAsync with something like return Task.CompletedTask;
            // as the last line.

            // We only skip analysis if we're in a method
            if (operationContext.ContainingSymbol.Kind != SymbolKind.Method)
            {
                return(false);
            }

            // Get the enclosing block. If that block's parent isn't null (MSTest case) or an IAnonymousFunctionOperation (xUnit/NUnit), then
            // we bail immediately
            if (!(operationContext.Operation.Parent is IBlockOperation enclosingBlock))
            {
                return(false);
            }

            if (enclosingBlock.Parent != null && enclosingBlock.Parent.Kind != OperationKind.AnonymousFunction)
            {
                return(false);
            }

            // Only skip analyzing the last non-implicit statement in the function
            bool foundBlock = false;

            foreach (var statement in enclosingBlock.Operations)
            {
                if (statement == operationContext.Operation)
                {
                    foundBlock = true;
                }
                else if (foundBlock)
                {
                    if (!statement.IsImplicit)
                    {
                        return(false);
                    }
                }
            }

            // If the parent is Null, we're in the MSTest case. Otherwise, we're in the xUnit/NUnit case.
            if (enclosingBlock.Parent == null)
            {
                if (expectedExceptionType == null)
                {
                    return(false);
                }

                IMethodSymbol methodSymbol = (IMethodSymbol)operationContext.ContainingSymbol;

                return(methodSymbol.GetAttributes().Any(attr => attr.AttributeClass == expectedExceptionType));
            }
            else
            {
                IArgumentOperation argumentOperation = enclosingBlock.GetAncestor <IArgumentOperation>(OperationKind.Argument);

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

                return(IsNUnitThrowsArgument(argumentOperation.Parameter) || IsXunitThrowsArgument(argumentOperation.Parameter));
            }
        }
 public virtual void HandleOperation(OperationAnalysisContext context)
 {
 }
            private void OnMethodReference(OperationAnalysisContext context)
            {
                var methodBinding = (IMethodReferenceOperation)context.Operation;

                _methodsUsedAsDelegates.GetOrAdd(methodBinding.Method.OriginalDefinition, true);
            }
 private static bool ShouldSkipAnalyzing(OperationAnalysisContext operationContext, INamedTypeSymbol?expectedExceptionType, INamedTypeSymbol?xunitAssertType, INamedTypeSymbol?nunitAssertType)
 {
        private IMethodSymbol TryGetContainingMethod([NotNull] IInvocationExpression invocation, OperationAnalysisContext context)
        {
            SemanticModel model = context.Compilation.GetSemanticModel(invocation.Syntax.SyntaxTree);

            return(model.GetEnclosingSymbol(invocation.Syntax.GetLocation().SourceSpan.Start) as IMethodSymbol);
        }
 static bool GetUseNamingHeuristicOption(OperationAnalysisContext operationContext)
 => operationContext.Options.GetBoolOptionValue(EditorConfigOptionNames.UseNamingHeuristic, Rule,
                                                operationContext.Operation.Syntax.SyntaxTree, operationContext.Compilation, defaultValue: false);
            private void AnalyzeFieldDeclaration(OperationAnalysisContext context)
            {
                IFieldInitializer fieldInit = context.Operation as IFieldInitializer;

                if(fieldInit == null)
                {
                    return;
                }

                foreach (IFieldSymbol field in fieldInit.InitializedFields)
                {
                    IOperation valueOperation = fieldInit.Value;
                    AnalyzeObjectCreationInternal(context, field, valueOperation);
                }
            }
            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);
                }
            }
示例#26
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 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);
                }
            }
示例#28
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 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)));
 }
示例#30
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);
                }
            }
        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));
            }
        }
示例#32
0
            private void AnalyzeVariableDeclaration(OperationAnalysisContext context)
            {
                IVariableDeclaration declare = context.Operation as IVariableDeclaration;

                AnalyzeObjectCreationInternal(context, declare.Variable, declare.InitialValue);
            }
        /// <summary>
        /// Checks if the tuple language feature is supported.
        /// </summary>
        /// <param name="context">The analysis context that will be checked.</param>
        /// <returns>True if tuples are supported by the compiler.</returns>
        internal static bool SupportsTuples(this OperationAnalysisContext context)
        {
            var csharpParseOptions = context.Operation.Syntax.SyntaxTree.Options as CSharpParseOptions;

            return((csharpParseOptions != null) && (csharpParseOptions.LanguageVersion >= LanguageVersionEx.CSharp7));
        }
示例#34
0
            private void AnalyzeAssignment(OperationAnalysisContext context)
            {
                IAssignmentExpression expression = context.Operation as IAssignmentExpression;

                if (expression.Target == null)
                {
                    return;
                }

                SemanticModel model   = context.Compilation.GetSemanticModel(expression.Syntax.SyntaxTree);
                var           propRef = expression.Target as IPropertyReferenceExpression;

                if (propRef == null) // A variable/field assignment
                {
                    ISymbol symbolAssignedTo = expression.Target.Syntax.GetDeclaredOrReferencedSymbol(model);

                    if (symbolAssignedTo != null)
                    {
                        AnalyzeObjectCreationInternal(context, symbolAssignedTo, expression.Value);
                    }
                }
                else // A property assignment
                {
                    if (propRef.Instance == null)
                    {
                        return;
                    }

                    ISymbol assignedSymbol = propRef.Instance.Syntax.GetDeclaredOrReferencedSymbol(model);

                    if (propRef.Property.MatchPropertyByName(_xmlTypes.XmlDocument, "XmlResolver"))
                    {
                        AnalyzeXmlResolverPropertyAssignmentForXmlDocument(context, assignedSymbol, expression);
                    }
                    else
                    {
                        bool isXmlTextReaderXmlResolverProperty =
                            SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverPropertyDerived(propRef.Property, _xmlTypes);
                        bool isXmlTextReaderDtdProcessingProperty = !isXmlTextReaderXmlResolverProperty &&
                                                                    SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingPropertyDerived(propRef.Property, _xmlTypes);
                        if (isXmlTextReaderXmlResolverProperty || isXmlTextReaderDtdProcessingProperty)
                        {
                            AnalyzeXmlTextReaderProperties(context, assignedSymbol, expression, isXmlTextReaderXmlResolverProperty,
                                                           isXmlTextReaderDtdProcessingProperty);
                        }
                        else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsType(propRef.Instance.Type, _xmlTypes))
                        {
                            XmlReaderSettingsEnvironment env;

                            if (!_xmlReaderSettingsEnvironments.TryGetValue(assignedSymbol, out env))
                            {
                                env = new XmlReaderSettingsEnvironment(_isFrameworkSecure);
                                _xmlReaderSettingsEnvironments[assignedSymbol] = env;
                            }

                            IConversionExpression conv = expression.Value as IConversionExpression;

                            if (conv != null && SecurityDiagnosticHelpers.IsXmlReaderSettingsXmlResolverProperty(propRef.Property, _xmlTypes))
                            {
                                if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(conv.Operand.Type, _xmlTypes))
                                {
                                    env.IsSecureResolver = true;
                                }
                                else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(conv.Operand))
                                {
                                    env.IsSecureResolver = true;
                                }
                            }
                            else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsDtdProcessingProperty(propRef.Property, _xmlTypes))
                            {
                                env.IsDtdProcessingDisabled =
                                    !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(expression.Value);
                            }
                            else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsMaxCharactersFromEntitiesProperty(propRef.Property,
                                                                                                                    _xmlTypes))
                            {
                                env.IsMaxCharactersFromEntitiesLimited =
                                    !SecurityDiagnosticHelpers.IsExpressionEqualsIntZero(expression.Value);
                            }
                        }
                        else
                        {
                            AnalyzeNeverSetProperties(context, propRef.Property, expression.Syntax.GetLocation());
                        }
                    }
                }
            }
示例#35
0
        private static void TestAscendingArgument(OperationAnalysisContext operationContext, IOperation argument, ref long priorArgumentValue)
        {
            Optional<object> argumentValue = argument.ConstantValue;
            if (argumentValue.HasValue && argument.Type.SpecialType == SpecialType.System_Int32)
            {
                int integerArgument = (int)argumentValue.Value;
                if (integerArgument < priorArgumentValue)
                {
                    Report(operationContext, argument.Syntax, OutOfNumericalOrderArgumentsDescriptor);
                }

                priorArgumentValue = integerArgument;
            }
        }
示例#36
0
 private void AnalyzeObjectCreationOperation(OperationAnalysisContext context)
 {
     AnalyzeObjectCreationInternal(context, null, context.Operation);
 }
 public void AnalyzeOperation(OperationAnalysisContext context)
 {
     switch (context.Operation.Kind)
     {
         case OperationKind.ObjectCreationExpression:
             AnalyzeObjectCreationOperation(context);
             break;
         case OperationKind.AssignmentExpression:
             AnalyzeAssignment(context);
             break;
         case OperationKind.FieldInitializerAtDeclaration:
             AnalyzeFieldDeclaration(context);
             break;
         case OperationKind.VariableDeclaration:
             AnalyzeVariableDeclaration(context);
             break;
         case OperationKind.InvocationExpression:
             AnalyzeInvocation(context);
             break;
     }
 }
 protected abstract bool IsValidTypeofAction(OperationAnalysisContext context);
            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);
                        }
                    }
                }
            }
示例#40
0
        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;
            }

            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));

            // 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));
            }
        }
            private void AnalyzeObjectCreationInternal(OperationAnalysisContext context, ISymbol variable, IOperation value)
            {
                IObjectCreationExpression objCreation = value as IObjectCreationExpression;

                if (objCreation == null)
                {
                    return;
                }

                if (_objectCreationOperationsAnalyzed.Contains(objCreation))
                {
                    return;
                }
                else
                {
                    _objectCreationOperationsAnalyzed.Add(objCreation);
                }

                if (SecurityDiagnosticHelpers.IsXmlDocumentCtorDerived(objCreation.Constructor, _xmlTypes))
                {
                    AnalyzeObjectCreationForXmlDocument(context, variable, objCreation);
                }
                else if (SecurityDiagnosticHelpers.IsXmlTextReaderCtorDerived(objCreation.Constructor, _xmlTypes))
                {
                    AnalyzeObjectCreationForXmlTextReader(context, variable, objCreation);
                }
                else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsCtor(objCreation.Constructor, _xmlTypes))
                {
                    AnalyzeObjectCreationForXmlReaderSettings(variable, objCreation);
                }
                else
                {
                    AnalyzeMethodOverloads(context, objCreation.Constructor, objCreation);
                }
            }
 private static IEventSymbol TryGetEventForLocalCopy([NotNull] IOperation operation,
                                                     [CanBeNull] IMethodSymbol containingMethod, OperationAnalysisContext context)
 {
     return(operation is ILocalReferenceOperation local && containingMethod != null
         ? TryGetEventFromMethodStatements(containingMethod, local.Local, context)
         : null);
 }
            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 static IEventSymbol TryGetEventFromMethodStatements([NotNull] IMethodSymbol containingMethod,
                                                                    [NotNull] ILocalSymbol local, OperationAnalysisContext context)
        {
            IOperation body = containingMethod.TryGetOperationBlockForMethod(context.Compilation, context.CancellationToken);

            if (body != null)
            {
                var walker = new LocalAssignmentWalker(local);
                walker.Visit(body);

                return(walker.Event);
            }

            return(null);
        }
            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 AnalyzeMethodCall(OperationAnalysisContext operationContext,
                                              IMethodSymbol constructorSymbol,
                                              ISymbol containingSymbol,
                                              ImmutableArray <IArgumentOperation> arguments,
                                              SyntaxNode invocationSyntax,
                                              bool isInDbCommandConstructor,
                                              bool isInDataAdapterConstructor,
                                              INamedTypeSymbol iDbCommandType,
                                              INamedTypeSymbol iDataAdapterType)
        {
            CheckForDbCommandAndDataAdapterImplementation(constructorSymbol.ContainingType, iDbCommandType, iDataAdapterType,
                                                          out var callingDbCommandConstructor,
                                                          out var callingDataAdapterConstructor);

            if (!callingDataAdapterConstructor && !callingDbCommandConstructor)
            {
                return;
            }

            // All parameters the function takes that are explicit strings are potential vulnerabilities
            var potentials = arguments.WhereAsArray(arg => arg.Parameter.Type.SpecialType == SpecialType.System_String && !arg.Parameter.IsImplicitlyDeclared);

            if (potentials.IsEmpty)
            {
                return;
            }

            var vulnerableArgumentsBuilder = ImmutableArray.CreateBuilder <IArgumentOperation>();

            foreach (var argument in potentials)
            {
                // For the constructor of a IDbCommand-derived class, if there is only one string parameter, then we just
                // assume that it's the command text. If it takes more than one string, then we need to figure out which
                // one is the command string. However, for the constructor of a IDataAdapter, a lot of times the
                // constructor also take in the connection string, so we can't assume it's the command if there is only one
                // string.
                if (callingDataAdapterConstructor || potentials.Length > 1)
                {
                    if (!IsParameterSymbolVulnerable(argument.Parameter))
                    {
                        continue;
                    }
                }

                vulnerableArgumentsBuilder.Add(argument);
            }

            var vulnerableArguments = vulnerableArgumentsBuilder.ToImmutable();

            foreach (var argument in vulnerableArguments)
            {
                if (IsParameterSymbolVulnerable(argument.Parameter) && (isInDbCommandConstructor || isInDataAdapterConstructor))
                {
                    //No warnings, as Constructor parameters in derived classes are assumed to be safe since this rule will check the constructor arguments at their call sites.
                    return;
                }

                if (ReportDiagnosticIfNecessary(operationContext, argument.Value, invocationSyntax, constructorSymbol, containingSymbol))
                {
                    // Only report one warning per invocation
                    return;
                }
            }
        }
            private void AnalyzeAssignment(OperationAnalysisContext context)
            {
                IAssignmentExpression expression = context.Operation as IAssignmentExpression;

                if (expression.Target == null)
                {
                    return;
                }

                SemanticModel model = context.Compilation.GetSemanticModel(expression.Syntax.SyntaxTree);
                var propRef = expression.Target as IPropertyReferenceExpression;

                if (propRef == null) // A variable/field assignment
                {
                    ISymbol symbolAssignedTo = expression.Target.Syntax.GetDeclaredOrReferencedSymbol(model);

                    if (symbolAssignedTo != null)
                    {
                        AnalyzeObjectCreationInternal(context, symbolAssignedTo, expression.Value);
                    }
                }
                else // A property assignment
                {
                    if (propRef.Instance == null)
                    {
                        return;
                    }

                    ISymbol assignedSymbol = propRef.Instance.Syntax.GetDeclaredOrReferencedSymbol(model);

                    if (propRef.Property.MatchPropertyByName(_xmlTypes.XmlDocument, "XmlResolver"))
                    {
                        AnalyzeXmlResolverPropertyAssignmentForXmlDocument(context, assignedSymbol, expression);
                    }
                    else
                    {
                        bool isXmlTextReaderXmlResolverProperty =
                            SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverPropertyDerived(propRef.Property, _xmlTypes);
                        bool isXmlTextReaderDtdProcessingProperty = !isXmlTextReaderXmlResolverProperty &&
                            SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingPropertyDerived(propRef.Property,_xmlTypes);
                        if (isXmlTextReaderXmlResolverProperty || isXmlTextReaderDtdProcessingProperty)
                        {
                            AnalyzeXmlTextReaderProperties(context, assignedSymbol, expression, isXmlTextReaderXmlResolverProperty, 
                                isXmlTextReaderDtdProcessingProperty);
                        }
                        else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsType(propRef.Instance.Type, _xmlTypes))
                        {
                            XmlReaderSettingsEnvironment env;

                            if (!_xmlReaderSettingsEnvironments.TryGetValue(assignedSymbol, out env))
                            {
                                env = new XmlReaderSettingsEnvironment(_isFrameworkSecure);
                                _xmlReaderSettingsEnvironments[assignedSymbol] = env;
                            }

                            IConversionExpression conv = expression.Value as IConversionExpression;

                            if (conv != null && SecurityDiagnosticHelpers.IsXmlReaderSettingsXmlResolverProperty(propRef.Property, _xmlTypes))
                            {
                                if (SecurityDiagnosticHelpers.IsXmlSecureResolverType(conv.Operand.Type, _xmlTypes))
                                {
                                    env.IsSecureResolver = true;
                                }
                                else if (SecurityDiagnosticHelpers.IsExpressionEqualsNull(conv.Operand))
                                {
                                    env.IsSecureResolver = true;
                                }
                            }
                            else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsDtdProcessingProperty(propRef.Property, _xmlTypes))
                            {
                                env.IsDtdProcessingDisabled =
                                    !SecurityDiagnosticHelpers.IsExpressionEqualsDtdProcessingParse(expression.Value);
                            }
                            else if (SecurityDiagnosticHelpers.IsXmlReaderSettingsMaxCharactersFromEntitiesProperty(propRef.Property,
                                _xmlTypes))
                            {
                                env.IsMaxCharactersFromEntitiesLimited =
                                    !SecurityDiagnosticHelpers.IsExpressionEqualsIntZero(expression.Value);
                            }
                        }
                        else
                        {
                            AnalyzeNeverSetProperties(context, propRef.Property, expression.Syntax.GetLocation());
                        }
                    }
                }
            }
        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 AnalyzeObjectCreationOperation(OperationAnalysisContext context)
 {
     AnalyzeObjectCreationInternal(context, null, context.Operation);
 }
            public void AnalyzeOperation(OperationAnalysisContext context)
            {
                // Check if we have any pending unreferenced parameters.
                if (_unusedParameters.Count == 0)
                {
                    return;
                }

                // Mark this parameter as used.
                var parameter = ((IParameterReferenceExpression)context.Operation).Parameter;
                _unusedParameters.Remove(parameter);
            }
示例#51
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));
            }
        }
示例#52
0
            internal void AnalyzeInvocation(OperationAnalysisContext context)
            {
                var operation    = (IInvocationOperation)context.Operation;
                var targetMethod = operation.TargetMethod;

                if (operation.IsInNameofOperation())
                {
                    return;
                }

                // Task.Wait()
                // Task`1.Wait()
                if (string.Equals(targetMethod.Name, nameof(Task.Wait), StringComparison.Ordinal))
                {
                    if (targetMethod.ContainingType.OriginalDefinition.IsEqualToAny(TaskSymbol, TaskOfTSymbol))
                    {
                        ReportDiagnosticIfNeeded(context, operation, "Use await instead of 'Wait()'");
                        return;
                    }
                }

                // Task.GetAwaiter().GetResult()
                if (string.Equals(targetMethod.Name, nameof(TaskAwaiter.GetResult), StringComparison.Ordinal))
                {
                    if (targetMethod.ContainingType.OriginalDefinition.IsEqualTo(TaskAwaiterSymbol))
                    {
                        ReportDiagnosticIfNeeded(context, operation, "Use await instead of 'GetResult()'");
                        return;
                    }
                }

                // Thread.Sleep => Task.Delay
                if (string.Equals(targetMethod.Name, "Sleep", StringComparison.Ordinal))
                {
                    if (targetMethod.ContainingType.IsEqualToAny(ThreadSymbols))
                    {
                        ReportDiagnosticIfNeeded(context, operation, "Use await and 'Task.Delay()' instead of 'Thread.Sleep()'");
                        return;
                    }
                }

                // Search async equivalent: sample.Write() => sample.WriteAsync()
                if (!targetMethod.ReturnType.OriginalDefinition.IsEqualToAny(TaskSymbol, TaskOfTSymbol))
                {
                    var potentialMethod = targetMethod.ContainingType.GetMembers().FirstOrDefault(IsPotentialMember);
                    if (potentialMethod != null)
                    {
                        ReportDiagnosticIfNeeded(context, operation, $"Use '{potentialMethod.Name}' instead of '{targetMethod.Name}'");
                    }

                    bool IsPotentialMember(ISymbol memberSymbol)
                    {
                        if (memberSymbol.Equals(targetMethod))
                        {
                            return(false);
                        }

                        if (memberSymbol is IMethodSymbol methodSymbol)
                        {
                            if (targetMethod.IsStatic && !methodSymbol.IsStatic)
                            {
                                return(false);
                            }

                            if (!string.Equals(methodSymbol.Name, targetMethod.Name, StringComparison.Ordinal) && !string.Equals(methodSymbol.Name, targetMethod.Name + "Async", StringComparison.Ordinal))
                            {
                                return(false);
                            }

                            if (!methodSymbol.ReturnType.OriginalDefinition.IsEqualToAny(TaskSymbol, TaskOfTSymbol))
                            {
                                return(false);
                            }

                            if (methodSymbol.IsObsolete(context.Compilation))
                            {
                                return(false);
                            }

                            if (!targetMethod.HasSimilarParameters(methodSymbol) && !targetMethod.HasSimilarParameters(methodSymbol, CancellationTokenSymbol))
                            {
                                return(false);
                            }

                            return(true);
                        }

                        return(false);
                    }
                }
            }
 private static void AnalyzePropertyReference(IPropertyReferenceOperation operation, OperationAnalysisContext context, string methodName)
 {
     operation = FindVirtualPropertyReference(operation);
     if (operation == null)
     {
         return;
     }
     if (IsLocalReference(operation.Instance))
     {
         var diagnostic = Diagnostic.Create(LazyEvaluationInExpressionRule, operation.Syntax.GetLocation(), operation.Property.Name,
                                            methodName);
         context.ReportDiagnostic(diagnostic);
     }
 }
 private static void ReportDiagnostic(OperationAnalysisContext context, object messageArg)
 => context.ReportDiagnostic(
     Diagnostic.Create(Descriptor, NarrowDownSyntax(context.Operation.Syntax).GetLocation(), messageArg));
示例#55
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 (!method.MatchesConfiguredVisibility(context.ContainingSymbol, context.Options, Rule, context.Compilation, context.CancellationToken))
                {
                    // 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 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 &&
                            !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;
                        }
                    }
                }
            }
                static void CheckMethodOrCtorCall(
                    OperationAnalysisContext operationContext,
                    IMethodSymbol method)
                {
                    // Find containing symbol
                    ISymbol?containingSymbol = null;
                    for (var current = operationContext.Operation;
                         current is not null;
                         current = current.Parent)
                    {
                        if (current is ILocalFunctionOperation local)
                        {
                            containingSymbol = local.Symbol;
                            break;
                        }
                        else if (current is IAnonymousFunctionOperation lambda)
                        {
                            containingSymbol = lambda.Symbol;
                            break;
                        }
                        else if (current is IMethodBodyBaseOperation)
                        {
                            break;
                        }
                    }
                    containingSymbol ??= operationContext.ContainingSymbol;

                    // If parent method contains RequiresUnreferencedCodeAttribute then we shouldn't report diagnostics for this method
                    if (containingSymbol is IMethodSymbol &&
                        containingSymbol.HasAttribute(RequiresUnreferencedCodeAttribute))
                    {
                        return;
                    }

                    // If calling an instance constructor, check first for any static constructor since it will be called implicitly
                    if (method.ContainingType is { } containingType&& operationContext.Operation is IObjectCreationOperation)
                    {
                        CheckStaticConstructors(operationContext, containingType.StaticConstructors);
                    }

                    if (!method.HasAttribute(RequiresUnreferencedCodeAttribute))
                    {
                        return;
                    }

                    // Warn on the most derived base method taking into account covariant returns
                    while (method.OverriddenMethod != null && SymbolEqualityComparer.Default.Equals(method.ReturnType, method.OverriddenMethod.ReturnType))
                    {
                        method = method.OverriddenMethod;
                    }

                    if (method.TryGetAttributeWithMessageOnCtor(FullyQualifiedRequiresUnreferencedCodeAttribute, out AttributeData? requiresUnreferencedCode))
                    {
                        operationContext.ReportDiagnostic(Diagnostic.Create(
                                                              s_requiresUnreferencedCodeRule,
                                                              operationContext.Operation.Syntax.GetLocation(),
                                                              method.OriginalDefinition.ToString(),
                                                              (string)requiresUnreferencedCode !.ConstructorArguments[0].Value !,
                                                              requiresUnreferencedCode !.NamedArguments.FirstOrDefault(na => na.Key == "Url").Value.Value?.ToString()));
                    }
                }
示例#57
0
        private static void ReportAtLastClause([NotNull] ISwitchCaseOperation switchCase, OperationAnalysisContext context)
        {
            ICaseClauseOperation lastClause = switchCase.Clauses.Last();

            Location location = lastClause.GetLocationForKeyword();

            context.ReportDiagnostic(Diagnostic.Create(Rule, location));
        }
        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)
                    {
                        if (((string)argument.ConstantValue.Value) == "{0}" && 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;
                        }
                    }
                }
            }
        }
        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, 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));
            }
        }