internal static async Task <PropertyMetricData> ComputeAsync(IPropertySymbol property, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                ImmutableArray <SyntaxReference> declarations = property.DeclaringSyntaxReferences;
                long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, property, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) =
                    await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, property, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, property.Parameters);
                MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, property.Type);

                ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(GetAccessors(property), semanticModelProvider, cancellationToken).ConfigureAwait(false);

                int maintainabilityIndexTotal = 0;

                foreach (CodeAnalysisMetricData child in children)
                {
                    MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, child.CoupledNamedTypes);
                    maintainabilityIndexTotal     += child.MaintainabilityIndex;
                    cyclomaticComplexity          += child.CyclomaticComplexity;
                    computationalComplexityMetrics = computationalComplexityMetrics.Union(child.ComputationalComplexityMetrics);
                }

                int?depthOfInheritance   = null;
                int maintainabilityIndex = children.Length > 0 ? MetricsHelper.GetAverageRoundedMetricValue(maintainabilityIndexTotal, children.Length) : 100;

                MetricsHelper.RemoveContainingTypes(property, coupledTypesBuilder);

                return(new PropertyMetricData(property, maintainabilityIndex, computationalComplexityMetrics,
                                              coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance, children));
            }
            internal static async Task <MethodMetricData> ComputeAsync(IMethodSymbol method, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                ImmutableArray <SyntaxReference> declarations = method.DeclaringSyntaxReferences;
                long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, method, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) =
                    await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, method, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, method.Parameters);
                if (!method.ReturnsVoid)
                {
                    MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, method.ReturnType);
                }
                int?depthOfInheritance   = null;
                int maintainabilityIndex = CalculateMaintainabilityIndex(computationalComplexityMetrics, cyclomaticComplexity);

                MetricsHelper.RemoveContainingTypes(method, coupledTypesBuilder);

                if (cyclomaticComplexity == 0)
                {
                    // Empty method, such as auto-generated accessor.
                    cyclomaticComplexity = 1;
                }

                return(new MethodMetricData(method, maintainabilityIndex, computationalComplexityMetrics,
                                            coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance));
            }
