using System; using Codelyzer.Analysis.Build; using Codelyzer.Analysis.Common; using Codelyzer.Analysis.Model; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Codelyzer.Analysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic; namespace Codelyzer.Analysis { /// /// Code analyzer for VisualBasic /// public class VisualBasicCodeAnalyzer : CodeAnalyzer { public VisualBasicCodeAnalyzer(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 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 VisualBasicRoslynProcessor processor = new VisualBasicRoslynProcessor(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; } 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 }; } } }