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); }
private static void Report(OperationAnalysisContext context, SyntaxNode syntax, DiagnosticDescriptor descriptor) { context.ReportDiagnostic(Diagnostic.Create(descriptor, syntax.GetLocation())); }
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); } }
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); } }
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))); }
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)); } }
/// <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)); }
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 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; } }
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); } } } }
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 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); }
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); }
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)); } }
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));
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())); } }
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)); } }