示例#3
0
            internal static async Task <NamespaceMetricData> ComputeAsync(INamespaceSymbol @namespace, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var  coupledTypesBuilder       = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                int  maintainabilityIndexTotal = 0;
                int  cyclomaticComplexity      = 0;
                int  depthOfInheritance        = 0;
                long childrenLinesOfCode       = 0;

                ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(GetChildSymbols(@namespace), semanticModelProvider, cancellationToken).ConfigureAwait(false);

                foreach (CodeAnalysisMetricData child in children)
                {
                    MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, child.CoupledNamedTypes);
                    maintainabilityIndexTotal += child.MaintainabilityIndex;
                    cyclomaticComplexity      += child.CyclomaticComplexity;
                    depthOfInheritance         = Math.Max(child.DepthOfInheritance.GetValueOrDefault(), depthOfInheritance);

                    // Avoid double counting lines for nested types.
                    if (child.Symbol.ContainingType == null)
                    {
                        childrenLinesOfCode += child.SourceLines;
                    }
                }

                long linesOfCode = @namespace.IsImplicitlyDeclared ?
                                   childrenLinesOfCode :
                                   await MetricsHelper.GetLinesOfCodeAsync(@namespace.DeclaringSyntaxReferences, @namespace, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                int maintainabilityIndex = children.Length > 0 ? MetricsHelper.GetAverageRoundedMetricValue(maintainabilityIndexTotal, children.Length) : 100;

                return(new NamespaceMetricData(@namespace, maintainabilityIndex,
                                               coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance, children));
            }
            internal static async Task <FieldMetricData> ComputeAsync(IFieldSymbol field, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                ImmutableArray <SyntaxReference> declarations = field.DeclaringSyntaxReferences;
                long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, field, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) =
                    await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, field, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, field.Type);
                int?depthOfInheritance   = null;
                int maintainabilityIndex = CalculateMaintainabilityIndex(computationalComplexityMetrics, cyclomaticComplexity);

                MetricsHelper.RemoveContainingTypes(field, coupledTypesBuilder);

                return(new FieldMetricData(field, maintainabilityIndex, computationalComplexityMetrics,
                                           coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance));
            }
            internal static async Task <NamedTypeMetricData> ComputeAsync(INamedTypeSymbol namedType, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken)
            {
                var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>();
                ImmutableArray <SyntaxReference> declarations = namedType.DeclaringSyntaxReferences;

                (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) =
                    await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, namedType, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                // Compat: Filter out nested types as they are children of most closest containing namespace.
                var members = namedType.GetMembers().Where(m => m.Kind != SymbolKind.NamedType);

#if LEGACY_CODE_METRICS_MODE
                // Legacy mode skips metrics for field/property/event symbols, and explicitly includes accessors as methods.
                members = members.Where(m => m.Kind != SymbolKind.Field && m.Kind != SymbolKind.Property && m.Kind != SymbolKind.Event);
#else
                // Filter out accessors as they are children of their associated symbols, for which we generate a separate node.
                members = members.Where(m => m.Kind != SymbolKind.Method || ((IMethodSymbol)m).AssociatedSymbol == null);
#endif

                ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(members, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                // Heuristic to prevent simple fields (no initializer or simple initializer) from skewing the complexity.
                ImmutableHashSet <IFieldSymbol> filteredFieldsForComplexity = getFilteredFieldsForComplexity();

                int effectiveChildrenCountForComplexity      = 0;
                int singleEffectiveChildMaintainabilityIndex = -1;
                foreach (CodeAnalysisMetricData child in children)
                {
                    MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, child.CoupledNamedTypes);

                    if (child.Symbol.Kind != SymbolKind.Field ||
                        filteredFieldsForComplexity.Contains((IFieldSymbol)child.Symbol))
                    {
                        singleEffectiveChildMaintainabilityIndex = effectiveChildrenCountForComplexity == 0 && computationalComplexityMetrics.IsDefault ?
                                                                   child.MaintainabilityIndex :
                                                                   -1;
                        effectiveChildrenCountForComplexity++;
                        cyclomaticComplexity          += child.CyclomaticComplexity;
                        computationalComplexityMetrics = computationalComplexityMetrics.Union(child.ComputationalComplexityMetrics);
                    }
                }

                if (cyclomaticComplexity == 0 && !namedType.IsStatic)
                {
                    // Empty named type, account for implicit constructor.
                    cyclomaticComplexity = 1;
                }

                int  depthOfInheritance = CalculateDepthOfInheritance(namedType);
                long linesOfCode        = await MetricsHelper.GetLinesOfCodeAsync(declarations, namedType, semanticModelProvider, cancellationToken).ConfigureAwait(false);

                int maintainabilityIndex = singleEffectiveChildMaintainabilityIndex != -1 ?
                                           singleEffectiveChildMaintainabilityIndex :
                                           CalculateMaintainabilityIndex(computationalComplexityMetrics, cyclomaticComplexity, effectiveChildrenCountForComplexity);
                MetricsHelper.RemoveContainingTypes(namedType, coupledTypesBuilder);

                return(new NamedTypeMetricData(namedType, maintainabilityIndex, computationalComplexityMetrics,
                                               coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance, children));

                ImmutableHashSet <IFieldSymbol> getFilteredFieldsForComplexity()
                {
                    ImmutableHashSet <IFieldSymbol> .Builder builderOpt = null;
                    var orderedFieldDatas = children.Where(c => c.Symbol.Kind == SymbolKind.Field).OrderBy(c => c.MaintainabilityIndex);
                    var indexThreshold    = 99;

                    foreach (CodeAnalysisMetricData fieldData in orderedFieldDatas)
                    {
                        if (fieldData.MaintainabilityIndex > indexThreshold)
                        {
                            break;
                        }

                        builderOpt = ImmutableHashSet.CreateBuilder <IFieldSymbol>();
                        builderOpt.Add((IFieldSymbol)fieldData.Symbol);
                        indexThreshold -= 4;
                    }

                    return(builderOpt?.ToImmutable() ?? ImmutableHashSet <IFieldSymbol> .Empty);
                }
            }