private string getCPPCheckArgs(SourceFilesWithConfiguration configuredFiles, bool analysisOnSavedFile, string tempFileName) { if (!configuredFiles.Any()) { Debug.Fail("Empty files list!"); return(""); } Debug.Assert(_numCores > 0); String cppheckargs = Properties.Settings.Default.DefaultArguments; if (Properties.Settings.Default.SeveritiesString.Length != 0) { cppheckargs += " --enable=" + Properties.Settings.Default.SeveritiesString; } HashSet <string> suppressions = new HashSet <string>(Properties.Settings.Default.SuppressionsString.Split(',')); suppressions.Add("unmatchedSuppression"); HashSet <string> skippedFilesMask = new HashSet <string>(); HashSet <string> skippedIncludeMask = new HashSet <string>(); SuppressionsInfo unitedSuppressionsInfo = readSuppressions(ICodeAnalyzer.SuppressionStorage.Global); unitedSuppressionsInfo.UnionWith(readSuppressions(ICodeAnalyzer.SuppressionStorage.Solution)); var filesToAnalyze = configuredFiles.Files; // Creating the list of all different project locations (no duplicates) HashSet <string> projectPaths = new HashSet <string>(); // enforce uniqueness on the list of project paths foreach (var file in filesToAnalyze) { projectPaths.Add(file.BaseProjectPath); } Debug.Assert(projectPaths.Count == 1); _projectBasePath = projectPaths.First(); _projectName = filesToAnalyze.First().ProjectName; // Creating the list of all different suppressions (no duplicates) foreach (var path in projectPaths) { unitedSuppressionsInfo.UnionWith(readSuppressions(SuppressionStorage.Project, path, filesToAnalyze.First().ProjectName)); } cppheckargs += (" --relative-paths=\"" + _projectBasePath + "\""); cppheckargs += (" -j " + _numCores.ToString()); if (Properties.Settings.Default.InconclusiveChecksEnabled) { cppheckargs += " --inconclusive "; } suppressions.UnionWith(unitedSuppressionsInfo.SuppressionLines); foreach (string suppression in suppressions) { if (!String.IsNullOrWhiteSpace(suppression)) { cppheckargs += (" --suppress=" + suppression); } } if (!(analysisOnSavedFile && Properties.Settings.Default.IgnoreIncludePaths)) { // We only add include paths once, and then specify a set of files to check HashSet <string> includePaths = new HashSet <string>(); foreach (var file in filesToAnalyze) { if (!matchMasksList(file.FilePath, unitedSuppressionsInfo.SkippedFilesMask)) { includePaths.UnionWith(file.IncludePaths); } } includePaths.Add(filesToAnalyze.First().BaseProjectPath); // Fix for #60 foreach (string path in includePaths) { if (!matchMasksList(path, unitedSuppressionsInfo.SkippedIncludesMask)) { String includeArgument = " -I\"" + path + "\""; cppheckargs = cppheckargs + " " + includeArgument; } } } using (StreamWriter tempFile = new StreamWriter(tempFileName)) { foreach (SourceFile file in filesToAnalyze) { if (!matchMasksList(file.FilePath, unitedSuppressionsInfo.SkippedFilesMask)) { tempFile.WriteLine(file.FilePath); } } } cppheckargs += " --file-list=\"" + tempFileName + "\""; if ((analysisOnSavedFile && Properties.Settings.Default.FileOnlyCheckCurrentConfig) || (!analysisOnSavedFile && Properties.Settings.Default.ProjectOnlyCheckCurrentConfig)) // Only checking current macros configuration (for speed) { cppheckargs = cppheckargs.Replace("--force", ""); // Creating the list of all different macros (no duplicates) HashSet <string> macros = new HashSet <string>(); // TODO: handle /Zc:__cplusplus // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ macros.Add("__cplusplus=199711L"); // At least in VS2012, this is still 199711L // Assuming all files passed here are from the same project / same toolset, which should be true, so peeking the first file for global settings switch (filesToAnalyze.First().vcCompilerVersion) { case SourceFile.VCCompilerVersion.vc2003: macros.Add("_MSC_VER=1310"); break; case SourceFile.VCCompilerVersion.vc2005: macros.Add("_MSC_VER=1400"); break; case SourceFile.VCCompilerVersion.vc2008: macros.Add("_MSC_VER=1500"); break; case SourceFile.VCCompilerVersion.vc2010: macros.Add("_MSC_VER=1600"); break; case SourceFile.VCCompilerVersion.vc2012: macros.Add("_MSC_VER=1700"); break; case SourceFile.VCCompilerVersion.vc2013: macros.Add("_MSC_VER=1800"); break; case SourceFile.VCCompilerVersion.vc2015: macros.Add("_MSC_VER=1900"); break; case SourceFile.VCCompilerVersion.vc2017: macros.Add("_MSC_VER=1916"); break; case SourceFile.VCCompilerVersion.vc2019: macros.Add("_MSC_VER=1926"); macros.Add("_MSC_FULL_VER=192628808"); break; } foreach (var file in filesToAnalyze) { macros.UnionWith(file.Macros); } macros.Add("WIN32"); macros.Add("_WIN32"); CPPCheckPluginPackage.Instance.JoinableTaskFactory.Run(async() => { if (await configuredFiles.is64bitConfigurationAsync()) { macros.Add("_M_X64"); macros.Add("_WIN64"); } else { macros.Add("_M_IX86"); } if (await configuredFiles.isDebugConfigurationAsync()) { macros.Add("_DEBUG"); } }); foreach (string macro in macros) { if (!String.IsNullOrEmpty(macro) && !macro.Contains(" ") /* macros with spaces are invalid in VS */) { String macroArgument = " -D" + macro; cppheckargs += macroArgument; } } HashSet <string> macrosToUndefine = new HashSet <string>(); foreach (var file in filesToAnalyze) { macrosToUndefine.UnionWith(file.MacrosToUndefine); } foreach (string macro in macrosToUndefine) { if (!String.IsNullOrEmpty(macro) && !macro.Contains(" ") /* macros with spaces are invalid in VS */) { String macroUndefArgument = " -U" + macro; cppheckargs += macroUndefArgument; } } } else if (!cppheckargs.Contains("--force")) { cppheckargs += " --force"; } return(cppheckargs); }
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); }