Skip to content

Commit

Permalink
Merge pull request #7118 from sharwell/metrics-perf
Browse files Browse the repository at this point in the history
Improvements for CodeMetricsAnalyzer performance
  • Loading branch information
sharwell authored Jan 2, 2024
2 parents 5340636 + 4f9757f commit 8a92037
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.ExecutableLines.get ->
Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.MaintainabilityIndex.get -> int
Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.SourceLines.get -> long
Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.Symbol.get -> Microsoft.CodeAnalysis.ISymbol!
Microsoft.CodeAnalysis.CodeMetrics.CodeMetricsAnalysisContext.WellKnownTypeProvider.get -> Analyzer.Utilities.WellKnownTypeProvider!
Microsoft.CodeAnalysis.FlowAnalysis.BranchWithInfo
Microsoft.CodeAnalysis.FlowAnalysis.BranchWithInfo.BranchValue.get -> Microsoft.CodeAnalysis.IOperation?
Microsoft.CodeAnalysis.FlowAnalysis.BranchWithInfo.ControlFlowConditionKind.get -> Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowConditionKind
Expand Down Expand Up @@ -74,6 +75,8 @@ static Analyzer.Utilities.RoslynHashCode.Combine<T1, T2, T3, T4>(T1 value1, T2 v
static Analyzer.Utilities.RoslynHashCode.Combine<T1, T2, T3>(T1 value1, T2 value2, T3 value3) -> int
static Analyzer.Utilities.RoslynHashCode.Combine<T1, T2>(T1 value1, T2 value2) -> int
static Analyzer.Utilities.RoslynHashCode.Combine<T1>(T1 value1) -> int
static Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.ComputeSynchronously(Microsoft.CodeAnalysis.CodeMetrics.CodeMetricsAnalysisContext! context) -> Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData!
static Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData.ComputeSynchronously(Microsoft.CodeAnalysis.ISymbol! symbol, Microsoft.CodeAnalysis.CodeMetrics.CodeMetricsAnalysisContext! context) -> Microsoft.CodeAnalysis.CodeMetrics.CodeAnalysisMetricData!
static Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.AnalysisEntity.Create(Microsoft.CodeAnalysis.ISymbol? symbol, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.AbstractIndex!> indices, Microsoft.CodeAnalysis.ITypeSymbol! type, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis.PointsToAbstractValue! instanceLocation, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.AnalysisEntity? parent, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.AnalysisEntity? entityForInstanceLocation) -> Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.AnalysisEntity!
static Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis.DisposeAnalysis.TryGetOrComputeResult(Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! cfg, Microsoft.CodeAnalysis.ISymbol! owningSymbol, Analyzer.Utilities.WellKnownTypeProvider! wellKnownTypeProvider, Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions! analyzerOptions, Microsoft.CodeAnalysis.DiagnosticDescriptor! rule, System.Collections.Immutable.ImmutableHashSet<Microsoft.CodeAnalysis.INamedTypeSymbol!>! disposeOwnershipTransferLikelyTypes, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis.PointsToAnalysisKind defaultPointsToAnalysisKind, bool trackInstanceFields, bool exceptionPathsAnalysis, out Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis.PointsToAnalysisResult? pointsToAnalysisResult, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisKind interproceduralAnalysisKind = Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisKind.ContextSensitive, bool performCopyAnalysisIfNotUserConfigured = false, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisPredicate? interproceduralAnalysisPredicate = null, bool defaultDisposeOwnershipTransferAtConstructor = false, bool defaultDisposeOwnershipTransferAtMethodCall = false) -> Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis.DisposeAnalysisResult?
static Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisConfiguration.Create(Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions! analyzerOptions, Microsoft.CodeAnalysis.DiagnosticDescriptor! rule, Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph! cfg, Microsoft.CodeAnalysis.Compilation! compilation, Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisKind defaultInterproceduralAnalysisKind, uint defaultMaxInterproceduralMethodCallChain = 3, uint defaultMaxInterproceduralLambdaOrLocalFunctionCallChain = 3) -> Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.InterproceduralAnalysisConfiguration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,10 @@ public override void Initialize(AnalysisContext context)

var metricsAnalysisContext = new CodeMetricsAnalysisContext(compilationContext.Compilation, compilationContext.CancellationToken,
namedType => IsConfiguredToSkipFromInheritanceCount(namedType, compilationContext, tree));
var computeTask = CodeAnalysisMetricData.ComputeAsync(metricsAnalysisContext);
computeTask.Wait(compilationContext.CancellationToken);
var codeAnalysisMetricData = CodeAnalysisMetricData.ComputeSynchronously(metricsAnalysisContext);

// Analyze code metrics tree and report diagnostics.
analyzeMetricsData(computeTask.Result);
analyzeMetricsData(codeAnalysisMetricData);

void analyzeMetricsData(CodeAnalysisMetricData codeAnalysisMetricData)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
Expand All @@ -18,8 +18,11 @@ public class CodeMetricsAnalyzerTests
{
#region CA1501: Avoid excessive inheritance

[Fact]
public async Task CA1501_CSharp_VerifyDiagnosticAsync()
[Theory]
[InlineData("\r\n")]
[InlineData("\r")]
[InlineData("\n")]
public async Task CA1501_CSharp_VerifyDiagnosticAsync(string lineEndings)
{
var source = @"
class BaseClass { }
Expand All @@ -31,7 +34,7 @@ class FifthDerivedClass : FourthDerivedClass { }
// This class violates the rule.
class SixthDerivedClass : FifthDerivedClass { }
";
".ReplaceLineEndings(lineEndings);
DiagnosticResult[] expected = new[] {
GetCSharpCA1501ExpectedDiagnostic(10, 7, "SixthDerivedClass", 6, 6, "FifthDerivedClass, FourthDerivedClass, ThirdDerivedClass, SecondDerivedClass, FirstDerivedClass, BaseClass")};
await VerifyCS.VerifyAnalyzerAsync(source, expected);
Expand Down Expand Up @@ -618,6 +621,85 @@ void M(bool b)
await VerifyCS.VerifyAnalyzerAsync(source, expected);
}

[Fact]
public async Task CA1502_CSharp_VerifyDiagnosticInPropertyAsync()
{
var source = @"
class C
{
bool b;
bool M
{
get
{
// Default threshold = 25
var x = b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b;
return x;
}
set
{
// Default threshold = 25
var x = b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b;
}
}
}
";
DiagnosticResult[] expected = new[]
{
// Test0.cs(8,9): warning CA1502: 'get_M' has a cyclomatic complexity of '28'. Rewrite or refactor the code to decrease its complexity below '26'.
GetCSharpCA1502ExpectedDiagnostic(8, 9, "get_M", 28, 26),
// Test0.cs(17,9): warning CA1502: 'set_M' has a cyclomatic complexity of '28'. Rewrite or refactor the code to decrease its complexity below '26'.
GetCSharpCA1502ExpectedDiagnostic(17, 9, "set_M", 28, 26),
};
await VerifyCS.VerifyAnalyzerAsync(source, expected);
}

[Fact]
public async Task CA1502_CSharp_VerifyDiagnosticInEventAsync()
{
var source = @"
class C
{
bool b;
event System.EventHandler M
{
add
{
// Default threshold = 25
var x = b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b;
}
remove
{
// Default threshold = 25
var x = b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b &&
b && b && b && b && b && b && b;
}
}
}
";
DiagnosticResult[] expected = new[]
{
// Test0.cs(8,9): warning CA1502: 'add_M' has a cyclomatic complexity of '28'. Rewrite or refactor the code to decrease its complexity below '26'.
GetCSharpCA1502ExpectedDiagnostic(8, 9, "add_M", 28, 26),
// Test0.cs(16,9): warning CA1502: 'remove_M' has a cyclomatic complexity of '28'. Rewrite or refactor the code to decrease its complexity below '26'.
GetCSharpCA1502ExpectedDiagnostic(16, 9, "remove_M", 28, 26),
};
await VerifyCS.VerifyAnalyzerAsync(source, expected);
}

[Fact]
public async Task CA1502_Basic_VerifyDiagnosticAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public void M1(C c)
c.M(str);
}
}
".NormalizeLineEndings(),
",
// Test0.cs(16,13): warning CA1303: Method 'void Test.M1(C c)' passes a literal string as parameter 'param' of a call to 'void C.M(string param)'. Retrieve the following string(s) from a resource table instead: "a a".
GetCSharpResultAt(16, 13, "void Test.M1(C c)", "param", "void C.M(string param)", "a a"));

