public override void VisitArgument(IArgumentOperation operation) { var argumentKind = operation.ArgumentKind; var parameter = operation.Parameter; base.VisitArgument(operation); }
private static Argument ReadArgument(IArgumentOperation op) { return(new Argument { Modifier = op.Parameter.GetParameterModifier(), Expression = ReadExpression(op.Value) }); }
private static void AnalyzeAnalyzerReleases( string ruleId, IArgumentOperation ruleIdArgument, string?category, string analyzerName, string?helpLink, bool?isEnabledByDefault, DiagnosticSeverity?defaultSeverity, ReleaseTrackingData shippedData, ReleaseTrackingData unshippedData, Action <Diagnostic> addDiagnostic) { if (!TryGetLatestReleaseTrackingLine(ruleId, shippedData, unshippedData, out _, out var releaseTrackingLine) || releaseTrackingLine.IsShipped && releaseTrackingLine.IsRemovedRule) { var properties = ImmutableDictionary <string, string?> .Empty.Add( EntryToAddPropertyName, GetEntry(ruleId, category, analyzerName, helpLink, isEnabledByDefault, defaultSeverity)); var diagnostic = ruleIdArgument.CreateDiagnostic(DeclareDiagnosticIdInAnalyzerReleaseRule, properties, ruleId); addDiagnostic(diagnostic); return; } if (releaseTrackingLine.IsRemovedRule) { var diagnostic = ruleIdArgument.CreateDiagnostic(UnexpectedAnalyzerDiagnosticForRemovedDiagnosticIdRule, ruleId); addDiagnostic(diagnostic); return; } if (category != null && !string.Equals(category, releaseTrackingLine.Category, StringComparison.OrdinalIgnoreCase) || isEnabledByDefault != null && isEnabledByDefault != releaseTrackingLine.EnabledByDefault || defaultSeverity != null && defaultSeverity != releaseTrackingLine.DefaultSeverity) { string propertyName; (string category, bool?isEnabledByDefault, DiagnosticSeverity? defaultSeverity)? oldRule = null; if (!releaseTrackingLine.IsShipped) { // For existing entry in unshipped file, we can just update. propertyName = EntryToUpdatePropertyName; if (releaseTrackingLine is ChangedRuleReleaseTrackingLine changedLine) { oldRule = (changedLine.OldCategory, changedLine.OldEnabledByDefault, changedLine.OldDefaultSeverity); } } else { // Need to add a new changed rule entry in unshipped file. propertyName = EntryToAddPropertyName; oldRule = (releaseTrackingLine.Category, releaseTrackingLine.EnabledByDefault, releaseTrackingLine.DefaultSeverity); } var newEntry = GetEntry(ruleId, category, analyzerName, helpLink, isEnabledByDefault, defaultSeverity, oldRule); var properties = ImmutableDictionary <string, string?> .Empty.Add(propertyName, newEntry); var diagnostic = ruleIdArgument.CreateDiagnostic(UpdateDiagnosticIdInAnalyzerReleaseRule, properties, ruleId); addDiagnostic(diagnostic); return; } }
private static IArgumentOperation GetSenderArgument([NotNull] IInvocationOperation invocation) { IArgumentOperation argument = invocation.Arguments.FirstOrDefault(nextArgument => nextArgument.Parameter.Name == "sender"); return(argument != null && argument.Parameter.Type.SpecialType == SpecialType.System_Object ? argument : null); }
private static void AnalyzeInvocationExpression(IInvocationOperation operation, INamedTypeSymbol stringComparisonType, Action <Diagnostic> reportDiagnostic, Func <SyntaxNode, Location> getMethodNameLocation) { IMethodSymbol methodSymbol = operation.TargetMethod; if (methodSymbol != null && methodSymbol.ContainingType.SpecialType == SpecialType.System_String && IsEqualsOrCompare(methodSymbol.Name)) { if (!IsAcceptableOverload(methodSymbol, stringComparisonType)) { // wrong overload reportDiagnostic(Diagnostic.Create(Rule, getMethodNameLocation(operation.Syntax))); } else { IArgumentOperation lastArgument = operation.Arguments.Last(); if (lastArgument.Value.Kind == OperationKind.FieldReference) { IFieldSymbol fieldSymbol = ((IFieldReferenceOperation)lastArgument.Value).Field; if (fieldSymbol != null && fieldSymbol.ContainingType.Equals(stringComparisonType) && !IsOrdinalOrOrdinalIgnoreCase(fieldSymbol.Name)) { // right overload, wrong value reportDiagnostic(lastArgument.Syntax.CreateDiagnostic(Rule)); } } } } }
public override TAbstractAnalysisValue VisitArgument(IArgumentOperation operation, object argument) { var value = Visit(operation.Value, argument); _pendingArgumentsToReset.Add(operation); return(value); }
public override bool VisitArgument([NotNull] IArgumentOperation operation1, [CanBeNull] IOperation argument) { return(argument is IArgumentOperation operation2 && AreBaseOperationsEqual(operation1, operation2) && operation1.ArgumentKind == operation2.ArgumentKind && AreSymbolsEqual(operation1.Parameter, operation2.Parameter) && operation1.InConversion.Equals(operation2.InConversion) && operation1.OutConversion.Equals(operation2.OutConversion)); }
private static void AnalyzeArgument(IArgumentOperation argument, OperationAnalysisContext context, string methodName) { if (!HasLambdaExpression(argument)) { return; } FindAndAnalyzePropertyReference(argument, context, methodName); }
private void AnalyzeMethodOverloads(OperationAnalysisContext context, IMethodSymbol method, ImmutableArray <IArgumentOperation> arguments, SyntaxNode expressionSyntax) { 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) { context.ReportDiagnostic(expressionSyntax.CreateDiagnostic(RuleDoNotUseDtdProcessingOverloads, method.Name)); } } else if (method.MatchMethodDerivedByName(_xmlTypes.XmlReader, SecurityMemberNames.Create)) { int xmlReaderSettingsIndex = SecurityDiagnosticHelpers.GetXmlReaderSettingsParameterIndex(method, _xmlTypes); if (xmlReaderSettingsIndex < 0) { if (method.Parameters.Length == 1 && method.Parameters[0].RefKind == RefKind.None && method.Parameters[0].Type.SpecialType == SpecialType.System_String) { // inputUri can load be a URL. Should further investigate if this is worth flagging. context.ReportDiagnostic(expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateWrongOverload)); } // If no XmlReaderSettings are passed, then the default // XmlReaderSettings are used, with DtdProcessing set to Prohibit. } else if (arguments.Length > xmlReaderSettingsIndex) { IArgumentOperation arg = arguments[xmlReaderSettingsIndex]; ISymbol settingsSymbol = arg.GetReferencedMemberOrLocalOrParameter(); if (settingsSymbol == null) { return; } // If we have no XmlReaderSettingsEnvironment, then we don't know. if (_xmlReaderSettingsEnvironments.TryGetValue(settingsSymbol, out XmlReaderSettingsEnvironment env) && !env.IsDtdProcessingDisabled && !(env.IsSecureResolver && env.IsMaxCharactersFromEntitiesLimited)) { var diag = env.IsConstructedInCodeBlock ? expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateInsecureConstructed) : expressionSyntax.CreateDiagnostic(RuleXmlReaderCreateInsecureInput); context.ReportDiagnostic(diag); } } } }
public override void VisitArgument([NotNull] IArgumentOperation operation) { if (operation.Parameter.RefKind == RefKind.Ref || operation.Parameter.RefKind == RefKind.Out) { RegisterAssignmentToParameter(operation.Value); } base.VisitArgument(operation); }
private static void ReportArgument([NotNull] IArgumentOperation argument, [NotNull] Action <Diagnostic> reportDiagnostic) { var syntax = (ArgumentSyntax)argument.Syntax; string methodText = argument.Parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat); reportDiagnostic(Diagnostic.Create(Rule, syntax.NameColon.GetLocation(), argument.Parameter.Name, methodText)); }
private static void AnalyzeSenderArgument([NotNull] IInvocationOperation invocation, OperationAnalysisContext context) { IArgumentOperation senderArgument = GetSenderArgument(invocation); if (senderArgument != null && IsNullConstant(senderArgument.Value)) { context.ReportDiagnostic(Diagnostic.Create(SenderRule, senderArgument.Syntax.GetLocation())); } }
protected override TAbstractAnalysisValue ComputeAnalysisValueForOutArgument(IArgumentOperation operation, TAbstractAnalysisValue defaultValue) { if (operation.Value.Type != null) { PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(operation); return(HandleInstanceCreation(operation.Value.Type, instanceLocation, defaultValue)); } return(defaultValue); }
private static bool IsThis(IArgumentOperation operation) { var value = operation.Value; while (value is IConversionOperation conversion) { value = conversion.Operand; } return(value is IInstanceReferenceOperation); }
private static void AnalyzeArgsArgument([NotNull] IInvocationOperation invocation, [NotNull] INamedTypeSymbol systemEventArgs, OperationAnalysisContext context) { IArgumentOperation argsArgument = GetArgsArgument(invocation, systemEventArgs); if (argsArgument != null && IsNullConstant(argsArgument.Value)) { context.ReportDiagnostic(Diagnostic.Create(ArgsRule, argsArgument.Syntax.GetLocation(), argsArgument.Parameter.Name)); } }
static bool CheckForViolation(IArgumentOperation primaryArgument) { if (primaryArgument.Value is ILiteralOperation literalOperation && literalOperation.ConstantValue.HasValue && literalOperation.ConstantValue.Value is string constantString && constantString.Length == 1) { return(true); } return(false); }
public override DisposeAbstractValue VisitArgument(IArgumentOperation operation, object argument) { var value = base.VisitArgument(operation, argument); // Discover if a disposable object is being passed into the creation method for this new disposable object // and if the new dispoable object assumes ownership of that passed in disposable object. if (operation.Parent is IObjectCreationOperation objectCreation && objectCreation.Arguments.Length == 1 && objectCreation.Constructor.Parameters.Length == 1 && _disposeOwnershipTransferLikelyTypes.Contains(objectCreation.Constructor.Parameters[0].Type)) { HandlePossibleEscapingOperation(operation, operation.Value); }
public static ITypeSymbol GetArgumentOperationActualTypeSymbol(this IArgumentOperation argumentOperation) { ITypeSymbol conversionTypeSymbol = null; switch (argumentOperation.Value) { case IConversionOperation conversionOperation: conversionTypeSymbol = conversionOperation.Operand.Type; break; } return(conversionTypeSymbol ?? argumentOperation.GetArgumentOperationDeclaredTypeSymbol()); }
private static void AnalyzeDescription(OperationAnalysisContext operationAnalysisContext, ImmutableArray <IArgumentOperation> creationArguments) { IArgumentOperation descriptionArgument = creationArguments.FirstOrDefault(a => a.Parameter.Name.Equals("description", StringComparison.OrdinalIgnoreCase)); if (!TryGetNonEmptyConstantStringValue(descriptionArgument, out var description)) { return; } if (!EndsWithPunctuation(description)) { operationAnalysisContext.ReportDiagnostic(descriptionArgument.CreateDiagnostic(DefineDiagnosticDescriptionCorrectlyRule)); } }
public override void VisitArgument(IArgumentOperation operation) { Assert.Equal(OperationKind.Argument, operation.Kind); Assert.Contains(operation.ArgumentKind, new[] { ArgumentKind.DefaultValue, ArgumentKind.Explicit, ArgumentKind.ParamArray }); var parameter = operation.Parameter; Assert.Same(operation.Value, operation.Children.Single()); var inConversion = operation.InConversion; var outConversion = operation.OutConversion; if (operation.ArgumentKind == ArgumentKind.DefaultValue) { Assert.True(operation.Descendants().All(n => n.IsImplicit), $"Explicit node in default argument value ({operation.Syntax.RawKind}): {operation.Syntax.ToString()}"); } }
private static bool RequiresReport([NotNull] IArgumentOperation argument, [NotNull] IInvocationOperation invocation, [NotNull] IDictionary <IParameterSymbol, bool> parameterUsageMap) { if (RequiresAnalysis(argument)) { ICollection <IParameterSymbol> precedingParameters = GetPrecedingParameters(argument.Parameter, invocation.TargetMethod); if (AreParametersUsed(precedingParameters, parameterUsageMap)) { return(true); } } return(false); }
private static void AnalyzeMessage(OperationAnalysisContext operationAnalysisContext, ImmutableArray <IArgumentOperation> creationArguments) { IArgumentOperation messageArgument = creationArguments.FirstOrDefault(a => a.Parameter.Name.Equals("messageFormat", StringComparison.OrdinalIgnoreCase)); if (!TryGetNonEmptyConstantStringValue(messageArgument, out var message)) { return; } var isMultiSentenceMessage = message.Contains(". "); if ((IsMultiSentences(message) ^ EndsWithPeriod(message)) || ContainsLineReturn(message)) { operationAnalysisContext.ReportDiagnostic(messageArgument.CreateDiagnostic(DefineDiagnosticMessageCorrectlyRule)); } }
/// <summary> /// Resets the analysis data for an object instance passed around as an <see cref="IArgumentOperation"/>. /// </summary> private void ResetInstanceAnalysisDataForArgument(IArgumentOperation operation) { // For reference types passed as arguments, // reset all analysis data for the instance members as the content might change for them. if (HasPointsToAnalysisResult && !operation.Value.Type.HasValueCopySemantics()) { ResetReferenceTypeInstanceAnalysisData(operation.Value); } // Handle ref/out arguments as escapes. if (operation.Parameter.RefKind != RefKind.None) { SetAbstractValueForAssignment(operation.Value, operation.Value, ValueDomain.UnknownOrMayBeValue); } }
private static bool HasLambdaExpression(IArgumentOperation argument) { ArgumentSyntax syntax = argument.Syntax as ArgumentSyntax; if (syntax == null) { return(false); } LambdaExpressionSyntax lambdaSyntax = syntax.Expression as LambdaExpressionSyntax; if (lambdaSyntax == null) { return(false); } return(true); }
private static bool ShouldTrackArgument(IArgumentOperation argumentOperation) { // Ref or Out arguments always contribute data as "assignments" // across method calls if (argumentOperation.Parameter?.IsRefOrOut() == true) { return(true); } // If the argument value is an expression, binary operation, or // invocation then parts of the operation need to be evaluated // to see if they contribute data for value tracking if (argumentOperation.Value is IExpressionStatementOperation or IBinaryOperation or IInvocationOperation) { return(true); } // If the argument value is a parameter reference, then the method calls // leading to that parameter value should be tracked as well. // Ex: // string Prepend(string s1) => "pre" + s1; // string CallPrepend(string [|s2|]) => Prepend(s2); // Tracking [|s2|] into calls as an argument means that we // need to know where [|s2|] comes from and how it contributes // to the value s1 if (argumentOperation.Value is IParameterReferenceOperation) { return(true); } // A literal value as an argument is a dead end for data, but still contributes // to a value and should be shown in value tracking. It should never expand // further though. // Ex: // string Prepend(string [|s|]) => "pre" + s; // string DefaultPrepend() => Prepend("default"); // [|s|] is the parameter we need to track values for, which // is assigned to "default" in DefaultPrepend if (argumentOperation.Value is ILiteralOperation) { return(true); } return(false); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { // Check that StringBuilder is defined in this compilation if (!compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemTextStringBuilder, out INamedTypeSymbol? stringBuilderType)) { return; } IMethodSymbol appendStringMethod = stringBuilderType .GetMembers("Append") .OfType <IMethodSymbol>() .FirstOrDefault(s => s.Parameters.Length == 1 && s.Parameters[0].Type.SpecialType == SpecialType.System_String); if (appendStringMethod is null) { return; } compilationContext.RegisterOperationAction(context => { var invocationOperation = (IInvocationOperation)context.Operation; if (invocationOperation.Arguments.Length < 1) { return; } if (!invocationOperation.TargetMethod.Equals(appendStringMethod)) { return; } ImmutableArray <IArgumentOperation> arguments = invocationOperation.Arguments; IArgumentOperation firstArgument = arguments[0]; if (firstArgument.Value.ConstantValue.HasValue && firstArgument.Value.ConstantValue.Value is string unitString && unitString.Length == 1) { context.ReportDiagnostic(firstArgument.Value.CreateDiagnostic(Rule)); } }, OperationKind.Invocation); }); }
private NullCheckScanResult?AnalyzeDoubleArgumentInvocation([NotNull] IInvocationOperation invocation) { NullCheckMethod?nullCheckMethod = TryGetNullCheckForDoubleArgumentInvocation(invocation); if (nullCheckMethod != null) { IArgumentOperation leftArgument = invocation.Arguments[0]; IArgumentOperation rightArgument = invocation.Arguments[1]; NullCheckOperand nullCheckOperand = GetParentNullCheckOperand(invocation); return(AnalyzeArguments(new ArgumentsInfo(leftArgument.Value, rightArgument.Value, nullCheckMethod.Value, nullCheckOperand))); } return(null); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( (context) => { INamedTypeSymbol?stringComparisonType = context.Compilation.GetOrCreateTypeByMetadataName(StringComparisonTypeName); if (stringComparisonType != null) { context.RegisterOperationAction(operationContext => { var operation = (IInvocationOperation)operationContext.Operation; IMethodSymbol methodSymbol = operation.TargetMethod; if (methodSymbol != null && methodSymbol.ContainingType.SpecialType == SpecialType.System_String && IsEqualsOrCompare(methodSymbol.Name)) { if (!IsAcceptableOverload(methodSymbol, stringComparisonType)) { // wrong overload operationContext.ReportDiagnostic(Diagnostic.Create(Rule, GetMethodNameLocation(operation.Syntax))); } else { IArgumentOperation lastArgument = operation.Arguments.Last(); if (lastArgument.Value.Kind == OperationKind.FieldReference) { IFieldSymbol fieldSymbol = ((IFieldReferenceOperation)lastArgument.Value).Field; if (fieldSymbol != null && fieldSymbol.ContainingType.Equals(stringComparisonType) && !IsOrdinalOrOrdinalIgnoreCase(fieldSymbol.Name)) { // right overload, wrong value operationContext.ReportDiagnostic(lastArgument.Syntax.CreateDiagnostic(Rule)); } } } } }, OperationKind.Invocation); } }); }
protected override void PostProcessArgument(IArgumentOperation operation, bool isEscaped) { base.PostProcessArgument(operation, isEscaped); if (isEscaped) { PostProcessEscapedArgument(); } return; // Local functions. void PostProcessEscapedArgument() { // Discover if a disposable object is being passed into the creation method for this new disposable object // and if the new disposable object assumes ownership of that passed in disposable object. if (IsDisposeOwnershipTransfer()) { var pointsToValue = GetPointsToAbstractValue(operation.Value); HandlePossibleEscapingOperation(operation, pointsToValue.Locations); } } bool IsDisposeOwnershipTransfer() { if (!operation.Parameter.Type.IsDisposable(WellKnownTypeProvider.IDisposable)) { return(false); } switch (operation.Parent) { case IObjectCreationOperation _: return(DisposeOwnershipTransferAtConstructor || DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type)); case IInvocationOperation invocation: return(IsDisposableCreationSpecialCase(invocation.TargetMethod) && DisposeOwnershipTransferLikelyTypes.Contains(operation.Parameter.Type)); default: return(false); } } }
/// <summary> /// Computes abstract value for out or ref arguments when not performing interprocedural analysis. /// </summary> /// <param name="analysisEntity">Analysis entity.</param> /// <param name="operation">IArgumentOperation.</param> /// <param name="defaultValue">Default TaintedDataAbstractValue if we don't need to override.</param> /// <returns>Abstract value of the output parameter.</returns> protected override TaintedDataAbstractValue ComputeAnalysisValueForEscapedRefOrOutArgument( AnalysisEntity analysisEntity, IArgumentOperation operation, TaintedDataAbstractValue defaultValue) { // Note this method is only called when interprocedural DFA is *NOT* performed. if (operation.Parent is IInvocationOperation invocationOperation) { Debug.Assert(!this.TryGetInterproceduralAnalysisResult(invocationOperation, out TaintedDataAnalysisResult _)); // Treat ref or out arguments as the same as the invocation operation. TaintedDataAbstractValue returnValueAbstractValue = this.GetCachedAbstractValue(invocationOperation); return(returnValueAbstractValue); } else { return(defaultValue); } }