using Codelyzer.Analysis.Build;
using Codelyzer.Analysis.Common;
using Codelyzer.Analysis.CSharp;
using Codelyzer.Analysis.Model;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
namespace Codelyzer.Analysis
{
///
/// Code analyzer for CSharp
///
public class CSharpCodeAnalyzer : CodeAnalyzer
{
public CSharpCodeAnalyzer(AnalyzerConfiguration configuration, ILogger logger)
: base(configuration, logger)
{
}
///
public override async Task AnalyzeProject(string projectPath)
{
AnalyzerResult analyzerResult = (await Analyze(projectPath)).First();
return analyzerResult;
}
public override async Task AnalyzeProject(string projectPath, List oldReferences, List references)
{
var analyzerResult = await AnalyzeWithReferences(projectPath, oldReferences?.ToDictionary(r => projectPath, r => oldReferences), references?.ToDictionary(r => projectPath, r => references));
return analyzerResult.FirstOrDefault();
}
///
public override async Task> AnalyzeSolution(string solutionPath)
{
return await Analyze(solutionPath);
}
///
public override CodeGraph GenerateGraph(List analyzerResults)
{
var codeGraph = new CodeGraph(Logger);
try
{
codeGraph.Initialize(analyzerResults);
}
catch (Exception ex)
{
Logger.LogError(ex, "Error while generating graph");
}
return codeGraph;
}
///
public override async Task AnalyzeSolutionWithGraph(string solutionPath)
{
var analyzerResults = await AnalyzeSolution(solutionPath);
var codeGraph = GenerateGraph(analyzerResults);
return new SolutionAnalyzerResult()
{
CodeGraph = codeGraph,
AnalyzerResults = analyzerResults
};
}
///
public override async IAsyncEnumerable AnalyzeSolutionGeneratorAsync(string solutionPath)
{
var result = AnalyzeGeneratorAsync(solutionPath).GetAsyncEnumerator();
try
{
while (await result.MoveNextAsync().ConfigureAwait(false))
{
yield return result.Current;
}
}
finally
{
await result.DisposeAsync();
}
}
///
public override async Task> AnalyzeSolution(string solutionPath, Dictionary> oldReferences, Dictionary> references)
{
var analyzerResults = await AnalyzeWithReferences(solutionPath, oldReferences, references);
return analyzerResults;
}
private async Task> AnalyzeWithReferences(string path, Dictionary> oldReferences, Dictionary> references)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
List workspaceResults = new List();
var analyzerResults = new List();
WorkspaceBuilder builder = new WorkspaceBuilder(Logger, path, AnalyzerConfiguration);
var projectBuildResults = builder.GenerateNoBuildAnalysis(oldReferences, references);
foreach (var projectBuildResult in projectBuildResults)
{
var workspaceResult = await Task.Run(() => AnalyzeProject(projectBuildResult));
workspaceResult.ProjectGuid = projectBuildResult.ProjectGuid;
workspaceResult.ProjectType = projectBuildResult.ProjectType;
workspaceResults.Add(workspaceResult);
//Generate Output result
if (AnalyzerConfiguration.MetaDataSettings.LoadBuildData)
{
analyzerResults.Add(new AnalyzerResult() { ProjectResult = workspaceResult, ProjectBuildResult = projectBuildResult });
}
else
{
analyzerResults.Add(new AnalyzerResult() { ProjectResult = workspaceResult });
}
}
await GenerateOptionalOutput(analyzerResults);
return analyzerResults;
}
private async Task> Analyze(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
List workspaceResults = new List();
var analyzerResults = new List();
WorkspaceBuilder builder = new WorkspaceBuilder(Logger, path, AnalyzerConfiguration);
var projectBuildResults = await builder.Build();
foreach (var projectBuildResult in projectBuildResults)
{
var workspaceResult = await Task.Run(() => AnalyzeProject(projectBuildResult));
workspaceResult.ProjectGuid = projectBuildResult.ProjectGuid;
workspaceResult.ProjectType = projectBuildResult.ProjectType;
workspaceResults.Add(workspaceResult);
//Generate Output result
if (AnalyzerConfiguration.MetaDataSettings.LoadBuildData)
{
analyzerResults.Add(new AnalyzerResult() { ProjectResult = workspaceResult, ProjectBuildResult = projectBuildResult });
}
else
{
analyzerResults.Add(new AnalyzerResult() { ProjectResult = workspaceResult });
}
}
await GenerateOptionalOutput(analyzerResults);
return analyzerResults;
}
private async IAsyncEnumerable AnalyzeGeneratorAsync(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
List workspaceResults = new List();
WorkspaceBuilder builder = new WorkspaceBuilder(Logger, path, AnalyzerConfiguration);
var projectBuildResultEnumerator = builder.BuildProject().GetAsyncEnumerator();
try
{
while (await projectBuildResultEnumerator.MoveNextAsync().ConfigureAwait(false))
{
var projectBuildResult = projectBuildResultEnumerator.Current;
var workspaceResult = AnalyzeProject(projectBuildResult);
workspaceResult.ProjectGuid = projectBuildResult.ProjectGuid;
workspaceResult.ProjectType = projectBuildResult.ProjectType;
workspaceResults.Add(workspaceResult);
if (AnalyzerConfiguration.MetaDataSettings.LoadBuildData)
{
yield return new AnalyzerResult() { ProjectResult = workspaceResult, ProjectBuildResult = projectBuildResult };
}
else
{
yield return new AnalyzerResult() { ProjectResult = workspaceResult };
}
}
}
finally
{
await projectBuildResultEnumerator.DisposeAsync();
}
}
private async Task GenerateOptionalOutput(List analyzerResults)
{
if (AnalyzerConfiguration.ExportSettings.GenerateJsonOutput)
{
Directory.CreateDirectory(AnalyzerConfiguration.ExportSettings.OutputPath);
foreach (var analyzerResult in analyzerResults)
{
Logger.LogDebug("Generating Json file for " + analyzerResult.ProjectResult.ProjectName);
var jsonOutput = SerializeUtils.ToJson(analyzerResult.ProjectResult);
var jsonFilePath = await FileUtils.WriteFileAsync(AnalyzerConfiguration.ExportSettings.OutputPath,
analyzerResult.ProjectResult.ProjectName+".json", jsonOutput);
analyzerResult.OutputJsonFilePath = jsonFilePath;
Logger.LogDebug("Generated Json file " + jsonFilePath);
}
}
}
private ProjectWorkspace AnalyzeProject(ProjectBuildResult projectResult)
{
Logger.LogDebug("Analyzing the project: " + projectResult.ProjectPath);
ProjectWorkspace workspace = new ProjectWorkspace(projectResult.ProjectPath)
{
SourceFiles = new UstList(projectResult.SourceFiles),
BuildErrors = projectResult.BuildErrors,
BuildErrorsCount = projectResult.BuildErrors.Count
};
if (AnalyzerConfiguration.MetaDataSettings.ReferenceData)
{
workspace.ExternalReferences = projectResult.ExternalReferences;
}
workspace.TargetFramework = projectResult.TargetFramework;
workspace.TargetFrameworks = projectResult.TargetFrameworks;
workspace.LinesOfCode = 0;
foreach (var fileBuildResult in projectResult.SourceFileBuildResults)
{
var fileAnalysis = AnalyzeFile(fileBuildResult, workspace.ProjectRootPath);
workspace.LinesOfCode += fileAnalysis.LinesOfCode;
workspace.SourceFileResults.Add(fileAnalysis);
}
return workspace;
}
private RootUstNode AnalyzeFile(SourceFileBuildResult sourceFileBuildResult, string projectRootPath)
{
CodeContext codeContext = new CodeContext(sourceFileBuildResult.PrePortSemanticModel,
sourceFileBuildResult.SemanticModel,
sourceFileBuildResult.SyntaxTree,
projectRootPath,
sourceFileBuildResult.SourceFilePath,
AnalyzerConfiguration,
Logger);
Logger.LogDebug("Analyzing: " + sourceFileBuildResult.SourceFileFullPath);
using CSharpRoslynProcessor processor = new CSharpRoslynProcessor(codeContext);
var result = (RootUstNode) processor.Visit(codeContext.SyntaxTree.GetRoot());
result.LinesOfCode = sourceFileBuildResult.SyntaxTree.GetRoot().DescendantTrivia()
.Where(t => t.IsKind(SyntaxKind.EndOfLineTrivia)).Count();
return result as RootUstNode;
}
public override async Task AnalyzeFile(string filePath, AnalyzerResult analyzerResult)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(filePath);
}
var projectBuildResult = analyzerResult.ProjectBuildResult;
var oldSourceFileResult = analyzerResult.ProjectResult.SourceFileResults.FirstOrDefault(sourceFile => sourceFile.FileFullPath == filePath);
analyzerResult.ProjectResult.SourceFileResults.Remove(oldSourceFileResult);
ProjectBuildHandler projectBuildHandler = new ProjectBuildHandler(Logger,
analyzerResult.ProjectBuildResult.Project,
analyzerResult.ProjectBuildResult.Compilation,
analyzerResult.ProjectBuildResult.PrePortCompilation,
AnalyzerConfiguration);
analyzerResult.ProjectBuildResult = await projectBuildHandler.IncrementalBuild(filePath, analyzerResult.ProjectBuildResult);
var newSourceFileBuildResult = projectBuildResult.SourceFileBuildResults.FirstOrDefault(sourceFile => sourceFile.SourceFileFullPath == filePath);
var fileAnalysis = AnalyzeFile(newSourceFileBuildResult, analyzerResult.ProjectResult.ProjectRootPath);
analyzerResult.ProjectResult.SourceFileResults.Add(fileAnalysis);
return analyzerResult;
}
public override async Task> AnalyzeFile(string filePath, List analyzerResults)
{
var analyzerResult = analyzerResults.First(analyzerResults => analyzerResults.ProjectBuildResult.SourceFileBuildResults.Any(s => s.SourceFileFullPath == filePath));
var updatedResult = await AnalyzeFile(filePath, analyzerResult);
analyzerResults.Remove(analyzerResult);
analyzerResults.Add(updatedResult);
return analyzerResults;
}
public override async Task AnalyzeFile(string projectPath, string filePath, List frameworkMetaReferences, List coreMetaReferences)
{
var fileInfo = new Dictionary();
var content = File.ReadAllText(filePath);
fileInfo.Add(filePath, content);
return await AnalyzeFile(projectPath, fileInfo, frameworkMetaReferences, coreMetaReferences);
}
public override async Task AnalyzeFile(string projectPath, List filePaths, List frameworkMetaReferences, List coreMetaReferences)
{
var fileInfo = new Dictionary();
filePaths.ForEach(filePath => {
var content = File.ReadAllText(filePath);
fileInfo.Add(filePath, content);
});
return await AnalyzeFile(projectPath, fileInfo, frameworkMetaReferences, coreMetaReferences);
}
public override async Task AnalyzeFile(string projectPath, string filePath, string fileContent, List frameworkMetaReferences, List coreMetaReferences)
{
var fileInfo = new Dictionary();
fileInfo.Add(filePath, fileContent);
return await AnalyzeFile(projectPath, fileInfo, frameworkMetaReferences, coreMetaReferences);
}
public override async Task AnalyzeFile(string projectPath, Dictionary fileInfo, List frameworkMetaReferences, List coreMetaReferences)
{
var result = new IDEProjectResult();
FileBuildHandler fileBuildHandler = new FileBuildHandler(Logger, projectPath, fileInfo, frameworkMetaReferences, coreMetaReferences);
var sourceFileResults = await fileBuildHandler.Build();
result.SourceFileBuildResults = sourceFileResults;
sourceFileResults.ForEach(sourceFileResult => {
var fileAnalysis = AnalyzeFile(sourceFileResult, projectPath);
result.RootNodes.Add(fileAnalysis);
});
return result;
}
public override async Task AnalyzeFile(string projectPath, Dictionary fileInfo, IEnumerable frameworkMetaReferences, List coreMetaReferences)
{
var result = new IDEProjectResult();
FileBuildHandler fileBuildHandler = new FileBuildHandler(Logger, projectPath, fileInfo, frameworkMetaReferences, coreMetaReferences);
var sourceFileResults = await fileBuildHandler.Build();
result.SourceFileBuildResults = sourceFileResults;
sourceFileResults.ForEach(sourceFileResult => {
var fileAnalysis = AnalyzeFile(sourceFileResult, projectPath);
result.RootNodes.Add(fileAnalysis);
});
return result;
}
}
}