Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements for CodeMetricsAnalyzer performance #7118

Merged
merged 12 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ End Class
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 @@ End Class
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