private static async Task<Document> RemoveRedundantComparisonAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var comparison = root.FindToken(diagnostic.Location.SourceSpan.Start).Parent.AncestorsAndSelf().OfType<BinaryExpressionSyntax>().First(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken); bool constValue; ExpressionSyntax replacer; var rightConst = semanticModel.GetConstantValue(comparison.Right); if (rightConst.HasValue) { constValue = (bool)rightConst.Value; replacer = comparison.Left; } else { var leftConst = semanticModel.GetConstantValue(comparison.Left); constValue = (bool)leftConst.Value; replacer = comparison.Right; } if ((!constValue && comparison.IsKind(SyntaxKind.EqualsExpression)) || (constValue && comparison.IsKind(SyntaxKind.NotEqualsExpression))) replacer = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, replacer); replacer = replacer.WithAdditionalAnnotations(Formatter.Annotation); var newRoot = root.ReplaceNode(comparison, replacer); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var objectCreateExpression = nodeContext.Node as ObjectCreationExpressionSyntax; ExpressionSyntax paramNode; ExpressionSyntax altParamNode; bool canAddParameterName; if (!CheckExceptionType(nodeContext.SemanticModel, objectCreateExpression, out paramNode, out altParamNode, out canAddParameterName)) return false; var paramName = GetArgumentParameterName(paramNode); if (paramName == null) return false; var validNames = GetValidParameterNames(objectCreateExpression); if (!validNames.Contains(paramName)) { // Case 1: Parameter name is swapped var altParamName = GetArgumentParameterName(altParamNode); if (altParamName != null && validNames.Contains(altParamName)) { diagnostic = Diagnostic.Create(descriptor2, altParamNode.GetLocation()); return true; } //var guessName = GuessParameterName(nodeContext.SemanticModel, objectCreateExpression, validNames); // General case: mark only diagnostic = Diagnostic.Create(descriptor, paramNode.GetLocation(), paramName); return true; } return false; }
private static bool TryGetUnusedLocalVariableDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var method = nodeContext.Node as MethodDeclarationSyntax; if ((method == null) || (method.Body == null)) return false; var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(method.Body); var variablesDeclared = dataFlow.VariablesDeclared; var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside); var unused = variablesDeclared.Except(variablesRead).Except(dataFlow.WrittenInside).ToArray(); if (unused.Any()) { foreach (var unusedVar in unused) { diagnostic = Diagnostic.Create(descriptor, unusedVar.Locations.First()); return true; } } return false; }
private static void AddCodeFix(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, ClassDeclarationSyntax classNode) { var newRoot = IsBusinessObjectSerializableMakeSerializableCodeFix.AddAttribute( root, classNode, IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SerializableName); if (!root.HasUsing(IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SystemNamespace)) { newRoot = (newRoot as CompilationUnitSyntax).AddUsings( SyntaxFactory.UsingDirective(SyntaxFactory.ParseName( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SystemNamespace))); } if (!root.HasUsing(IsBusinessObjectSerializableMakeSerializableCodeFixConstants.CslaSerializationNamespace)) { newRoot = (newRoot as CompilationUnitSyntax).AddUsings( SyntaxFactory.UsingDirective(SyntaxFactory.ParseName( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.CslaSerializationNamespace))); } context.RegisterCodeFix( CodeAction.Create( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.AddSerializableAndUsingDescription, _ => Task.FromResult<Document>(context.Document.WithSyntaxRoot(newRoot))), diagnostic); }
private static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var localDeclarationUnused = nodeContext.Node as LocalDeclarationStatementSyntax; var body = localDeclarationUnused?.Parent as BlockSyntax; if (body == null) return false; var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(body); var variablesDeclared = dataFlow.VariablesDeclared; var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside); var unused = variablesDeclared.Except(variablesRead).ToArray(); if (unused == null) return false; if (localDeclarationUnused.Declaration == null || !localDeclarationUnused.Declaration.Variables.Any()) return false; var localDeclarationSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(localDeclarationUnused.Declaration.Variables.FirstOrDefault()); if (unused.Any()) { if (unused.Contains(localDeclarationSymbol)) { diagnostic = Diagnostic.Create(descriptor, localDeclarationUnused.Declaration.GetLocation()); return true; } } return false; }
private static async Task<InconsistentAccessibilityInfo> GetInconsistentAccessibilityInfoAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { InconsistentAccessibilityInfoProvider inconsistentAccessibilityProvider = null; switch (diagnostic.Id) { case InconsistentAccessibilityInMethodReturnTypeCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInMethodReturnType(); break; case InconsistentAccessibilityInMethodParameterCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInMethodParameter(); break; case InconsistentAccessibilityInFieldTypeCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInFieldType(); break; case InconsistentAccessibilityInPropertyTypeCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInPropertyType(); break; case InconsistentAccessibilityInIndexerReturnTypeCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInIndexerReturnType(); break; case InconsistentAccessibilityInIndexerParameterCompilerErrorNumber: inconsistentAccessibilityProvider = new InconsistentAccessibilityInIndexerParameter(); break; } return await inconsistentAccessibilityProvider.GetInconsistentAccessibilityInfoAsync(document, diagnostic, cancellationToken).ConfigureAwait(false); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var enumMemberDeclaration = (EnumMemberDeclarationSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); var enumDeclaration = (EnumDeclarationSyntax)enumMemberDeclaration.Parent; var memberIndex = enumDeclaration.Members.IndexOf(enumMemberDeclaration); var precedingSeparatorToken = enumDeclaration.Members.GetSeparator(memberIndex - 1); // determine the indentation for enum members (which is parent + 1 step) var parentIndentationSteps = IndentationHelper.GetIndentationSteps(settings.Indentation, enumDeclaration); var indentation = IndentationHelper.GenerateWhitespaceTrivia(settings.Indentation, parentIndentationSteps + 1); // combine all trivia between the separator and the enum member and place them after the separator, followed by a new line. var enumMemberDeclarationFirstToken = enumMemberDeclaration.GetFirstToken(); var sharedTrivia = TriviaHelper.MergeTriviaLists(precedingSeparatorToken.TrailingTrivia, enumMemberDeclarationFirstToken.LeadingTrivia); var newTrailingTrivia = SyntaxFactory.TriviaList(sharedTrivia) .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); // replace the trivia for the tokens var replacements = new Dictionary<SyntaxToken, SyntaxToken> { [precedingSeparatorToken] = precedingSeparatorToken.WithTrailingTrivia(newTrailingTrivia), [enumMemberDeclarationFirstToken] = enumMemberDeclarationFirstToken.WithLeadingTrivia(indentation), }; var newSyntaxRoot = syntaxRoot.ReplaceTokens(replacements.Keys, (original, rewritten) => replacements[original]); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return newDocument; }
private static bool CanBeSuppressedOrUnsuppressed(Diagnostic diagnostic, bool checkCanBeSuppressed) { if (diagnostic.IsSuppressed == checkCanBeSuppressed || IsNotConfigurableDiagnostic(diagnostic)) { // Don't offer suppression fixes for: // 1. Diagnostics with a source suppression. // 2. Non-configurable diagnostics (includes compiler errors). return false; } switch (diagnostic.Severity) { case DiagnosticSeverity.Hidden: // Hidden diagnostics should never show up. return false; case DiagnosticSeverity.Error: case DiagnosticSeverity.Warning: case DiagnosticSeverity.Info: // We allow suppressions for all the remaining configurable, non-hidden diagnostics. // Note that compiler errors are not configurable by default, so only analyzer errors are suppressable. return true; default: throw ExceptionUtilities.Unreachable; } }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); if (nodeContext.IsFromGeneratedCode()) return false; var node = nodeContext.Node as MethodDeclarationSyntax; if (!node.Modifiers.Any(m => m.IsKind(SyntaxKind.OverrideKeyword))) return false; var lastParam = node.ParameterList.Parameters.LastOrDefault(); if (lastParam == null || lastParam.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))) return false; if (lastParam.Type == null || !lastParam.Type.IsKind(SyntaxKind.ArrayType)) return false; var rr = nodeContext.SemanticModel.GetDeclaredSymbol(node); if (rr == null || !rr.IsOverride) return false; var baseMember = rr.OverriddenMethod; if (baseMember == null || baseMember.Parameters.Length == 0 || !baseMember.Parameters.Last().IsParams) return false; diagnostic = Diagnostic.Create( descriptor, lastParam.GetLocation(), baseMember.Name ); return true; }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var node = nodeContext.Node as InvocationExpressionSyntax; MemberAccessExpressionSyntax mre = node.Expression as MemberAccessExpressionSyntax; if (mre == null) return false; if (mre.Name.Identifier.ValueText != "StartsWith") return false; var rr = nodeContext.SemanticModel.GetSymbolInfo(node, nodeContext.CancellationToken); if (rr.Symbol == null) return false; var symbol = rr.Symbol; if (!(symbol.ContainingType != null && symbol.ContainingType.SpecialType == SpecialType.System_String)) return false; var parameters = symbol.GetParameters(); var firstParameter = parameters.FirstOrDefault(); if (firstParameter == null || firstParameter.Type.SpecialType != SpecialType.System_String) return false; // First parameter not a string var lastParameter = parameters.Last(); if (lastParameter.Type.Name == "StringComparison") return false; // already specifying a string comparison diagnostic = Diagnostic.Create( descriptor, node.GetLocation() ); return true; }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); InitializerExpressionSyntax initializer = null; var node = nodeContext.Node as ArrayCreationExpressionSyntax; if (node != null) initializer = node.Initializer; var inode = nodeContext.Node as ImplicitArrayCreationExpressionSyntax; if (inode != null) initializer = inode.Initializer; if (initializer == null) return false; var varInitializer = nodeContext.Node.Parent.Parent; if (varInitializer == null) return false; var variableDeclaration = varInitializer.Parent as VariableDeclarationSyntax; if (variableDeclaration != null) { if (!variableDeclaration.Type.IsKind(SyntaxKind.ArrayType)) return false; diagnostic = Diagnostic.Create( descriptor, Location.Create(nodeContext.SemanticModel.SyntaxTree, TextSpan.FromBounds((node != null ? node.NewKeyword : inode.NewKeyword).Span.Start, initializer.Span.Start)) ); return true; } return false; }
private async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken token) { var syntaxRoot = await document.GetSyntaxRootAsync(token).ConfigureAwait(false); var newDocument = this.CreateCodeFix(document, diagnostic, syntaxRoot); return newDocument; }
private static SyntaxToken GetNewStartToken(SyntaxToken startToken, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) { var trivia = startToken.LeadingTrivia.ToImmutableArray(); // Insert the #pragma disable directive after all leading new line trivia but before first trivia of any other kind. int index; SyntaxTrivia firstNonEOLTrivia = trivia.FirstOrDefault(t => !fixer.IsEndOfLine(t)); if (firstNonEOLTrivia == default(SyntaxTrivia)) { index = trivia.Length; } else { index = trivia.IndexOf(firstNonEOLTrivia); } bool needsLeadingEOL; if (index > 0) { needsLeadingEOL = !fixer.IsEndOfLine(trivia[index - 1]); } else if (startToken.FullSpan.Start == 0) { needsLeadingEOL = false; } else { needsLeadingEOL = true; } var pragmaWarningTrivia = fixer.CreatePragmaDisableDirectiveTrivia(diagnostic, needsLeadingEOL); return startToken.WithLeadingTrivia(trivia.InsertRange(index, pragmaWarningTrivia)); }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var node = nodeContext.Node as LocalDeclarationStatementSyntax; var member = node.AncestorsAndSelf().FirstOrDefault(n => n is MemberDeclarationSyntax); if (member == null) return false; var symbols = nodeContext.SemanticModel.LookupSymbols(member.SpanStart); var memberSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(member); foreach (var variable in node.Declaration.Variables) { var hidingMember = symbols.FirstOrDefault(v => v.Name == variable.Identifier.ValueText && ((memberSymbol.IsStatic && v.IsStatic) || !memberSymbol.IsStatic) && !v.IsKind(SymbolKind.Local) && !v.IsKind(SymbolKind.Parameter)); if (hidingMember == null) continue; var mre = variable.Initializer?.Value as MemberAccessExpressionSyntax; if (mre != null && mre.Name.Identifier.ValueText == hidingMember.Name && mre.Expression.IsKind(SyntaxKind.ThisExpression)) { // Special case: the variable is initialized from the member it is hiding // In this case, the hiding is obviously intentional and we shouldn't show a warning. continue; } string memberType = GetMemberType(hidingMember.Kind); diagnostic = Diagnostic.Create(descriptor, variable.Identifier.GetLocation(), variable.Identifier, memberType, hidingMember.Name); return true; } return false; }
internal string GetMessagePrefix(Diagnostic diagnostic, CultureInfo culture) { string prefix; switch (diagnostic.Severity) { case DiagnosticSeverity.Hidden: prefix = CodeAnalysisResources.ResourceManager.GetString(nameof(CodeAnalysisResources.SeverityHidden), culture); break; case DiagnosticSeverity.Info: prefix = CodeAnalysisResources.ResourceManager.GetString(nameof(CodeAnalysisResources.SeverityInfo), culture); break; case DiagnosticSeverity.Warning: prefix = CodeAnalysisResources.ResourceManager.GetString(nameof(CodeAnalysisResources.SeverityWarning), culture); break; case DiagnosticSeverity.Error: prefix = CodeAnalysisResources.ResourceManager.GetString(nameof(CodeAnalysisResources.SeverityError), culture); break; default: throw ExceptionUtilities.UnexpectedValue(diagnostic.Severity); } return string.Format(culture, "{0} {1}", prefix, diagnostic.Id); }
/// <summary> /// Register the property fix for property documentation. /// </summary> /// <param name="root">the syntax root node.</param> /// <param name="context">the code fix context, containing the location of the fix.</param> /// <param name="diagnostic">the diagnostic, where the invalid code was located.</param> private void RegisterMethodDocumentationCodeFix(SyntaxNode root, CodeFixContext context, Diagnostic diagnostic) { var startNode = root.FindNode(diagnostic.Location.SourceSpan); var constructorDeclaration = startNode as ConstructorDeclarationSyntax; if (constructorDeclaration != null) this.RegisterConstructorCodeFix(constructorDeclaration, root, context, diagnostic); }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var options = nodeContext.SemanticModel.SyntaxTree.Options as VisualBasicParseOptions; if (options != null && options.LanguageVersion < LanguageVersion.VisualBasic14) return false; var objectCreateExpression = nodeContext.Node as ObjectCreationExpressionSyntax; ExpressionSyntax paramNode; if (!CheckExceptionType(nodeContext.SemanticModel, objectCreateExpression, out paramNode)) return false; var paramName = GetArgumentParameterName(paramNode); if (paramName == null) return false; var validNames = GetValidParameterNames(objectCreateExpression); if (!validNames.Contains(paramName)) return false; diagnostic = Diagnostic.Create(descriptor, paramNode.GetLocation(), paramName); return true; }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var node = nodeContext.Node as BinaryExpressionSyntax; var flowAnalzyer = new FlowAnalyzer<NullFlowState>(nodeContext.SemanticModel, new NullFlowState(nodeContext.SemanticModel)); var analyzer = flowAnalzyer.Analyze(nodeContext.Node); var state = analyzer.GetFlowState(node.Left); var leftState = state.GetReferenceState(node.Left); if (leftState == NullState.NotNull) { diagnostic = Diagnostic.Create (descriptor, node.Right.GetLocation (), "Remove redundant right side"); return true; } if (leftState == NullState.Null) { diagnostic = Diagnostic.Create (descriptor, node.Left.GetLocation (), "Remove redundant left side"); return true; } if (state.GetReferenceState(node.Right) == NullState.Null) { diagnostic = Diagnostic.Create (descriptor, node.Right.GetLocation (), "Remove redundant left side"); } return false; }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxToken token = root.FindToken(diagnostic.Location.SourceSpan.Start); if (!token.IsKind(SyntaxKind.CloseBracketToken)) { return document; } if (token.IsFirstInLine()) { return document; } SyntaxToken precedingToken = token.GetPreviousToken(); if (!precedingToken.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia)) { return document; } SyntaxToken corrected = precedingToken.WithoutTrailingWhitespace().WithoutFormatting(); SyntaxNode transformed = root.ReplaceToken(precedingToken, corrected); Document updatedDocument = document.WithSyntaxRoot(transformed); return updatedDocument; }
private static void AddCodeFixWithNewPublicConstructor(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, ClassDeclarationSyntax classNode) { // Generated from http://roslynquoter.azurewebsites.net/ var constructor = SyntaxFactory.ConstructorDeclaration(classNode.Identifier) .WithModifiers( SyntaxFactory.TokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword))) .WithParameterList(SyntaxFactory.ParameterList() .WithOpenParenToken( SyntaxFactory.Token(SyntaxKind.OpenParenToken)) .WithCloseParenToken( SyntaxFactory.Token( SyntaxKind.CloseParenToken))) .WithBody(SyntaxFactory.Block() .WithOpenBraceToken( SyntaxFactory.Token( SyntaxKind.OpenBraceToken)) .WithCloseBraceToken( SyntaxFactory.Token( SyntaxKind.CloseBraceToken))).NormalizeWhitespace().WithAdditionalAnnotations(Formatter.Annotation); var newClassNode = classNode.AddMembers(constructor); var newRoot = root.ReplaceNode(classNode, newClassNode); context.RegisterCodeFix( CodeAction.Create( CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription, _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription), diagnostic); }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var node = nodeContext.Node as AssignmentExpressionSyntax; if (node.IsKind(SyntaxKind.OrAssignmentExpression)) { LiteralExpressionSyntax right = node.Right as LiteralExpressionSyntax; //if right is true if ((right != null) && right.IsKind(SyntaxKind.TrueLiteralExpression)) { diagnostic = Diagnostic.Create( descriptor, node.GetLocation() ); return true; } } else if (node.IsKind(SyntaxKind.AndAssignmentExpression)) { LiteralExpressionSyntax right = node.Right as LiteralExpressionSyntax; //if right is false if ((right != null) && right.IsKind(SyntaxKind.FalseLiteralExpression)) { diagnostic = Diagnostic.Create( descriptor, node.GetLocation() ); return true; } } return false; }
private Image GetSeverityIconForDiagnostic(Diagnostic diagnostic) { ImageMoniker? moniker = null; switch (diagnostic.Severity) { case DiagnosticSeverity.Error: moniker = KnownMonikers.StatusError; break; case DiagnosticSeverity.Warning: moniker = KnownMonikers.StatusWarning; break; case DiagnosticSeverity.Info: moniker = KnownMonikers.StatusInformation; break; case DiagnosticSeverity.Hidden: moniker = KnownMonikers.StatusHidden; break; } if (moniker.HasValue) { return new CrispImage { Moniker = moniker.Value }; } return null; }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken token) { var sourceText = await document.GetTextAsync(token).ConfigureAwait(false); var startIndex = sourceText.Lines.IndexOf(diagnostic.Location.SourceSpan.Start); int endIndex = startIndex; for (var i = startIndex + 1; i < sourceText.Lines.Count; i++) { if (!string.IsNullOrWhiteSpace(sourceText.Lines[i].ToString())) { endIndex = i - 1; break; } } if (endIndex >= (startIndex + 1)) { var replaceSpan = TextSpan.FromBounds(sourceText.Lines[startIndex + 1].SpanIncludingLineBreak.Start, sourceText.Lines[endIndex].SpanIncludingLineBreak.End); var newSourceText = sourceText.Replace(replaceSpan, string.Empty); return document.WithText(newSourceText); } return document; }
private static async Task<Document> RemoveTrailingWhiteSpaceAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var trivia = root.FindTrivia(diagnostic.Location.SourceSpan.End - 1); SyntaxNode newRoot; if (trivia.IsKind(SyntaxKind.WhitespaceTrivia)) { newRoot = root.ReplaceTrivia(trivia, new SyntaxTrivia[] { }); } else if (trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia, SyntaxKind.MultiLineDocumentationCommentTrivia)) { var commentText = trivia.ToFullString(); var commentLines = commentText.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var newComment = ""; var builder = new System.Text.StringBuilder(); builder.Append(newComment); for (int i = 0; i < commentLines.Length; i++) { var commentLine = commentLines[i]; builder.Append(Regex.Replace(commentLine, @"\s+$", "")); if (i < commentLines.Length - 1) builder.Append(Environment.NewLine); } newComment = builder.ToString(); newRoot = root.ReplaceTrivia(trivia, SyntaxFactory.SyntaxTrivia(SyntaxKind.DocumentationCommentExteriorTrivia, newComment)); } else { var triviaNoTrailingWhiteSpace = Regex.Replace(trivia.ToFullString(), @"\s+$", ""); newRoot = root.ReplaceTrivia(trivia, SyntaxFactory.ParseTrailingTrivia(triviaNoTrailingWhiteSpace)); } return document.WithSyntaxRoot(newRoot); }
internal void LogDiagnostic(Diagnostic diagnostic, CultureInfo culture) { _writer.WriteObjectStart(); // result _writer.Write("ruleId", diagnostic.Id); _writer.Write("kind", GetKind(diagnostic.Severity)); WriteLocations(diagnostic.Location, diagnostic.AdditionalLocations); string message = diagnostic.GetMessage(culture); if (string.IsNullOrEmpty(message)) { message = "<None>"; } string description = diagnostic.Descriptor.Description.ToString(culture); if (string.IsNullOrEmpty(description)) { _writer.Write("fullMessage", message); } else { _writer.Write("shortMessage", message); _writer.Write("fullMessage", description); } _writer.Write("isSuppressedInSource", diagnostic.IsSuppressed); WriteTags(diagnostic); WriteProperties(diagnostic, culture); _writer.WriteObjectEnd(); // result }
private void AddEdits( SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) { var localDeclarationLocation = diagnostic.AdditionalLocations[0]; var ifStatementLocation = diagnostic.AdditionalLocations[1]; var conditionLocation = diagnostic.AdditionalLocations[2]; var asExpressionLocation = diagnostic.AdditionalLocations[3]; var localDeclaration = (LocalDeclarationStatementSyntax)localDeclarationLocation.FindNode(cancellationToken); var ifStatement = (IfStatementSyntax)ifStatementLocation.FindNode(cancellationToken); var condition = (BinaryExpressionSyntax)conditionLocation.FindNode(cancellationToken); var asExpression = (BinaryExpressionSyntax)asExpressionLocation.FindNode(cancellationToken); var updatedCondition = SyntaxFactory.IsPatternExpression( asExpression.Left, SyntaxFactory.DeclarationPattern( ((TypeSyntax)asExpression.Right).WithoutTrivia(), localDeclaration.Declaration.Variables[0].Identifier.WithoutTrivia())); var trivia = localDeclaration.GetLeadingTrivia().Concat(localDeclaration.GetTrailingTrivia()) .Where(t => t.IsSingleOrMultiLineComment()) .SelectMany(t => ImmutableArray.Create(t, SyntaxFactory.ElasticCarriageReturnLineFeed)) .ToImmutableArray(); var updatedIfStatement = ifStatement.ReplaceNode(condition, updatedCondition) .WithPrependedLeadingTrivia(trivia) .WithAdditionalAnnotations(Formatter.Annotation); editor.RemoveNode(localDeclaration); editor.ReplaceNode(ifStatement, updatedIfStatement); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var whereToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); var precedingToken = whereToken.GetPreviousToken(); var endToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.End); var afterEndToken = endToken.GetNextToken(); var parentIndentation = GetParentIndentation(whereToken); var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var indentationTrivia = SyntaxFactory.Whitespace(parentIndentation + IndentationHelper.GenerateIndentationString(settings.Indentation, 1)); var replaceMap = new Dictionary<SyntaxToken, SyntaxToken>() { [precedingToken] = precedingToken.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed), [whereToken] = whereToken.WithLeadingTrivia(indentationTrivia), [endToken] = endToken.WithTrailingTrivia(RemoveUnnecessaryWhitespaceTrivia(endToken).Add(SyntaxFactory.CarriageReturnLineFeed)), }; if (afterEndToken.IsKind(SyntaxKind.EqualsGreaterThanToken)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(indentationTrivia)); } else if (afterEndToken.IsKind(SyntaxKind.OpenBraceToken)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(SyntaxFactory.Whitespace(parentIndentation))); } else if (afterEndToken.IsKind(SyntaxKind.WhereKeyword)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(indentationTrivia)); } var newSyntaxRoot = syntaxRoot.ReplaceTokens(replaceMap.Keys, (t1, t2) => replaceMap[t1]).WithoutFormatting(); return document.WithSyntaxRoot(newSyntaxRoot); }
private Document CreateCodeFix(Document document, Diagnostic diagnostic, SyntaxNode syntaxRoot) { SyntaxNode newSyntaxRoot = syntaxRoot; var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan); var indentationOptions = IndentationOptions.FromDocument(document); switch (node.Kind()) { case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.EnumDeclaration: newSyntaxRoot = this.RegisterBaseTypeDeclarationCodeFix(syntaxRoot, (BaseTypeDeclarationSyntax)node, indentationOptions); break; case SyntaxKind.AccessorList: newSyntaxRoot = this.RegisterPropertyLikeDeclarationCodeFix(syntaxRoot, (BasePropertyDeclarationSyntax)node.Parent, indentationOptions); break; case SyntaxKind.Block: newSyntaxRoot = this.RegisterMethodLikeDeclarationCodeFix(syntaxRoot, (BaseMethodDeclarationSyntax)node.Parent, indentationOptions); break; case SyntaxKind.NamespaceDeclaration: newSyntaxRoot = this.RegisterNamespaceDeclarationCodeFix(syntaxRoot, (NamespaceDeclarationSyntax)node, indentationOptions); break; } return document.WithSyntaxRoot(newSyntaxRoot); }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); var anyInvoke = nodeContext.Node as InvocationExpressionSyntax; var info = nodeContext.SemanticModel.GetSymbolInfo(anyInvoke); IMethodSymbol anyResolve = info.Symbol as IMethodSymbol; if (anyResolve == null) { anyResolve = info.CandidateSymbols.OfType<IMethodSymbol>().FirstOrDefault(candidate => HasPredicateVersion(candidate)); } if (anyResolve == null || !HasPredicateVersion(anyResolve)) return false; ExpressionSyntax target, followUp; TypeSyntax type; ParameterSyntax param; if (ReplaceWithOfTypeAnyAnalyzer.MatchSelect(anyInvoke, out target, out type, out param, out followUp)) { // if (member == "Where" && followUp == null) return; diagnostic = Diagnostic.Create( descriptor, anyInvoke.GetLocation() ); return true; } return false; }
static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic) { diagnostic = default(Diagnostic); if (nodeContext.IsFromGeneratedCode()) return false; var node = nodeContext.Node as ConditionalExpressionSyntax; bool? trueBranch = SimplifyConditionalTernaryExpressionCodeFixProvider.GetBool(node.WhenTrue.SkipParens()); bool? falseBranch = SimplifyConditionalTernaryExpressionCodeFixProvider.GetBool(node.WhenFalse.SkipParens()); if (trueBranch == falseBranch || trueBranch == true && falseBranch == false) // Handled by RedundantTernaryExpressionIssue return false; var typeTrue = nodeContext.SemanticModel.GetTypeInfo(node.WhenTrue); var typeFalse = nodeContext.SemanticModel.GetTypeInfo(node.WhenFalse); if (typeTrue.Type == null || typeTrue.Type.SpecialType != SpecialType.System_Boolean || typeFalse.Type == null || typeFalse.Type.SpecialType != SpecialType.System_Boolean) return false; diagnostic = Diagnostic.Create( descriptor, node.GetLocation() ); return true; }
private static SyntaxToken GetNewTokenWithPragmaUnsuppress(SyntaxToken token, int indexOfTriviaToRemoveOrToggle, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer, bool isStartToken, bool toggle) { Contract.ThrowIfFalse(indexOfTriviaToRemoveOrToggle >= 0); var triviaList = GetTriviaListForSuppression(token, isStartToken, fixer); if (toggle) { var triviaToToggle = triviaList.ElementAt(indexOfTriviaToRemoveOrToggle); Contract.ThrowIfFalse(triviaToToggle != default); var toggledTrivia = fixer.TogglePragmaDirective(triviaToToggle); triviaList = triviaList.Replace(triviaToToggle, toggledTrivia); } else { triviaList = triviaList.RemoveAt(indexOfTriviaToRemoveOrToggle); } return(UpdateTriviaList(token, isStartToken, triviaList, fixer)); }
/// <summary> /// Returns an existing, or gets a new connection using the details in the specified /// <paramref name="connectToPeerResponse"/> and pierces the remote peer's firewall. /// </summary> /// <remarks> /// This method will be invoked from <see cref="Messaging.Handlers.ServerMessageHandler"/> upon receipt of an /// unsolicited <see cref="ConnectToPeerResponse"/> of type 'P' only. This connection should only be initiated if /// there is no existing connection; superseding should be avoided if possible. /// </remarks> /// <param name="connectToPeerResponse">The response that solicited the connection.</param> /// <returns>The operation context, including the new or updated connection.</returns> public async Task <IMessageConnection> GetOrAddMessageConnectionAsync(ConnectToPeerResponse connectToPeerResponse) { bool cached = true; var r = connectToPeerResponse; try { var connection = await MessageConnectionDictionary.GetOrAdd( r.Username, key => new Lazy <Task <IMessageConnection> >(() => GetConnection())).Value.ConfigureAwait(false); if (cached) { Diagnostic.Debug($"Retrieved cached message connection to {r.Username} ({r.IPEndPoint}) (type: {connection.Type}, id: {connection.Id})"); } return(connection); } catch (Exception ex) { var msg = $"Failed to establish an inbound indirect message connection to {r.Username} ({r.IPEndPoint}): {ex.Message}"; Diagnostic.Debug(msg); Diagnostic.Debug($"Purging message connection cache of failed connection to {r.Username} ({r.IPEndPoint})."); MessageConnectionDictionary.TryRemove(r.Username, out _); throw new ConnectionException(msg, ex); } async Task <IMessageConnection> GetConnection() { cached = false; Diagnostic.Debug($"Attempting inbound indirect message connection to {r.Username} ({r.IPEndPoint}) for token {r.Token}"); var connection = ConnectionFactory.GetMessageConnection( r.Username, r.IPEndPoint, SoulseekClient.Options.PeerConnectionOptions); connection.Type = ConnectionTypes.Inbound | ConnectionTypes.Indirect; connection.MessageRead += SoulseekClient.PeerMessageHandler.HandleMessageRead; connection.MessageReceived += SoulseekClient.PeerMessageHandler.HandleMessageReceived; connection.MessageWritten += SoulseekClient.PeerMessageHandler.HandleMessageWritten; connection.Disconnected += MessageConnection_Disconnected; using (var cts = new CancellationTokenSource()) { // add a record to the pending dictionary so we can tell whether the following code is waiting PendingInboundIndirectConnectionDictionary.AddOrUpdate(r.Username, cts, (username, existingCts) => cts); try { await connection.ConnectAsync(cts.Token).ConfigureAwait(false); var request = new PierceFirewall(r.Token); await connection.WriteAsync(request.ToByteArray(), cts.Token).ConfigureAwait(false); } catch { connection.Dispose(); throw; } finally { // let everyone know this code is done executing and that .Value of the containing cache is safe to await with no delay. PendingInboundIndirectConnectionDictionary.TryRemove(r.Username, out _); } } Diagnostic.Debug($"Message connection to {r.Username} ({r.IPEndPoint}) established. (type: {connection.Type}, id: {connection.Id})"); return(connection); } }
public override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction(compilationContext => { AdditionalText publicApiAdditionalText = TryGetPublicApiSpec(compilationContext.Options.AdditionalFiles, compilationContext.CancellationToken); if (publicApiAdditionalText == null) { return; } SourceText publicApiSourceText = publicApiAdditionalText.GetText(compilationContext.CancellationToken); HashSet <string> declaredPublicSymbols = ReadPublicSymbols(publicApiSourceText, compilationContext.CancellationToken); HashSet <string> examinedPublicTypes = new HashSet <string>(); object lockObj = new object(); Dictionary <ITypeSymbol, bool> typeCanBeExtendedPubliclyMap = new Dictionary <ITypeSymbol, bool>(); Func <ITypeSymbol, bool> typeCanBeExtendedPublicly = type => { bool result; if (typeCanBeExtendedPubliclyMap.TryGetValue(type, out result)) { return(result); } // a type can be extended publicly if (1) it isn't sealed, and (2) it has some constructor that is // not internal, private or protected&internal result = !type.IsSealed && type.GetMembers(WellKnownMemberNames.InstanceConstructorName).Any( m => m.DeclaredAccessibility != Accessibility.Internal && m.DeclaredAccessibility != Accessibility.Private && m.DeclaredAccessibility != Accessibility.ProtectedAndInternal ); typeCanBeExtendedPubliclyMap.Add(type, result); return(result); }; compilationContext.RegisterSymbolAction(symbolContext => { var symbol = symbolContext.Symbol; var methodSymbol = symbol as IMethodSymbol; if (methodSymbol != null && s_ignorableMethodKinds.Contains(methodSymbol.MethodKind)) { return; } lock (lockObj) { if (!IsPublicApi(symbol, typeCanBeExtendedPublicly)) { return; } string publicApiName = GetPublicApiName(symbol); examinedPublicTypes.Add(publicApiName); if (!declaredPublicSymbols.Contains(publicApiName)) { var errorMessageName = symbol.ToDisplayString(ShortSymbolNameFormat); var propertyBag = ImmutableDictionary <string, string> .Empty .Add(PublicApiNamePropertyBagKey, publicApiName) .Add(MinimalNamePropertyBagKey, errorMessageName); foreach (var sourceLocation in symbol.Locations.Where(loc => loc.IsInSource)) { symbolContext.ReportDiagnostic(Diagnostic.Create(DeclareNewApiRule, sourceLocation, propertyBag, errorMessageName)); } } // Check if a public API is a constructor that makes this class instantiable, even though the base class // is not instantiable. That API pattern is not allowed, because it causes protected members of // the base class, which are not considered public APIs, to be exposed to subclasses of this class. if ((symbol as IMethodSymbol)?.MethodKind == MethodKind.Constructor && symbol.ContainingType.TypeKind == TypeKind.Class && !symbol.ContainingType.IsSealed && symbol.ContainingType.BaseType != null && IsPublicApi(symbol.ContainingType.BaseType, typeCanBeExtendedPublicly) && !typeCanBeExtendedPublicly(symbol.ContainingType.BaseType)) { var errorMessageName = symbol.ToDisplayString(ShortSymbolNameFormat); var propertyBag = ImmutableDictionary <string, string> .Empty; symbolContext.ReportDiagnostic(Diagnostic.Create(ExposedNoninstantiableType, symbol.Locations[0], propertyBag, errorMessageName)); } } }, SymbolKind.NamedType, SymbolKind.Event, SymbolKind.Field, SymbolKind.Method); compilationContext.RegisterCompilationEndAction(compilationEndContext => { ImmutableArray <string> deletedSymbols; lock (lockObj) { deletedSymbols = declaredPublicSymbols.Where(symbol => !examinedPublicTypes.Contains(symbol)).ToImmutableArray(); } foreach (var symbol in deletedSymbols) { var span = FindString(publicApiSourceText, symbol); Location location; if (span.HasValue) { var linePositionSpan = publicApiSourceText.Lines.GetLinePositionSpan(span.Value); location = Location.Create(publicApiAdditionalText.Path, span.Value, linePositionSpan); } else { location = Location.Create(publicApiAdditionalText.Path, default(TextSpan), default(LinePositionSpan)); } var propertyBag = ImmutableDictionary <string, string> .Empty.Add(PublicApiNamePropertyBagKey, symbol); compilationEndContext.ReportDiagnostic(Diagnostic.Create(RemoveDeletedApiRule, location, propertyBag, symbol)); } }); }); }
private static string GetSquiggledText(Diagnostic diagnostic) { return(diagnostic.Location.SourceTree.GetText().ToString(diagnostic.Location.SourceSpan)); }
/// <summary> /// Gets a new or existing message connection to the specified <paramref name="username"/>. /// </summary> /// <remarks> /// If a connection doesn't exist, new direct and indirect connections are attempted simultaneously, and the first to /// connect is returned. /// </remarks> /// <param name="username">The username of the user to which to connect.</param> /// <param name="ipEndPoint">The remote IP endpoint of the connection.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The operation context, including the new or existing connection.</returns> public async Task <IMessageConnection> GetOrAddMessageConnectionAsync(string username, IPEndPoint ipEndPoint, CancellationToken cancellationToken) { bool cached = true; try { var connection = await MessageConnectionDictionary.GetOrAdd( username, key => new Lazy <Task <IMessageConnection> >(() => GetConnection())).Value.ConfigureAwait(false); if (cached) { Diagnostic.Debug($"Retrieved cached message connection to {username} ({ipEndPoint}) (type: {connection.Type}, id: {connection.Id})"); } return(connection); } catch { Diagnostic.Debug($"Purging message connection cache of failed connection to {username} ({ipEndPoint})."); MessageConnectionDictionary.TryRemove(username, out _); throw; } async Task <IMessageConnection> GetConnection() { cached = false; using var directCts = new CancellationTokenSource(); using var directLinkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, directCts.Token); using var indirectCts = new CancellationTokenSource(); using var indirectLinkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, indirectCts.Token); Diagnostic.Debug($"Attempting simultaneous direct and indirect message connections to {username} ({ipEndPoint})"); var direct = GetMessageConnectionOutboundDirectAsync(username, ipEndPoint, directLinkedCts.Token); var indirect = GetMessageConnectionOutboundIndirectAsync(username, indirectLinkedCts.Token); var tasks = new[] { direct, indirect }.ToList(); Task <IMessageConnection> task; do { task = await Task.WhenAny(tasks).ConfigureAwait(false); tasks.Remove(task); }while (task.Status != TaskStatus.RanToCompletion && tasks.Count > 0); if (task.Status != TaskStatus.RanToCompletion) { var msg = $"Failed to establish a direct or indirect message connection to {username} ({ipEndPoint})"; Diagnostic.Debug(msg); throw new ConnectionException(msg); } var connection = await task.ConfigureAwait(false); connection.Disconnected += MessageConnection_Disconnected; var isDirect = task == direct; Diagnostic.Debug($"{(isDirect ? "Direct" : "Indirect")} message connection to {username} ({ipEndPoint}) established first, attempting to cancel {(isDirect ? "indirect" : "direct")} connection."); (isDirect ? indirectCts : directCts).Cancel(); try { if (isDirect) { var request = new PeerInit(SoulseekClient.Username, Constants.ConnectionType.Peer, SoulseekClient.GetNextToken()); await connection.WriteAsync(request.ToByteArray(), cancellationToken).ConfigureAwait(false); } else { connection.StartReadingContinuously(); } } catch (Exception ex) { var msg = $"Failed to negotiate message connection to {username} ({ipEndPoint}): {ex.Message}"; Diagnostic.Debug($"{msg} (type: {connection.Type}, id: {connection.Id})"); connection.Dispose(); throw new ConnectionException(msg, ex); } Diagnostic.Debug($"Message connection to {username} ({ipEndPoint}) established. (type: {connection.Type}, id: {connection.Id})"); return(connection); } }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( new HazardousUsageEvaluator("GetBytes", HazardousUsageCallback)); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, out var rfc2898DeriveBytesTypeSymbol)) { return; } var cancellationToken = compilationStartAnalysisContext.CancellationToken; var sufficientIterationCount = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue( optionName: EditorConfigOptionNames.SufficientIterationCountForWeakKDFAlgorithm, rule: DefinitelyUseWeakKDFInsufficientIterationCountRule, defaultValue: 100000, cancellationToken: cancellationToken); var constructorMapper = new ConstructorMapper( (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) => { var kind = DefaultIterationCount >= sufficientIterationCount ? PropertySetAbstractValueKind.Unflagged : PropertySetAbstractValueKind.Flagged; if (constructorMethod.Parameters.Length >= 3) { if (constructorMethod.Parameters[2].Name == "iterations" && constructorMethod.Parameters[2].Type.SpecialType == SpecialType.System_Int32) { kind = PropertySetCallbacks.EvaluateLiteralValues(argumentValueContentAbstractValues[2], o => Convert.ToInt32(o) < sufficientIterationCount); } } return(PropertySetAbstractValue.GetInstance(kind)); }); var propertyMappers = new PropertyMapperCollection( new PropertyMapper( "IterationCount", (ValueContentAbstractValue valueContentAbstractValue) => { return(PropertySetCallbacks.EvaluateLiteralValues(valueContentAbstractValue, o => Convert.ToInt32(o) < sufficientIterationCount)); })); var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (rfc2898DeriveBytesTypeSymbol.Equals(invocationOperation.Instance?.Type) && invocationOperation.TargetMethod.Name == "GetBytes") { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation; if (rfc2898DeriveBytesTypeSymbol.Equals(argumentOperation.Parameter.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Argument); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, constructorMapper, propertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: cancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { DiagnosticDescriptor descriptor; switch (kvp.Value) { case HazardousUsageEvaluationResult.Flagged: descriptor = DefinitelyUseWeakKDFInsufficientIterationCountRule; break; case HazardousUsageEvaluationResult.MaybeFlagged: descriptor = MaybeUseWeakKDFInsufficientIterationCountRule; break; default: Debug.Fail($"Unhandled result value {kvp.Value}"); continue; } compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, sufficientIterationCount)); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }
/// <summary> /// Adds a new message connection from an incoming connection. /// </summary> /// <remarks> /// This method will be invoked from <see cref="ListenerHandler"/> upon receipt of an incoming unsolicited message /// only. Because this connection is fully established by the time it is passed to this method, it must supersede any /// cached connection, as it will be the most recently established connection as tracked by the remote user. /// </remarks> /// <param name="username">The username of the user from which the connection originated.</param> /// <param name="incomingConnection">The the accepted connection.</param> /// <returns>The operation context.</returns> public async Task AddMessageConnectionAsync(string username, IConnection incomingConnection) { var c = incomingConnection; try { await MessageConnectionDictionary.AddOrUpdate( username, new Lazy <Task <IMessageConnection> >(() => GetConnection()), (key, cachedConnectionRecord) => new Lazy <Task <IMessageConnection> >(() => GetConnection(cachedConnectionRecord))).Value.ConfigureAwait(false); } catch (Exception ex) { var msg = $"Failed to establish an inbound message connection to {username} ({c.IPEndPoint}): {ex.Message}"; Diagnostic.Debug($"{msg} (type: {c.Type}, id: {c.Id})"); Diagnostic.Debug($"Purging message connection cache of failed connection to {username} ({c.IPEndPoint})."); MessageConnectionDictionary.TryRemove(username, out _); throw new ConnectionException(msg, ex); } async Task <IMessageConnection> GetConnection(Lazy <Task <IMessageConnection> > cachedConnectionRecord = null) { Diagnostic.Debug($"Inbound message connection to {username} ({c.IPEndPoint}) accepted. (type: {c.Type}, id: {c.Id})"); var connection = ConnectionFactory.GetMessageConnection( username, c.IPEndPoint, SoulseekClient.Options.PeerConnectionOptions, c.HandoffTcpClient()); connection.Type = ConnectionTypes.Inbound | ConnectionTypes.Direct; connection.MessageRead += SoulseekClient.PeerMessageHandler.HandleMessageRead; connection.MessageWritten += SoulseekClient.PeerMessageHandler.HandleMessageWritten; connection.Disconnected += MessageConnection_Disconnected; Diagnostic.Debug($"Inbound message connection to {username} ({connection.IPEndPoint}) handed off. (old: {c.Id}, new: {connection.Id})"); if (cachedConnectionRecord != null) { // because the cache is Lazy<>, the cached entry may be either a connected or pending connection. // if we try to reference .Value before the cached function is dispositioned we'll get stuck waiting for it, // which will prevent this code from superseding the connection until the pending connection times out. // to get around this the pending connection dictionary was added, allowing us to tell if the connection is still pending. // if so, we can just cancel the token and move on. if (PendingInboundIndirectConnectionDictionary.TryGetValue(username, out var pendingCts)) { Diagnostic.Debug($"Cancelling pending inbound indirect message connection to {username}"); pendingCts.Cancel(); } else { // if there's no entry in the pending connection dictionary, the Lazy<> function has completed executing and we know that // awaiting .Value will return immediately, allowing us to tear down the disconnected event handler. try { var cachedConnection = await cachedConnectionRecord.Value.ConfigureAwait(false); cachedConnection.Disconnected -= MessageConnection_Disconnected; Diagnostic.Debug($"Superseding cached message connection to {username} ({cachedConnection.IPEndPoint}) (old: {cachedConnection.Id}, new: {connection.Id}"); } catch { // noop } } } connection.StartReadingContinuously(); Diagnostic.Debug($"Message connection to {username} ({connection.IPEndPoint}) established. (type: {connection.Type}, id: {connection.Id})"); return(connection); } }