private static int CalculateMaintainabilityIndex(ComputationalComplexityMetrics computationalComplexityMetrics, int cyclomaticComplexity) { double computationalComplexityVolume = Math.Max(0.0, Math.Log(computationalComplexityMetrics.Volume)); //avoid Log(0) = -Infinity double logEffectiveLinesOfCode = Math.Max(0.0, Math.Log(computationalComplexityMetrics.EffectiveLinesOfCode)); //avoid Log(0) = -Infinity return(MetricsHelper.NormalizeAndRoundMaintainabilityIndex(171 - 5.2 * computationalComplexityVolume - 0.23 * cyclomaticComplexity - 16.2 * logEffectiveLinesOfCode)); }
internal CodeAnalysisMetricData( ISymbol symbol, int maintainabilityIndex, ComputationalComplexityMetrics computationalComplexityMetrics, ImmutableHashSet <INamedTypeSymbol> coupledNamedTypes, long linesOfCode, int cyclomaticComplexity, int?depthOfInheritance, ImmutableArray <CodeAnalysisMetricData> children) { Debug.Assert( symbol.Kind == SymbolKind.Assembly || symbol.Kind == SymbolKind.Namespace || symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Event || symbol.Kind == SymbolKind.Property); Debug.Assert(depthOfInheritance.HasValue == (symbol.Kind == SymbolKind.Assembly || symbol.Kind == SymbolKind.Namespace || symbol.Kind == SymbolKind.NamedType)); var executableLines = !computationalComplexityMetrics.IsDefault ? computationalComplexityMetrics.ExecutableLines : children.Sum(c => c.ExecutableLines); Symbol = symbol; MaintainabilityIndex = maintainabilityIndex; ComputationalComplexityMetrics = computationalComplexityMetrics; CoupledNamedTypes = coupledNamedTypes; SourceLines = linesOfCode; ExecutableLines = executableLines; CyclomaticComplexity = cyclomaticComplexity; DepthOfInheritance = depthOfInheritance; Children = children; }
internal FieldMetricData( IFieldSymbol symbol, int maintainabilityIndex, ComputationalComplexityMetrics computationalComplexityMetrics, ImmutableHashSet <INamedTypeSymbol> coupledNamedTypes, long linesOfCode, int cyclomaticComplexity, int?depthOfInheritance) : base(symbol, maintainabilityIndex, computationalComplexityMetrics, coupledNamedTypes, linesOfCode, cyclomaticComplexity, depthOfInheritance, children: ImmutableArray <CodeAnalysisMetricData> .Empty) { }
private static int CalculateMaintainabilityIndex( ComputationalComplexityMetrics computationalComplexityMetrics, int cyclomaticComplexity, int effectiveChildrenCount) { double avgComputationalComplexityVolume = 1.0; double avgEffectiveLinesOfCode = 0.0; double avgCyclomaticComplexity = 0.0; if (effectiveChildrenCount > 0) { avgComputationalComplexityVolume = computationalComplexityMetrics.Volume / effectiveChildrenCount; avgEffectiveLinesOfCode = computationalComplexityMetrics.EffectiveLinesOfCode / effectiveChildrenCount; avgCyclomaticComplexity = cyclomaticComplexity / effectiveChildrenCount; } double logAvgComputationalComplexityVolume = Math.Max(0.0, Math.Log(avgComputationalComplexityVolume)); //avoid Log(0) = -Infinity double logAvgLinesOfCode = Math.Max(0.0, Math.Log(avgEffectiveLinesOfCode)); //avoid Log(0) = -Infinity return(MetricsHelper.NormalizeAndRoundMaintainabilityIndex(171 - 5.2 * logAvgComputationalComplexityVolume - 0.23 * avgCyclomaticComplexity - 16.2 * logAvgLinesOfCode)); }
public ComputationalComplexityMetrics Union(ComputationalComplexityMetrics other) { if (ReferenceEquals(this, Default)) { return(other); } else if (ReferenceEquals(other, Default)) { return(this); } return(new ComputationalComplexityMetrics( executableLinesOfCode: ExecutableLines + other.ExecutableLines, effectiveLinesOfMaintainableCode: EffectiveLinesOfCode + other.EffectiveLinesOfCode, operatorUsageCounts: _operatorUsageCounts + other._operatorUsageCounts, symbolUsageCounts: _symbolUsageCounts + other._symbolUsageCounts, constantUsageCounts: _constantUsageCounts + other._constantUsageCounts, distinctOperatorKinds: _distinctOperatorKinds.Union(other._distinctOperatorKinds), distinctBinaryOperatorKinds: _distinctBinaryOperatorKinds.Union(other._distinctBinaryOperatorKinds), distinctUnaryOperatorKinds: _distinctUnaryOperatorKinds.Union(other._distinctUnaryOperatorKinds), distinctCaseKinds: _distinctCaseKinds.Union(other._distinctCaseKinds), distinctReferencedSymbols: _distinctReferencedSymbols.Union(other._distinctReferencedSymbols), distinctReferencedConstants: _distinctReferencedConstants.Union(other._distinctReferencedConstants))); }
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>(); var applicableAttributeNodes = PooledHashSet <SyntaxNode> .GetInstance(); 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 && attribute.ApplicationSyntaxReference.SyntaxTree == declaration.SyntaxTree) { var attributeSyntax = await attribute.ApplicationSyntaxReference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false); if (applicableAttributeNodes.Add(attributeSyntax)) { 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; case OperationKind.None: // Skip non-applicable attributes. if (!applicableAttributeNodes.Contains(node)) { continue; } 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); } } }