private void runSavedFileAnalysis(SourceFile file, Configuration currentConfig)
        {
            Debug.Assert(currentConfig != null);

            var configuredFiles = new SourceFilesWithConfiguration();

            configuredFiles.addOrUpdateFile(file);
            configuredFiles.Configuration = currentConfig;

            _ = System.Threading.Tasks.Task.Run(async delegate
            {
                await System.Threading.Tasks.Task.Delay(750);
                await JoinableTaskFactory.SwitchToMainThreadAsync();
                runAnalysis(new List <SourceFilesWithConfiguration> {
                    configuredFiles
                }, true);
            });
        }
        // Looks at the project item. If it's a supported file type it's added to the list, and if it's a filter it keeps digging into it.
        private async Task scanProjectItemForSourceFilesAsync(ProjectItem item, SourceFilesWithConfiguration configuredFiles, Configuration configuration, Project project)
        {
            await JoinableTaskFactory.SwitchToMainThreadAsync();

            var itemType = await getTypeOfProjectItemAsync(item);

            if (itemType == ProjectItemType.folder)
            {
                foreach (ProjectItem subItem in item.ProjectItems)
                {
                    await scanProjectItemForSourceFilesAsync(subItem, configuredFiles, configuration, project);
                }
            }
            else if (itemType == ProjectItemType.headerFile || itemType == ProjectItemType.cFile || itemType == ProjectItemType.cppFile)
            {
                var itemName = item.Name;

                if (item.FileCount == 0)
                {
                    Debug.Fail("isCppFileAsync(item) is true, but item.FileCount is null!");
                    return;
                }

                var itemFileName = item.FileNames[1];
                if (!configuredFiles.Exists(itemFileName))
                {
                    // Don't bother rebuilding the entire definition if it already exists.
                    SourceFile sourceFile = await createSourceFileAsync(item);

                    if (sourceFile != null)
                    {
                        configuredFiles.addOrUpdateFile(sourceFile);
                        scanProgressUpdated(configuredFiles.Count());
                    }
                }
            }
        }
        private async Task checkProjectsAsync(List <Project> projects)
        {
            Debug.Assert(projects.Any());
            setMenuState(true);

            List <SourceFilesWithConfiguration> allConfiguredFiles = new List <SourceFilesWithConfiguration>();

            foreach (var project in projects)
            {
                await JoinableTaskFactory.SwitchToMainThreadAsync();

                Configuration config = await getConfigurationAsync(project);

                if (config == null)
                {
                    MessageBox.Show("No valid configuration in project " + project.Name);
                    continue;
                }

                SourceFilesWithConfiguration sourceFiles = new SourceFilesWithConfiguration();
                sourceFiles.Configuration = config;

                foreach (ProjectItem projectItem in project.ProjectItems)
                {
                    await scanProjectItemForSourceFilesAsync(projectItem, sourceFiles, config, project);
                }

                // Although we're using the same base configuration, it's possible for each file to override that.
                // Group files into separate configs based on actual parameters. We'll be iterating in reverse order so
                // reverse the list first to keep the final order the same.
                List <SourceFile> allSourceFiles = sourceFiles.Files.ToList();
                allSourceFiles.Reverse();

                while (allSourceFiles.Any())
                {
                    SourceFilesWithConfiguration newConfig = new SourceFilesWithConfiguration();
                    newConfig.Configuration = config;

                    SourceFile templateFile = allSourceFiles.Last();
                    newConfig.addOrUpdateFile(templateFile);
                    allSourceFiles.RemoveAt(allSourceFiles.Count - 1);

                    for (int i = allSourceFiles.Count - 1; i >= 0; i--)
                    {
                        SourceFile otherFile = allSourceFiles[i];

                        if (otherFile.Macros.All(templateFile.Macros.Contains) && templateFile.Macros.All(otherFile.Macros.Contains) &&
                            otherFile.MacrosToUndefine.All(templateFile.MacrosToUndefine.Contains) && templateFile.MacrosToUndefine.All(otherFile.MacrosToUndefine.Contains) &&
                            otherFile.IncludePaths.All(templateFile.IncludePaths.Contains) && templateFile.IncludePaths.All(otherFile.IncludePaths.Contains) &&
                            otherFile.ProjectName == templateFile.ProjectName
                            )
                        {
                            newConfig.addOrUpdateFile(otherFile);
                            allSourceFiles.RemoveAt(i);
                        }
                    }

                    if (newConfig.Any())
                    {
                        allConfiguredFiles.Add(newConfig);
                    }
                }
            }

            _ = JoinableTaskFactory.RunAsync(async() => {
                await JoinableTaskFactory.SwitchToMainThreadAsync();

                MainToolWindow.Instance.ContentsType = ICodeAnalyzer.AnalysisType.ProjectAnalysis;
                MainToolWindow.Instance.showIfWindowNotCreated();
            });

            scanProgressUpdated(-1);
            runAnalysis(allConfiguredFiles, false);
        }