Esempio n. 1
0
        internal static async Task <long> GetLinesOfCodeAsync(ImmutableArray <SyntaxReference> declarations, ISymbol symbol, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
        {
            long linesOfCode = 0;

            foreach (var decl in declarations)
            {
                SyntaxNode declSyntax = await GetTopmostSyntaxNodeForDeclarationAsync(decl, symbol, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                // For namespace symbols, don't count lines of code for declarations of child namespaces.
                // For example, "namespace N1.N2 { }" is a declaration reference for N1, but the actual declaration is for N2.
                if (symbol.Kind == SymbolKind.Namespace)
                {
                    var model = semanticModelProvider.GetSemanticModel(declSyntax);
                    if (model.GetDeclaredSymbol(declSyntax, cancellationToken) != (object)symbol)
                    {
                        continue;
                    }
                }

                FileLinePositionSpan linePosition = declSyntax.SyntaxTree.GetLineSpan(declSyntax.FullSpan, cancellationToken);
                long delta = linePosition.EndLinePosition.Line - linePosition.StartLinePosition.Line;
                if (delta == 0)
                {
                    // Declaration on a single line, we count it as a separate line.
                    delta = 1;
                }

                linesOfCode += delta;
            }

            return(linesOfCode);
        }
Esempio n. 2
0
        internal static async Task <SyntaxNode> GetTopmostSyntaxNodeForDeclarationAsync(SyntaxReference declaration, ISymbol declaredSymbol, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
        {
            var declSyntax = await declaration.GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

            if (declSyntax.Language == LanguageNames.VisualBasic)
            {
                SemanticModel model = semanticModelProvider.GetSemanticModel(declSyntax);
                while (declSyntax.Parent != null && Equals(model.GetDeclaredSymbol(declSyntax.Parent, cancellationToken), declaredSymbol))
                {
                    declSyntax = declSyntax.Parent;
                }
            }

            return(declSyntax);
        }
Esempio n. 3
0
        internal static async Task <(int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics)> ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(
            ImmutableArray <SyntaxReference> declarations,
            ISymbol symbol,
            ImmutableHashSet <INamedTypeSymbol> .Builder builder,
            SemanticModelProvider semanticModelProvider,
            CancellationToken cancellationToken)
        {
            int cyclomaticComplexity = 0;
            ComputationalComplexityMetrics computationalComplexityMetrics = ComputationalComplexityMetrics.Default;

            var nodesToProcess = new Queue <SyntaxNode>();

            foreach (var declaration in declarations)
            {
                SyntaxNode syntax = await GetTopmostSyntaxNodeForDeclarationAsync(declaration, symbol, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                nodesToProcess.Enqueue(syntax);

                // Ensure we process parameter initializers and attributes.
                var parameters = GetParameters(symbol);
                foreach (var parameter in parameters)
                {
                    var parameterSyntaxRef = parameter.DeclaringSyntaxReferences.FirstOrDefault();
                    if (parameterSyntaxRef != null)
                    {
                        var parameterSyntax = await parameterSyntaxRef.GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

                        nodesToProcess.Enqueue(parameterSyntax);
                    }
                }

                var attributes = symbol.GetAttributes();
                if (symbol is IMethodSymbol methodSymbol)
                {
                    attributes = attributes.AddRange(methodSymbol.GetReturnTypeAttributes());
                }

                foreach (var attribute in attributes)
                {
                    if (attribute.ApplicationSyntaxReference != null)
                    {
                        var attributeSyntax = await attribute.ApplicationSyntaxReference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

                        nodesToProcess.Enqueue(attributeSyntax);
                    }
                }

                do
                {
                    var node  = nodesToProcess.Dequeue();
                    var model = semanticModelProvider.GetSemanticModel(node);

                    if (!ReferenceEquals(node, syntax))
                    {
                        var declaredSymbol = model.GetDeclaredSymbol(node, cancellationToken);
                        if (declaredSymbol != null && !Equals(symbol, declaredSymbol) && declaredSymbol.Kind != SymbolKind.Parameter)
                        {
                            // Skip member declarations.
                            continue;
                        }
                    }

                    var typeInfo = model.GetTypeInfo(node, cancellationToken);
                    AddCoupledNamedTypesCore(builder, typeInfo.Type);

                    var operationBlock = model.GetOperation(node, cancellationToken);
                    if (operationBlock != null && operationBlock.Parent == null)
                    {
                        switch (operationBlock.Kind)
                        {
                        case OperationKind.Block:
                        case OperationKind.MethodBodyOperation:
                        case OperationKind.ConstructorBodyOperation:
                            cyclomaticComplexity += 1;
                            break;
                        }

                        computationalComplexityMetrics = computationalComplexityMetrics.Union(ComputationalComplexityMetrics.Compute(operationBlock));

                        // Add used types within executable code in the operation tree.
                        foreach (var operation in operationBlock.DescendantsAndSelf())
                        {
#if LEGACY_CODE_METRICS_MODE
                            // Legacy mode does not account for code within lambdas/local functions for code metrics.
                            if (operation.IsWithinLambdaOrLocalFunction())
                            {
                                continue;
                            }
#endif

                            if (!operation.IsImplicit && hasConditionalLogic(operation))
                            {
                                cyclomaticComplexity += 1;
                            }

                            AddCoupledNamedTypesCore(builder, operation.Type);

                            // Handle static member accesses specially as there is no operation for static type off which the member is accessed.
                            if (operation is IMemberReferenceOperation memberReference &&
                                memberReference.Member.IsStatic)
                            {
                                AddCoupledNamedTypesCore(builder, memberReference.Member.ContainingType);
                            }
                            else if (operation is IInvocationOperation invocation &&
                                     (invocation.TargetMethod.IsStatic || invocation.TargetMethod.IsExtensionMethod))
                            {
                                AddCoupledNamedTypesCore(builder, invocation.TargetMethod.ContainingType);
                            }
                        }
                    }