public void summaryScales() { string programDir = srcDir + "\\ExprData\\sourcecode"; string summaryDir = srcDir + "\\ExprData\\summaryScales"; if (!Directory.Exists(summaryDir)) { Directory.CreateDirectory(summaryDir); } int sumFiles = 0; int sumClasses = 0; int sumMethods = 0; int sumLines = 0; StringBuilder sb_files = new StringBuilder(); StringBuilder sb_classes = new StringBuilder(); StringBuilder sb_methods = new StringBuilder(); StringBuilder sb_lines = new StringBuilder(); foreach (var proPath in Directory.GetDirectories(programDir)) { string proName = proPath.Split('\\').Last(); Console.WriteLine("Summary " + proName + "..."); int countFiles = 0; int countClasses = 0; int countMethods = 0; int countLines = 0; HashSet <string> filePath = new HashSet <string>(); foreach (var slnPath in Common.scanCSharpSln(proPath)) { var msWorkspace = MSBuildWorkspace.Create(); var sol = msWorkspace.OpenSolutionAsync(slnPath).Result; foreach (var pro in sol.Projects) { foreach (var doc in pro.Documents) { if (filePath.Contains(doc.FilePath)) { continue; } filePath.Add(doc.FilePath); countFiles++; var rootNode = doc.GetSyntaxRootAsync().Result; var classNodes = rootNode.DescendantNodes().OfType <ClassDeclarationSyntax>(); var methodNodes = rootNode.DescendantNodes().OfType <MethodDeclarationSyntax>(); countClasses += classNodes.Count(); countMethods += methodNodes.Count(); var text = doc.GetTextAsync().Result.ToString(); countLines += text.Split('\n').Length; } } } sumFiles += countFiles; sumClasses += countClasses; sumMethods += countMethods; sumLines += countLines; sb_files.AppendLine(proName + "\t" + countFiles); sb_classes.AppendLine(proName + "\t" + countClasses); sb_methods.AppendLine(proName + "\t" + countMethods); sb_lines.AppendLine(proName + "\t" + countLines); } File.WriteAllText(summaryDir + "\\Files.txt", sb_files.ToString()); File.WriteAllText(summaryDir + "\\Classes.txt", sb_classes.ToString()); File.WriteAllText(summaryDir + "\\Methods.txt", sb_methods.ToString()); File.WriteAllText(summaryDir + "\\Lines.txt", sb_lines.ToString()); StringBuilder sb1 = new StringBuilder(); sb1.AppendLine("Files\t\t" + sumFiles); sb1.AppendLine("Classes\t\t" + sumClasses); sb1.AppendLine("Methods\t\t" + sumMethods); sb1.AppendLine("Lines\t\t" + sumLines); File.WriteAllText(summaryDir + "\\Sum.txt", sb1.ToString()); }
private async Task LoadSolutionAsync() { var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); var solutionPath = Path.Combine(roslynRoot, "Compilers.sln"); if (!File.Exists(solutionPath)) { throw new ArgumentException("Couldn't find Compilers.sln"); } Console.WriteLine("Found Compilers.sln: " + Process.GetCurrentProcess().Id); var assemblies = MSBuildMefHostServices.DefaultAssemblies .Add(typeof(AnalyzerRunnerHelper).Assembly) .Add(typeof(FindReferencesBenchmarks).Assembly); var services = MefHostServices.Create(assemblies); _workspace = MSBuildWorkspace.Create(new Dictionary <string, string> { // Use the latest language version to force the full set of available analyzers to run on the project. { "LangVersion", "preview" }, }, services); if (_workspace == null) { throw new ArgumentException("Couldn't create workspace"); } _workspace.TryApplyChanges(_workspace.CurrentSolution.WithOptions(_workspace.Options .WithChangedOption(StorageOptions.Database, StorageDatabase.SQLite))); Console.WriteLine("Opening roslyn. Attach to: " + Process.GetCurrentProcess().Id); var start = DateTime.Now; _solution = await _workspace.OpenSolutionAsync(solutionPath, progress : null, CancellationToken.None); Console.WriteLine("Finished opening roslyn: " + (DateTime.Now - start)); // Force a storage instance to be created. This makes it simple to go examine it prior to any operations we // perform, including seeing how big the initial string table is. var storageService = _workspace.Services.GetPersistentStorageService(_workspace.CurrentSolution.Options); if (storageService == null) { throw new ArgumentException("Couldn't get storage service"); } using (var storage = await storageService.GetStorageAsync(SolutionKey.ToSolutionKey(_workspace.CurrentSolution), CancellationToken.None)) { Console.WriteLine("Sucessfully got persistent storage instance"); } // There might be multiple projects with this name. That's ok. FAR goes and finds all the linked-projects // anyways to perform the search on all the equivalent symbols from them. So the end perf cost is the // same. var project = _solution.Projects.First(p => p.AssemblyName == "Microsoft.CodeAnalysis"); start = DateTime.Now; var compilation = await project.GetCompilationAsync(); Console.WriteLine("Time to get first compilation: " + (DateTime.Now - start)); _type = compilation.GetTypeByMetadataName("Microsoft.CodeAnalysis.SyntaxToken"); if (_type == null) { throw new Exception("Couldn't find type"); } }
private Solution LoadSolution(string solutionFilePath, IDictionary <string, string> properties = null) { var ws = MSBuildWorkspace.Create(properties); return(ws.OpenSolutionAsync(solutionFilePath).Result); }
public void Cleanup() { _workspace?.Dispose(); _workspace = null; _solution = null; }
public DiagramGenerator(string solutionPath, MSBuildWorkspace workspace) { _solution = workspace.OpenSolutionAsync(solutionPath).Result; }
private static async Task Main(string[] args) { if (args == null || args.Length == 0) { #if DEBUG args = new[] { @"..\..\..\..\.." }; #else args = new string[] { Environment.CurrentDirectory }; #endif } string rootPath = args[0]; StringComparer comparer = StringComparer.InvariantCulture; var metadata = new RoslynatorMetadata(rootPath); ImmutableArray <AnalyzerMetadata> analyzers = metadata.Analyzers; ImmutableArray <AnalyzerMetadata> codeAnalysisAnalyzers = metadata.CodeAnalysisAnalyzers; ImmutableArray <AnalyzerMetadata> formattingAnalyzers = metadata.FormattingAnalyzers; ImmutableArray <RefactoringMetadata> refactorings = metadata.Refactorings; ImmutableArray <CodeFixMetadata> codeFixes = metadata.CodeFixes; ImmutableArray <CompilerDiagnosticMetadata> compilerDiagnostics = metadata.CompilerDiagnostics; WriteAllText( @"..\docs\Options.md", MarkdownGenerator.CreateListOfAnalyzerOptions(metadata)); WriteAnalyzersReadMe(@"Analyzers\README.md", analyzers, "Roslynator.Analyzers"); WriteAnalyzersReadMe(@"CodeAnalysis.Analyzers\README.md", codeAnalysisAnalyzers, "Roslynator.CodeAnalysis.Analyzers"); WriteAnalyzersReadMe(@"Formatting.Analyzers\README.md", formattingAnalyzers, "Roslynator.Formatting.Analyzers"); #if !DEBUG VisualStudioInstance instance = MSBuildLocator.QueryVisualStudioInstances().First(f => f.Version.Major == 16); MSBuildLocator.RegisterInstance(instance); using (MSBuildWorkspace workspace = MSBuildWorkspace.Create()) { workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message); string solutionPath = Path.Combine(rootPath, "Roslynator.sln"); Console.WriteLine($"Loading solution '{solutionPath}'"); Solution solution = await workspace.OpenSolutionAsync(solutionPath).ConfigureAwait(false); Console.WriteLine($"Finished loading solution '{solutionPath}'"); RoslynatorInfo roslynatorInfo = await RoslynatorInfo.Create(solution).ConfigureAwait(false); IOrderedEnumerable <SourceFile> sourceFiles = analyzers .Concat(codeAnalysisAnalyzers) .Concat(formattingAnalyzers) .Select(f => new SourceFile(f.Id, roslynatorInfo.GetAnalyzerFilesAsync(f.Identifier).Result)) .Concat(refactorings .Select(f => new SourceFile(f.Id, roslynatorInfo.GetRefactoringFilesAsync(f.Identifier).Result))) .OrderBy(f => f.Id); MetadataFile.SaveSourceFiles(sourceFiles, @"..\SourceFiles.xml"); } #endif WriteAnalyzerMarkdowns(codeAnalysisAnalyzers, new (string, string)[] { ("Roslynator.CodeAnalysis.Analyzers", "https://www.nuget.org/packages/Roslynator.CodeAnalysis.Analyzers") });
private static async Task MainAsync(string[] args, CancellationToken cancellationToken) { // A valid call must have at least one parameter (a solution file). Optionally it can include /all or /id:SAXXXX. if (args.Length < 1) { PrintHelp(); } else { bool applyChanges = args.Contains("/apply"); if (applyChanges) { if (!args.Contains("/fixall")) { Console.Error.WriteLine("Error: /apply can only be used with /fixall"); return; } } MSBuildLocator.RegisterDefaults(); Stopwatch stopwatch = Stopwatch.StartNew(); var analyzers = GetAllAnalyzers(); analyzers = FilterAnalyzers(analyzers, args).ToImmutableArray(); if (analyzers.Length == 0) { PrintHelp(); return; } var properties = new Dictionary <string, string> { // This property ensures that XAML files will be compiled in the current AppDomain // rather than a separate one. Any tasks isolated in AppDomains or tasks that create // AppDomains will likely not work due to https://github.com/Microsoft/MSBuildLocator/issues/16. { "AlwaysCompileMarkupFilesInSeparateDomain", bool.FalseString }, }; MSBuildWorkspace workspace = MSBuildWorkspace.Create(); string solutionPath = args.SingleOrDefault(i => !i.StartsWith("/", StringComparison.Ordinal)); Solution solution = await workspace.OpenSolutionAsync(solutionPath, cancellationToken : cancellationToken).ConfigureAwait(false); Console.WriteLine($"Loaded solution in {stopwatch.ElapsedMilliseconds}ms"); if (args.Contains("/stats")) { List <Project> csharpProjects = solution.Projects.Where(i => i.Language == LanguageNames.CSharp).ToList(); Console.WriteLine("Number of projects:\t\t" + csharpProjects.Count); Console.WriteLine("Number of documents:\t\t" + csharpProjects.Sum(x => x.DocumentIds.Count)); var statistics = await GetAnalyzerStatisticsAsync(csharpProjects, cancellationToken).ConfigureAwait(true); Console.WriteLine("Number of syntax nodes:\t\t" + statistics.NumberofNodes); Console.WriteLine("Number of syntax tokens:\t" + statistics.NumberOfTokens); Console.WriteLine("Number of syntax trivia:\t" + statistics.NumberOfTrivia); } stopwatch.Restart(); bool force = args.Contains("/force"); var diagnostics = await GetAnalyzerDiagnosticsAsync(solution, analyzers, force, cancellationToken).ConfigureAwait(true); var allDiagnostics = diagnostics.SelectMany(i => i.Value).ToImmutableArray(); Console.WriteLine($"Found {allDiagnostics.Length} diagnostics in {stopwatch.ElapsedMilliseconds}ms"); bool testDocuments = args.Contains("/editperf") || args.Any(arg => arg.StartsWith("/editperf:")); if (testDocuments) { Func <string, bool> documentMatch = _ => true; string matchArg = args.FirstOrDefault(arg => arg.StartsWith("/editperf:")); if (matchArg != null) { Regex expression = new Regex(matchArg.Substring("/editperf:".Length), RegexOptions.Compiled | RegexOptions.IgnoreCase); documentMatch = documentPath => expression.IsMatch(documentPath); } int iterations = 10; string iterationsArg = args.FirstOrDefault(arg => arg.StartsWith("/edititer:")); if (iterationsArg != null) { iterations = int.Parse(iterationsArg.Substring("/edititer:".Length)); } var projectPerformance = new Dictionary <ProjectId, double>(); var documentPerformance = new Dictionary <DocumentId, DocumentAnalyzerPerformance>(); foreach (var projectId in solution.ProjectIds) { Project project = solution.GetProject(projectId); if (project.Language != LanguageNames.CSharp) { continue; } foreach (var documentId in project.DocumentIds) { var document = project.GetDocument(documentId); if (!documentMatch(document.FilePath)) { continue; } var currentDocumentPerformance = await TestDocumentPerformanceAsync(analyzers, project, documentId, iterations, force, cancellationToken).ConfigureAwait(false); Console.WriteLine($"{document.FilePath ?? document.Name}: {currentDocumentPerformance.EditsPerSecond:0.00}"); documentPerformance.Add(documentId, currentDocumentPerformance); } double sumOfDocumentAverages = documentPerformance.Where(x => x.Key.ProjectId == projectId).Sum(x => x.Value.EditsPerSecond); double documentCount = documentPerformance.Where(x => x.Key.ProjectId == projectId).Count(); if (documentCount > 0) { projectPerformance[project.Id] = sumOfDocumentAverages / documentCount; } } var slowestFiles = documentPerformance.OrderBy(pair => pair.Value.EditsPerSecond).GroupBy(pair => pair.Key.ProjectId); Console.WriteLine("Slowest files in each project:"); foreach (var projectGroup in slowestFiles) { Console.WriteLine($" {solution.GetProject(projectGroup.Key).Name}"); foreach (var pair in projectGroup.Take(5)) { var document = solution.GetDocument(pair.Key); Console.WriteLine($" {document.FilePath ?? document.Name}: {pair.Value.EditsPerSecond:0.00}"); } } foreach (var projectId in solution.ProjectIds) { double averageEditsInProject; if (!projectPerformance.TryGetValue(projectId, out averageEditsInProject)) { continue; } Project project = solution.GetProject(projectId); Console.WriteLine($"{project.Name} ({project.DocumentIds.Count} documents): {averageEditsInProject:0.00} edits per second"); } } foreach (var group in allDiagnostics.GroupBy(i => i.Id).OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase)) { Console.WriteLine($" {group.Key}: {group.Count()} instances"); // Print out analyzer diagnostics like AD0001 for analyzer exceptions if (group.Key.StartsWith("AD", StringComparison.Ordinal)) { foreach (var item in group) { Console.WriteLine(item); } } } string logArgument = args.FirstOrDefault(x => x.StartsWith("/log:")); if (logArgument != null) { string fileName = logArgument.Substring(logArgument.IndexOf(':') + 1); WriteDiagnosticResults(diagnostics.SelectMany(i => i.Value.Select(j => Tuple.Create(i.Key, j))).ToImmutableArray(), fileName); } if (args.Contains("/codefixes")) { await TestCodeFixesAsync(stopwatch, solution, allDiagnostics, cancellationToken).ConfigureAwait(true); } if (args.Contains("/fixall")) { await TestFixAllAsync(stopwatch, solution, diagnostics, applyChanges, cancellationToken).ConfigureAwait(true); } } }
private static async Task <int> Main(string[] args) { // TODO: Figure out why `dotnet run` from generateapis.sh is sending 6 args instead of 3 as in: arg1 arg2 arg3 arg1 arg2 arg3 if (args.Length < 3) { Console.WriteLine("Arguments: <project file> <api client name> <user client name>"); return(1); } var projectFile = args[0]; var apiClientName = args[1]; var userClientName = args[2]; var workspace = MSBuildWorkspace.Create(new Dictionary <string, string> { ["TargetFramework"] = "net45" }); Project project; try { project = await workspace.OpenProjectAsync(projectFile); } catch (FileNotFoundException) { Console.WriteLine($"Could not find project file {projectFile}"); return(2); } var compilation = await project.GetCompilationAsync(); var symbols = compilation.GetSymbolsWithName(name => name == apiClientName, SymbolFilter.Type).ToList(); if (symbols.Count != 1) { Console.WriteLine($"Could not find type {apiClientName}"); var errors = compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); if (errors.Count != 0) { Console.WriteLine($"Errors: {errors.Count}, first error: {errors[0]}"); } return(2); } var apiClientSymbol = (INamedTypeSymbol)symbols[0]; // Find the API client from a generated file (there should be only one). var generatedApiClientSyntax = apiClientSymbol.DeclaringSyntaxReferences .Select(syntaxReference => syntaxReference.GetSyntax()) .Cast <ClassDeclarationSyntax>() .SingleOrDefault( syntax => syntax.SyntaxTree.GetRoot().GetLeadingTrivia().ToFullString().Contains("// Generated code. DO NOT EDIT!")); if (generatedApiClientSyntax == null) { Console.WriteLine($"Could not find an auto-generated file containing the {apiClientName} definition"); return(3); } var syntaxTree = generatedApiClientSyntax.SyntaxTree; var semanticModel = compilation.GetSemanticModel(syntaxTree); var generator = SyntaxGenerator.GetGenerator(project.GetDocument(syntaxTree)); var requestMethodRewriter = new RequestMethodRewriter(semanticModel); var nonRequestMethodRewriter = new ClientMethodRewriter(semanticModel); var requestMethodToImplRewriter = new RequestMethodToImplRewriter(); var convertToAsyncCancellationTokenOverload = new ConvertToAsyncCancellationTokenOverloadRewriter(); var userClientSyntax = (ClassDeclarationSyntax)generator.ClassDeclaration( userClientName, accessibility: Accessibility.Public, modifiers: DeclarationModifiers.Partial) .WithLeadingTrivia(generatedApiClientSyntax.GetLeadingTrivia()); var userClientImplSyntax = (ClassDeclarationSyntax)generator.ClassDeclaration( userClientName + "Impl", accessibility: Accessibility.Public, modifiers: DeclarationModifiers.Sealed | DeclarationModifiers.Partial, baseType: ParseTypeName(userClientName)) .WithLeadingTrivia(generatedApiClientSyntax.GetLeadingTrivia()); // Copy the request methods from the API client with the user client. We only require these to be copied since // we already have handwritten flattening overloads to change ByteString to BigtableByteString. foreach (var methodSyntax in generatedApiClientSyntax.Members.OfType <MethodDeclarationSyntax>()) { var method = semanticModel.GetDeclaredSymbol(methodSyntax); if (method.DeclaredAccessibility != Accessibility.Public || method.Parameters.IsEmpty) { continue; } if (method.Parameters.Length == 2 && method.Parameters[0].Type.Name.EndsWith("Request")) { var clientMethod = (MethodDeclarationSyntax)requestMethodRewriter.Visit(methodSyntax); userClientSyntax = userClientSyntax.AddMembers(clientMethod); if (method.Parameters[1].Type.Name.EndsWith(nameof(CallSettings))) { var clientImplMethod = (MethodDeclarationSyntax)requestMethodToImplRewriter.Visit(clientMethod); if (s_customStreamMethods.TryGetValue(method.Name, out var customStreamMethodInfo) && customStreamMethodInfo.SplitSyncAndAsync) { var asyncMethod = clientMethod.ToAsync(); userClientSyntax = userClientSyntax.AddMembers(asyncMethod); var asyncMethodWithCancellationToken = (MethodDeclarationSyntax)convertToAsyncCancellationTokenOverload.Visit(asyncMethod); userClientSyntax = userClientSyntax.AddMembers(asyncMethodWithCancellationToken); var clientImplSyncMethod = clientImplMethod.WithBodySafe( Task().Member(nameof(System.Threading.Tasks.Task.Run)) .Invoke(Lambda(asyncMethod.Invoke(clientImplMethod.ParameterList.AsArguments()))) .Member(nameof(gax::TaskExtensions.ResultWithUnwrappedExceptions)).Invoke()); userClientImplSyntax = userClientImplSyntax.AddMembers(clientImplSyncMethod); var clientImplAsyncMethod = clientImplMethod.ToAsync(); userClientImplSyntax = userClientImplSyntax.AddMembers(clientImplAsyncMethod); } else { userClientImplSyntax = userClientImplSyntax.AddMembers(clientImplMethod); } } } else if ( method.Name != "Create" && method.Name != "CreateAsync" && !s_customStreamMethods.ContainsKey(method.Name) && !method.Parameters.Any(p => p.Type.Name == "ByteString")) { // TODO: We could also have this remap to BigtableByteString automatically, but we currently // have some validations for most methods with ByteStrings which I think we's lose by // autogenerating at the moment. // For any other methods which aren't custom streaming methods and which don't use ByteString, // which we remap to BigtableByteString, copy them (with some small fix ups) into the generated // client. userClientSyntax = userClientSyntax.AddMembers( (MethodDeclarationSyntax)nonRequestMethodRewriter.Visit(methodSyntax)); } } // Create a CompilationUnitSyntax from the Usings node of the original file, which will also contain the // copyright notice and generated code warnings in its leading trivia. // We also need a using directive for GAX, so that we can use ResultWithUnwrappedExceptions. var usings = syntaxTree.GetCompilationUnitRoot().Usings .Add(UsingDirective(ParseName(typeof(gax::TaskExtensions).Namespace))); var compilationUnit = CompilationUnit().WithUsings(usings); // Add in the namespace with the ...Client and ...ClientImpl classes. compilationUnit = compilationUnit.AddMembers( (NamespaceDeclarationSyntax)generator.NamespaceDeclaration( apiClientSymbol.ContainingNamespace.ToDisplayString(), userClientSyntax, userClientImplSyntax)); // Use idiomatic formatting for the project. compilationUnit = (CompilationUnitSyntax)Formatter.Format( compilationUnit, workspace, workspace.Options.WithChangedOption(FormattingOptions.NewLine, LanguageNames.CSharp, "\n")); var resultText = compilationUnit.ToFullString(); try { var resultPath = Path.Combine(Path.GetDirectoryName(projectFile), $"{userClientName}.cs"); File.WriteAllText(resultPath, resultText); } catch (Exception e) { Console.WriteLine($"Could not write the auto-generated {userClientName}:\n{e}"); return(4); } return(0); }
protected void AssertFailures(MSBuildWorkspace workspace, params string[] expectedFailures) { AssertEx.Equal(expectedFailures, workspace.Diagnostics.Where(d => d.Kind == WorkspaceDiagnosticKind.Failure).Select(d => d.Message)); }
static PlantUMLDiagramGenerator() { MSBuildLocator.RegisterDefaults(); workspace = MSBuildWorkspace.Create(); }
public static async Task <int> FormatWorkspaceAsync(ILogger logger, string solutionOrProjectPath, bool isSolution, bool logAllWorkspaceWarnings, bool saveFormattedFiles, CancellationToken cancellationToken) { logger.LogInformation(string.Format(Resources.Formatting_code_files_in_workspace_0, solutionOrProjectPath)); logger.LogTrace(Resources.Loading_workspace); var loggedWarningCount = 0; var exitCode = 1; var workspaceStopwatch = Stopwatch.StartNew(); var properties = new Dictionary <string, string>(StringComparer.Ordinal) { // This property ensures that XAML files will be compiled in the current AppDomain // rather than a separate one. Any tasks isolated in AppDomains or tasks that create // AppDomains will likely not work due to https://github.com/Microsoft/MSBuildLocator/issues/16. { "AlwaysCompileMarkupFilesInSeparateDomain", bool.FalseString }, }; var codingConventionsManager = CodingConventionsManagerFactory.CreateCodingConventionsManager(); using (var workspace = MSBuildWorkspace.Create(properties)) { workspace.WorkspaceFailed += LogWorkspaceWarnings; var projectPath = string.Empty; if (isSolution) { await workspace.OpenSolutionAsync(solutionOrProjectPath, cancellationToken : cancellationToken).ConfigureAwait(false); } else { await workspace.OpenProjectAsync(solutionOrProjectPath, cancellationToken : cancellationToken).ConfigureAwait(false); projectPath = solutionOrProjectPath; } logger.LogTrace(Resources.Workspace_loaded_in_0_ms, workspaceStopwatch.ElapsedMilliseconds); workspaceStopwatch.Restart(); int fileCount; int filesFormatted; (exitCode, fileCount, filesFormatted) = await FormatFilesInWorkspaceAsync(logger, workspace, projectPath, codingConventionsManager, saveFormattedFiles, cancellationToken).ConfigureAwait(false); logger.LogDebug(Resources.Formatted_0_of_1_files_in_2_ms, filesFormatted, fileCount, workspaceStopwatch.ElapsedMilliseconds); } logger.LogInformation(Resources.Format_complete); return(exitCode); void LogWorkspaceWarnings(object sender, WorkspaceDiagnosticEventArgs args) { if (args.Diagnostic.Kind == WorkspaceDiagnosticKind.Failure) { return; } logger.LogWarning(args.Diagnostic.Message); if (!logAllWorkspaceWarnings) { loggedWarningCount++; if (loggedWarningCount == MaxLoggedWorkspaceWarnings) { logger.LogWarning(Resources.Maximum_number_of_workspace_warnings_to_log_has_been_reached_Set_the_verbosity_option_to_the_diagnostic_level_to_see_all_warnings); ((MSBuildWorkspace)sender).WorkspaceFailed -= LogWorkspaceWarnings; } } } }
public SolutionData(Solution solution, MSBuildWorkspace buildWorkspace, SolutionConfiguration configuration) { Configuration = configuration; Workspace = buildWorkspace; Solution = solution; }
static async Task <List <KeyValuePair <IMethodSymbol, List <EnumUse> > > > Run(string[] args) { var securityUsagesCache = new Dictionary <ISymbol, List <EnumUse> >(); // load and compile the solution string solutionPath = args[0]; var msWorkspace = MSBuildWorkspace.Create(); var solution = await msWorkspace.OpenSolutionAsync(solutionPath); var compiles = solution.Projects.ToDictionary(i => i, i => i.GetCompilationAsync().Result); // find all 'Controller's in the web project var webProject = solution.Projects.Single(i => i.Name.EndsWith("Web")); var webCompile = compiles[webProject]; var controllers = webCompile.GetSymbolsWithName(i => i.EndsWith("Controller")).OfType <INamedTypeSymbol>().ToList(); var data = new List <KeyValuePair <IMethodSymbol, List <EnumUse> > >(); foreach (var controller in controllers) { var actions = controller.GetMembers().OfType <IMethodSymbol>().Where(i => i.DeclaredAccessibility == Accessibility.Public && i.MethodKind == MethodKind.Ordinary).ToList(); foreach (var action in actions) { var usages = await GetSecurityUsages(action); data.Add(new KeyValuePair <IMethodSymbol, List <EnumUse> >(action, usages)); } } return(data); async Task <List <EnumUse> > GetSecurityUsages(ISymbol method) { List <EnumUse> list; if (securityUsagesCache.TryGetValue(method, out list)) { return(list); } // load empty value to avoid recursion issues securityUsagesCache.Add(method, new List <EnumUse>()); try { list = await RawGetSecurityUsages(method); securityUsagesCache[method] = list; // replace empty value return(list); } catch { // remove dummy value so we'll retry later securityUsagesCache.Remove(method); throw; } } async Task <List <EnumUse> > RawGetSecurityUsages(ISymbol method) { //Console.WriteLine($"Checking {method}"); var usages = new List <EnumUse>(); var x = (IMethodSymbol)await SymbolFinder.FindSourceDefinitionAsync(method, solution); if (null == x) { return(usages); } var proj = solution.GetProject(x.ContainingAssembly); if (null == proj) { return(usages); } var compiled = compiles[proj]; foreach (var reference in x.DeclaringSyntaxReferences) { var node = await reference.GetSyntaxAsync(); var model = compiled.GetSemanticModel(node.SyntaxTree); var uses = node.DescendantNodesAndSelf().OfType <MemberAccessExpressionSyntax>() .Where(i => i.Expression is IdentifierNameSyntax && i.Expression.ToString() == "SecurityComponentEnum") .Where(i => !i.AncestorsAndSelf().OfType <AttributeSyntax>().Any()) ; foreach (var use in uses) { var nearestInvoke = use.AncestorsAndSelf().OfType <InvocationExpressionSyntax>().FirstOrDefault(); if (null != nearestInvoke) { // point to attach debugger to figure out how to deal with multi-line stuff if (nearestInvoke.ToString().Contains("\n")) { } } usages.Add(new EnumUse { Method = method, Call = nearestInvoke ?? (SyntaxNode)use, Use = use }); } var calls = node.DescendantNodesAndSelf().OfType <InvocationExpressionSyntax>().ToList(); foreach (var call in calls) { var callTarget = model.GetSymbolInfo(call); foreach (var candidate in callTarget.CandidateSymbols) { // it seems like we should be able to call SymbolFinder.FindImplementationsAsync directly on candidate, but I get no results // so instead, we call it on the type, then find members with the right name. // this means we recurse to *all* overloads... var classes = await SymbolFinder.FindImplementationsAsync(candidate.ContainingType, solution); foreach (ITypeSymbol cls in classes) { foreach (var implementation in cls.GetMembers(candidate.Name)) { usages.AddRange(await GetSecurityUsages(implementation)); } } usages.AddRange(await GetSecurityUsages(candidate)); } } } return(usages); } }
public Tern(MSBuildWorkspace workspace, string projectFilePath) { _workspace = workspace; _projectFilePath = projectFilePath; }