internal async static Task <EventMetricData> ComputeAsync(IEventSymbol @event, SemanticModelProvider semanticModelProvider, CancellationToken cancellationToken) { var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>(); ImmutableArray <SyntaxReference> declarations = @event.DeclaringSyntaxReferences; long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, @event, semanticModelProvider, cancellationToken).ConfigureAwait(false); (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) = await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, @event, coupledTypesBuilder, semanticModelProvider, cancellationToken).ConfigureAwait(false); MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, @event.Type); ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(GetAccessors(@event), 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(@event, coupledTypesBuilder); return(new EventMetricData(@event, maintainabilityIndex, computationalComplexityMetrics, coupledTypesBuilder.ToImmutable(), linesOfCode, cyclomaticComplexity, depthOfInheritance, children)); }
internal static async Task <MethodMetricData> ComputeAsync(IMethodSymbol method, CodeMetricsAnalysisContext context) { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation); var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>(); ImmutableArray <SyntaxReference> declarations = method.DeclaringSyntaxReferences; long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, method, context).ConfigureAwait(false); (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) = await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, method, coupledTypesBuilder, context).ConfigureAwait(false); MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, method.Parameters); if (!method.ReturnsVoid) { MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, 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)); }
internal static async Task <PropertyMetricData> ComputeAsync(IPropertySymbol property, CodeMetricsAnalysisContext context) { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation); var coupledTypesBuilder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>(); ImmutableArray <SyntaxReference> declarations = property.DeclaringSyntaxReferences; long linesOfCode = await MetricsHelper.GetLinesOfCodeAsync(declarations, property, context).ConfigureAwait(false); (int cyclomaticComplexity, ComputationalComplexityMetrics computationalComplexityMetrics) = await MetricsHelper.ComputeCoupledTypesAndComplexityExcludingMemberDeclsAsync(declarations, property, coupledTypesBuilder, context).ConfigureAwait(false); MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, property.Parameters); MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, property.Type); ImmutableArray <CodeAnalysisMetricData> children = await ComputeAsync(GetAccessors(property), context).ConfigureAwait(false); int maintainabilityIndexTotal = 0; foreach (CodeAnalysisMetricData child in children) { MetricsHelper.AddCoupledNamedTypes(coupledTypesBuilder, wellKnownTypeProvider, 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 <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); } }