Skip to content

Commit

Permalink
improve codeanalyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
DMarinhoCodacy committed Oct 22, 2024
1 parent 5f02ba0 commit 4e90a4c
Showing 1 changed file with 40 additions and 51 deletions.
91 changes: 40 additions & 51 deletions src/Analyzer/CodeAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
Expand All @@ -24,11 +25,12 @@ public class CodeAnalyzer : Codacy.Engine.Seed.CodeAnalyzer, IDisposable
private readonly string sonarConfigurationPath;
private readonly ImmutableArray<DiagnosticAnalyzer> availableAnalyzers;
private readonly DiagnosticsRunner diagnosticsRunner;

private readonly string tmpSonarLintFolder;
private static List<string> blacklist = new List<string> { "S1144", "S2325", "S2077"};
private static HashSet<string> blacklist = new HashSet<string> { "S1144", "S2325", "S2077" };
private static XElement cachedConfigurationFile;

public static bool IsInBlacklist(string id) {
public static bool IsInBlacklist(string id)
{
return blacklist.Contains(id);
}

Expand All @@ -38,19 +40,21 @@ public CodeAnalyzer() : base(csharpExtension)
availableAnalyzers = ImmutableArray.Create(
new RuleFinder()
.GetAnalyzerTypes()
.Select(type => (DiagnosticAnalyzer) Activator.CreateInstance(type))
.Select(type => (DiagnosticAnalyzer)Activator.CreateInstance(type))
.ToArray());

var additionalFiles = new List<AnalyzerAdditionalFile>();

if (!(PatternIds is null) && PatternIds.Any())
{
// create temporary directory
// create temporary directory only if needed
this.tmpSonarLintFolder = Path.Combine(Path.GetTempPath(), "sonarlint_" + Guid.NewGuid());
Directory.CreateDirectory(tmpSonarLintFolder);
var tmpSonarLintPath = Path.Combine(tmpSonarLintFolder, defaultSonarConfiguration);

var rules = new XElement("Rules");
var patterns = CurrentTool.Patterns.Where(pattern => !IsInBlacklist(pattern.PatternId)).ToArray();

foreach (var pattern in patterns)
{
var parameters = new XElement("Parameters");
Expand All @@ -69,20 +73,21 @@ public CodeAnalyzer() : base(csharpExtension)

new XDocument(new XElement("AnalysisInput", rules)).Save(tmpSonarLintPath);
additionalFiles.Add(new AnalyzerAdditionalFile(tmpSonarLintPath));
} else if (File.Exists(sonarConfigurationPath)) {
}
else if (cachedConfigurationFile == null && File.Exists(sonarConfigurationPath))
{
// Cache the configuration file in memory
cachedConfigurationFile = XDocument.Load(sonarConfigurationPath).Element("AnalysisInput");
additionalFiles.Add(new AnalyzerAdditionalFile(sonarConfigurationPath));
}

// if we don't have patterns let's get them from the config file
if (PatternIds is null && File.Exists(sonarConfigurationPath))
if (PatternIds is null && cachedConfigurationFile != null)
{
var xmlDoc = XDocument.Load(sonarConfigurationPath);
var analysisInput = xmlDoc.Element("AnalysisInput");
var rules = analysisInput.Element("Rules");
// Load patterns from cached configuration file
var rules = cachedConfigurationFile.Element("Rules");
if (rules != null)
{
PatternIds = rules.Elements("Rule").Select(e => e.Elements("Key").Single().Value)
.ToImmutableList();
PatternIds = rules.Elements("Rule").Select(e => e.Elements("Key").Single().Value).ToImmutableList();
}
}

Expand All @@ -95,17 +100,13 @@ public void Dispose()
GC.SuppressFinalize(this);
}

/// <summary>
/// Free temporary resources created on object construction.
/// </summary>
~CodeAnalyzer()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
// delete created temporary directory
if (tmpSonarLintFolder != null)
{
Directory.Delete(tmpSonarLintFolder, true);
Expand All @@ -114,19 +115,12 @@ protected virtual void Dispose(bool disposing)

protected override async Task Analyze(CancellationToken cancellationToken)
{
foreach (var file in Config.Files) {
// skip all files that don't have the main language extension
// To allow Semgrep to run on C# configuration files
// We are analyzing `Directory.Packages.props` as if it was a C# file
// This is to avoid that.
// More info here: https://codacy.zendesk.com/agent/tickets/44462
if (!file.EndsWith(".cs"))
{
continue;
}
// Process files concurrently for better performance
var fileAnalysisTasks = Config.Files
.Where(file => file.EndsWith(".cs")) // only analyze C# files
.Select(file => Analyze(file, cancellationToken));

await Analyze(file, cancellationToken).ConfigureAwait(false);
}
await Task.WhenAll(fileAnalysisTasks);
}

public async Task Analyze(string file, CancellationToken cancellationToken)
Expand All @@ -136,28 +130,24 @@ public async Task Analyze(string file, CancellationToken cancellationToken)
var solution = CompilationHelper.GetSolutionFromFile(DefaultSourceFolder + file);
var compilation = await solution.Projects.First().GetCompilationAsync();

foreach (var diagnostic in await diagnosticsRunner.GetDiagnostics(compilation, cancellationToken))
// Parallelize diagnostics fetching
var diagnostics = await diagnosticsRunner.GetDiagnostics(compilation, cancellationToken);

Parallel.ForEach(diagnostics, diagnostic =>
{
var result = new CodacyResult
{
Filename = file,
PatternId = diagnostic.Id,
Message = diagnostic.GetMessage()
Message = diagnostic.GetMessage(),
Line = diagnostic.Location != Location.None ? diagnostic.Location.GetLineNumberToReport() : 1
};

if (diagnostic.Location != Location.None)
{
result.Line = diagnostic.Location.GetLineNumberToReport();
}
else
if (!IsInBlacklist(diagnostic.Id))
{
result.Line = 1;
}

if(!IsInBlacklist(diagnostic.Id)) {
Console.WriteLine(result);
}
}
});
}
catch (Exception e)
{
Expand All @@ -177,27 +167,26 @@ public ImmutableArray<DiagnosticAnalyzer> GetAnalyzers()
{
return availableAnalyzers;
}
var builder = ImmutableArray.CreateBuilder<DiagnosticAnalyzer>();

foreach (var analyzer in availableAnalyzers
.Where(analyzer => analyzer.SupportedDiagnostics.Any(diagnostic => PatternIds.Contains(diagnostic.Id))))
builder.Add(analyzer);
// Initialize only relevant analyzers
var relevantAnalyzers = availableAnalyzers
.Where(analyzer => analyzer.SupportedDiagnostics.Any(diagnostic => PatternIds.Contains(diagnostic.Id)))
.ToImmutableArray();

return builder.ToImmutable();
return relevantAnalyzers;
}

public static ImmutableArray<DiagnosticAnalyzer> GetUtilityAnalyzers()
{
var builder = ImmutableArray.CreateBuilder<DiagnosticAnalyzer>();
var utilityAnalyzerTypes = RuleFinder.GetUtilityAnalyzerTypes()
.Where(t => !t.IsAbstract)
.ToList();

foreach (var analyzer in utilityAnalyzerTypes
.Select(type => (DiagnosticAnalyzer) Activator.CreateInstance(type)))
builder.Add(analyzer);
var utilityAnalyzers = utilityAnalyzerTypes
.Select(type => (DiagnosticAnalyzer)Activator.CreateInstance(type))
.ToImmutableArray();

return builder.ToImmutable();
return utilityAnalyzers;
}
}
}

0 comments on commit 4e90a4c

Please sign in to comment.