Expand All @@ -223,7 +223,7 @@ Public Sub M1(c As C)
c.M(str)
End Sub
End Class
".NormalizeLineEndings(),
",
// Test0.vb(13,13): warning CA1303: Method 'Sub Test.M1(c As C)' passes a literal string as parameter 'param' of a call to 'Sub C.M(param As String)'. Retrieve the following string(s) from a resource table instead: "a a".
GetBasicResultAt(13, 13, "Sub Test.M1(c As C)", "param", "Sub C.M(param As String)", "a a"));
}
Expand Down Expand Up @@ -1868,7 +1868,7 @@ public void M1(C c)
c.M(str);
}
}
".NormalizeLineEndings();
";
var csTest = new VerifyCS.Test()
{
TestState =
Expand Down Expand Up @@ -1903,7 +1903,7 @@ Public Sub M1(c As C)
c.M(str)
End Sub
End Class
".NormalizeLineEndings();
";
var vbTest = new VerifyVB.Test()
{
TestState =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3021,10 +3021,10 @@ public async Task TestPreserveTrailingNewlineAsync(string originalEndOfFile, str
C.Property.get -> int{expectedEndOfFile}";

await VerifyCSharpAdditionalFileFixAsync(
source.NormalizeLineEndings(),
source.ReplaceLineEndings("\r\n"),
shippedText,
unshippedText.NormalizeLineEndings(),
fixedUnshippedText.NormalizeLineEndings());
unshippedText.ReplaceLineEndings("\r\n"),
fixedUnshippedText.ReplaceLineEndings("\r\n"));
}

[Fact]
Expand Down
Loading

0 comments on commit 8a92037

Please sign in to comment.