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;
        }
示例#8
0
        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;
        }
示例#15
0
        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;
        }
示例#22
0
        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);
 }
示例#25
0
        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);
            }
        }
示例#33
0
        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));
                    }
                });
            });
        }
示例#34
0
 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);
            }
        }
示例#36
0
        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);
            }
        }