Repository: Caphyon/clang-power-tools Branch: master Commit: 511648a27cf8 Files: 390 Total size: 1.5 MB Directory structure: gitextract_1cs8fm3_/ ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── Build-ClangPowerTools.yml │ └── Run-ClangPowerTools-tests.yml ├── .gitignore ├── ClangPowerTools/ │ ├── Automation/ │ │ ├── full-llvm-update-instructions.md │ │ ├── get-tidy-checks-and-format.ps1 │ │ ├── input_checks.txt │ │ └── update_clang-format.ps1 │ ├── CPTReleases/ │ │ └── IncrementRevisionNumber.ps1 │ ├── ClangPowerTools/ │ │ ├── ClangPowerTools.csproj │ │ ├── ClangPowerTools.csproj.bak │ │ ├── ClangPowerTools.vsct │ │ ├── ClangPowerToolsPackage.cs │ │ ├── Key.snk │ │ ├── Properties/ │ │ │ ├── AssemblyInfo.cs │ │ │ ├── Resource.Designer.cs │ │ │ └── Resource.resx │ │ ├── Tooling/ │ │ │ └── v1/ │ │ │ ├── clang-build.ps1 │ │ │ └── psClang/ │ │ │ ├── get-header-references.ps1 │ │ │ ├── get-llvm-helper.ps1 │ │ │ ├── get-llvm.ps1 │ │ │ ├── io.ps1 │ │ │ ├── itemdefinition-context.ps1 │ │ │ ├── jsondb-export.ps1 │ │ │ ├── msbuild-expression-eval.ps1 │ │ │ ├── msbuild-project-cache-repository.ps1 │ │ │ ├── msbuild-project-data.ps1 │ │ │ ├── msbuild-project-load.ps1 │ │ │ └── visualstudio-detection.ps1 │ │ ├── VSPackage.resx │ │ ├── cpt.config │ │ └── source.extension.vsixmanifest │ ├── ClangPowerTools.aip │ ├── ClangPowerTools.sln │ ├── ClangPowerToolsLib16/ │ │ ├── ClangPowerToolsLib16.csproj │ │ ├── Key.snk │ │ └── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resource.Designer.cs │ │ └── Resource.resx │ ├── ClangPowerToolsLib17/ │ │ ├── ClangPowerToolsLib17.csproj │ │ ├── Key.snk │ │ └── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resource.Designer.cs │ │ └── Resource.resx │ ├── ClangPowerToolsShared/ │ │ ├── Attributes/ │ │ │ ├── ClangCheckAttribute.cs │ │ │ ├── ClangFormatPathAttribute.cs │ │ │ └── ClangTidyPathAttribute.cs │ │ ├── Builder/ │ │ │ ├── IAsyncBuilder.cs │ │ │ └── IBuilder.cs │ │ ├── CMake/ │ │ │ └── CMakeBuilder.cs │ │ ├── ClangPowerToolsPackage.cs │ │ ├── ClangPowerToolsPackageImpl.cs │ │ ├── ClangPowerToolsShared.projitems │ │ ├── ClangPowerToolsShared.projitems.bak │ │ ├── ClangPowerToolsShared.shproj │ │ ├── Commands/ │ │ │ ├── BackgroundTidy/ │ │ │ │ ├── BackgroundTidy.cs │ │ │ │ ├── DataProcessor.cs │ │ │ │ └── PowerShellWrapperBackground.cs │ │ │ ├── BasicCommand.cs │ │ │ ├── ClangCommand.cs │ │ │ ├── CommandController.cs │ │ │ ├── CommandControllerInstance.cs │ │ │ ├── CommandIds.cs │ │ │ ├── CommandUILocation.cs │ │ │ ├── CompileCommand.cs │ │ │ ├── DocumentationHtmlCommand.cs │ │ │ ├── DocumentationMdCommand.cs │ │ │ ├── DocumentationYamlCommand.cs │ │ │ ├── FindCommand.cs │ │ │ ├── FindCommandIds.cs │ │ │ ├── FindViewMenuCommand.cs │ │ │ ├── FormatCommand.cs │ │ │ ├── IgnoreCommand.cs │ │ │ ├── IgnoreCompileCommand.cs │ │ │ ├── IgnoreFormatCommand.cs │ │ │ ├── JsonCompilationDatabaseCommand.cs │ │ │ ├── LookInMenu.cs │ │ │ ├── Models/ │ │ │ │ └── CacheProjectsItemsModel.cs │ │ │ ├── OptimizeIncludesCommand.cs │ │ │ ├── RunController.cs │ │ │ ├── SettingsCommand.cs │ │ │ ├── StopCommand.cs │ │ │ ├── TidyCommand.cs │ │ │ └── VsCommands.cs │ │ ├── Convertors/ │ │ │ ├── BooleanToGridLengthConverter.cs │ │ │ ├── BooleanToVisibilityConverter.cs │ │ │ ├── ClangFormatFallbackStyleConverter.cs │ │ │ ├── ClangFormatStyleConverter.cs │ │ │ ├── ClangGeneralAdditionalIncludesConvertor.cs │ │ │ ├── ClangTidyHeaderFiltersConvertor.cs │ │ │ └── ClangTidyUseChecksFromConvertor.cs │ │ ├── Error/ │ │ │ ├── ErrorDetector.cs │ │ │ ├── ErrorFormatter.cs │ │ │ ├── ErrorParserConstants.cs │ │ │ ├── ErrorWindowController.cs │ │ │ ├── TaskErrorModel.cs │ │ │ ├── TaskErrorModelBuilder.cs │ │ │ └── TaskErrorViewModel.cs │ │ ├── Events/ │ │ │ ├── ActiveDocumentEventArgs.cs │ │ │ ├── BoolEventArgs.cs │ │ │ ├── ClangCommandEventArgs.cs │ │ │ ├── CleanErrorListEventArgs.cs │ │ │ ├── CloseDataConnectionEventArgs.cs │ │ │ ├── CloseDataStreamingEventArgs.cs │ │ │ ├── ErrorDetectedEventArgs.cs │ │ │ ├── FormatCommandEventArgs.cs │ │ │ ├── HasEncodingErrorEventArgs.cs │ │ │ ├── JsonFilePathArgs.cs │ │ │ └── VsHierarchyDetectedEventArgs.cs │ │ ├── Executables/ │ │ │ └── Clang Format Editor.msi │ │ ├── Export Config/ │ │ │ └── TidyConfigFile.cs │ │ ├── Extensions/ │ │ │ ├── IntExtension.cs │ │ │ ├── ObjectExtension.cs │ │ │ ├── StringExtension.cs │ │ │ └── TaskExtensions.cs │ │ ├── Files Operations/ │ │ │ ├── FileChangerWatcher.cs │ │ │ ├── FileOpener.cs │ │ │ └── FilePathCollector.cs │ │ ├── Helpers/ │ │ │ ├── ActiveWindowProperties.cs │ │ │ ├── ApiUtility.cs │ │ │ ├── AutomationUtil.cs │ │ │ ├── ClangTidyCleaner.cs │ │ │ ├── DocumentHandler.cs │ │ │ ├── FileSystem.cs │ │ │ ├── FormatEditorUtility.cs │ │ │ ├── GenerateDocumentation.cs │ │ │ ├── JoinUtility.cs │ │ │ ├── LaunchCompilationDbProgrammatically.cs │ │ │ ├── ManageEncoding.cs │ │ │ ├── NetworkUtility.cs │ │ │ ├── PCHCleaner.cs │ │ │ ├── PackageUtility.cs │ │ │ ├── ProjectConfigurationHandler.cs │ │ │ ├── PropertyHandler.cs │ │ │ ├── RegistryUtility.cs │ │ │ ├── RunningDocTableEvents.cs │ │ │ ├── ScriptGenerator.cs │ │ │ ├── SettingsApi.cs │ │ │ ├── SettingsPathBuilder.cs │ │ │ ├── SolutionInfo.cs │ │ │ ├── StatusBarHandler.cs │ │ │ ├── UIUpdater.cs │ │ │ ├── VsWindowController.cs │ │ │ └── Vsix.cs │ │ ├── IgnoreActions/ │ │ │ └── IgnoreItem.cs │ │ ├── Items/ │ │ │ ├── CurrentDocument.cs │ │ │ ├── CurrentProject.cs │ │ │ ├── CurrentProjectItem.cs │ │ │ ├── CurrentSolution.cs │ │ │ ├── IItem.cs │ │ │ └── ItemsCollector.cs │ │ ├── MVVM/ │ │ │ ├── .clang-format │ │ │ ├── AutoCompleteHistory/ │ │ │ │ ├── ASTMatchers.cs │ │ │ │ └── AutoCompleteBehavior.cs │ │ │ ├── CollectionElementsCounter.cs │ │ │ ├── Command/ │ │ │ │ └── RelayCommand.cs │ │ │ ├── Commands/ │ │ │ │ ├── FileCommand.cs │ │ │ │ ├── RelayCommand.cs │ │ │ │ ├── TidyDiffCommand.cs │ │ │ │ └── VSThemeCommand.cs │ │ │ ├── CommonSettingsFunctionality.cs │ │ │ ├── Constants/ │ │ │ │ ├── CPPKeywords.cs │ │ │ │ ├── ComboBoxConstants.cs │ │ │ │ ├── EncodingConstants.cs │ │ │ │ ├── FormatEditorConstants.cs │ │ │ │ ├── IconResourceConstants.cs │ │ │ │ ├── LLVMVersionsAlternate.cs │ │ │ │ ├── LlvmConstants.cs │ │ │ │ ├── LlvmVersions.cs │ │ │ │ ├── MatchConstants.cs │ │ │ │ ├── PathConstants.cs │ │ │ │ ├── PsUpdaterConstants.cs │ │ │ │ ├── ResourceConstants.cs │ │ │ │ ├── ThemeConstants.cs │ │ │ │ ├── TidyConstants.cs │ │ │ │ └── UIElementsConstants.cs │ │ │ ├── Controllers/ │ │ │ │ ├── AccountController.cs │ │ │ │ ├── FindController.cs │ │ │ │ ├── FormatEditorController.cs │ │ │ │ ├── FreeTrialController.cs │ │ │ │ ├── LicenseController.cs │ │ │ │ ├── LlvmController.cs │ │ │ │ ├── LookInMenuController.cs │ │ │ │ └── TidyToolWindowController.cs │ │ │ ├── FindToolWindowHandler.cs │ │ │ ├── Interfaces/ │ │ │ │ ├── IAccountValidator.cs │ │ │ │ ├── IDownload.cs │ │ │ │ ├── IInstall.cs │ │ │ │ ├── ILicense.cs │ │ │ │ ├── IView.cs │ │ │ │ └── IViewMatche.cs │ │ │ ├── LicenseValidation/ │ │ │ │ ├── CommercialLicenseValidator.cs │ │ │ │ ├── LicenseType.cs │ │ │ │ ├── LocalLicenseValidator.cs │ │ │ │ ├── PersonalLicenseValidator.cs │ │ │ │ └── Token.cs │ │ │ ├── LlvmUri.cs │ │ │ ├── Models/ │ │ │ │ ├── AccountApiModel.cs │ │ │ │ ├── AccountModel.cs │ │ │ │ ├── CompilerSettingsModel.cs │ │ │ │ ├── FileModel.cs │ │ │ │ ├── FormatSettingsModel.cs │ │ │ │ ├── GeneralSettingsModel.cs │ │ │ │ ├── InputDataModel.cs │ │ │ │ ├── LicenseModel.cs │ │ │ │ ├── LlvmModel.cs │ │ │ │ ├── LlvmSettingsModel.cs │ │ │ │ ├── MessageModel.cs │ │ │ │ ├── SelectedFileModel.cs │ │ │ │ ├── TidyCheckModel.cs │ │ │ │ ├── TidySettingsModel.cs │ │ │ │ ├── ToggleModel.cs │ │ │ │ ├── TokenModel.cs │ │ │ │ ├── ToolWindowModels/ │ │ │ │ │ ├── AutoCompleteHistoryModel.cs │ │ │ │ │ ├── ComponentVisibility.cs │ │ │ │ │ ├── CountStateFilesModel.cs │ │ │ │ │ ├── CustomMatchesModel.cs │ │ │ │ │ ├── DefaultArgsModel.cs │ │ │ │ │ ├── FileType.cs │ │ │ │ │ ├── FindControllerModel.cs │ │ │ │ │ ├── FindToolWindowModel.cs │ │ │ │ │ ├── IconModel.cs │ │ │ │ │ └── TidyToolWindowModel.cs │ │ │ │ └── UserModel.cs │ │ │ ├── OldSettings/ │ │ │ │ ├── ClangFormatPathValue.cs │ │ │ │ ├── ClangTidyPathValue.cs │ │ │ │ ├── HeaderFiltersValue.cs │ │ │ │ └── OldModels/ │ │ │ │ ├── ClangFormatOptions.cs │ │ │ │ ├── ClangOptions.cs │ │ │ │ ├── ClangTidyOptions.cs │ │ │ │ └── DefaultOptions.cs │ │ │ ├── PreinstalledLlvm.cs │ │ │ ├── Provider/ │ │ │ │ ├── FindToolWindowProvider.cs │ │ │ │ └── SettingsProvider.cs │ │ │ ├── SettingsHandler.cs │ │ │ ├── SettingsTooltips.cs │ │ │ ├── TextManipulation.cs │ │ │ ├── TidyChecks.cs │ │ │ ├── TidyChecksDefault.cs │ │ │ ├── ViewModels/ │ │ │ │ ├── AboutSettingsViewModel.cs │ │ │ │ ├── AutoCompleteHistoryViewModel.cs │ │ │ │ ├── CompilerSettingsViewModel.cs │ │ │ │ ├── DetectedStyleInfoViewModel.cs │ │ │ │ ├── EncodingErrorViewModel.cs │ │ │ │ ├── FeedbackViewModel.cs │ │ │ │ ├── FindToolWindowViewModel.cs │ │ │ │ ├── FolderExplorerViewModel.cs │ │ │ │ ├── FormatSettingsViewModel.cs │ │ │ │ ├── InputDataViewModel.cs │ │ │ │ ├── InputMultipleDataViewModel.cs │ │ │ │ ├── LicenseViewModel.cs │ │ │ │ ├── LlvmSettingsViewModel.cs │ │ │ │ ├── LoginViewModel.cs │ │ │ │ ├── ReleaseNotesViewModel.cs │ │ │ │ ├── SettingsViewModel.cs │ │ │ │ ├── TidyChecksViewModel.cs │ │ │ │ ├── TidySettingsViewModel.cs │ │ │ │ ├── TidyToolWindowViewModel.cs │ │ │ │ ├── ToggleMultipleDataViewModel.cs │ │ │ │ └── TrialExpiredViewModel.cs │ │ │ ├── Views/ │ │ │ │ ├── AboutSettingsView.xaml │ │ │ │ ├── AboutSettingsView.xaml.cs │ │ │ │ ├── CMakeBetaWarning.xaml │ │ │ │ ├── CMakeBetaWarning.xaml.cs │ │ │ │ ├── CompilerSettingsView.xaml │ │ │ │ ├── CompilerSettingsView.xaml.cs │ │ │ │ ├── Components/ │ │ │ │ │ ├── BuyNowFooter.xaml │ │ │ │ │ ├── BuyNowFooter.xaml.cs │ │ │ │ │ ├── InputList.xaml │ │ │ │ │ ├── InputList.xaml.cs │ │ │ │ │ ├── MessageBanner.xaml │ │ │ │ │ ├── MessageBanner.xaml.cs │ │ │ │ │ ├── ThreePieceButton.xaml │ │ │ │ │ ├── ThreePieceButton.xaml.cs │ │ │ │ │ ├── ThreePieceComponent.xaml │ │ │ │ │ └── ThreePieceComponent.xaml.cs │ │ │ │ ├── DialogWindow.cs │ │ │ │ ├── EncodingErrorView.xaml │ │ │ │ ├── EncodingErrorView.xaml.cs │ │ │ │ ├── FeedbackView.xaml │ │ │ │ ├── FeedbackView.xaml.cs │ │ │ │ ├── FindToolWindowView.xaml │ │ │ │ ├── FindToolWindowView.xaml.cs │ │ │ │ ├── FolderExplorerView.xaml │ │ │ │ ├── FolderExplorerView.xaml.cs │ │ │ │ ├── FormatEditorWarning.xaml │ │ │ │ ├── FormatEditorWarning.xaml.cs │ │ │ │ ├── FormatSettingsView.xaml │ │ │ │ ├── FormatSettingsView.xaml.cs │ │ │ │ ├── InputDataView.xaml │ │ │ │ ├── InputDataView.xaml.cs │ │ │ │ ├── LicenseView.xaml │ │ │ │ ├── LicenseView.xaml.cs │ │ │ │ ├── LlvmSettingsView.xaml │ │ │ │ ├── LlvmSettingsView.xaml.cs │ │ │ │ ├── LoginView.xaml │ │ │ │ ├── LoginView.xaml.cs │ │ │ │ ├── ReleaseNotesView.xaml │ │ │ │ ├── ReleaseNotesView.xaml.cs │ │ │ │ ├── SearchBoxView.xaml │ │ │ │ ├── SearchBoxView.xaml.cs │ │ │ │ ├── SettingsView.xaml │ │ │ │ ├── SettingsView.xaml.cs │ │ │ │ ├── Styles/ │ │ │ │ │ ├── AppResources.xaml │ │ │ │ │ ├── HyperlinkStyle.xaml │ │ │ │ │ ├── ImageResources.xaml │ │ │ │ │ ├── SettingsButtonStyle.xaml │ │ │ │ │ ├── SettingsComboBoxStyle.xaml │ │ │ │ │ ├── ToggleStyle.xaml │ │ │ │ │ └── YellowButtonStyle.xaml │ │ │ │ ├── TidyChecksView.xaml │ │ │ │ ├── TidyChecksView.xaml.cs │ │ │ │ ├── TidySettingsView.xaml │ │ │ │ ├── TidySettingsView.xaml.cs │ │ │ │ ├── TidyToolWindowView.xaml │ │ │ │ ├── TidyToolWindowView.xaml.cs │ │ │ │ ├── ToolWindows/ │ │ │ │ │ ├── FindToolWindow.cs │ │ │ │ │ └── TidyToolWindow.cs │ │ │ │ ├── TrialExpiredView.xaml │ │ │ │ └── TrialExpiredView.xaml.cs │ │ │ ├── WebApi/ │ │ │ │ └── WebApiUrl.cs │ │ │ └── XmlSerializer.cs │ │ ├── Output/ │ │ │ ├── OutputContentModel.cs │ │ │ ├── OutputProcessor.cs │ │ │ ├── OutputWindowBuilder.cs │ │ │ ├── OutputWindowConstants.cs │ │ │ ├── OutputWindowController.cs │ │ │ └── OutputWindowModel.cs │ │ ├── Resources/ │ │ │ └── LICENSE.txt │ │ ├── Script/ │ │ │ ├── ClangTidyModeParametersFactory.cs │ │ │ ├── GenericScriptBuilder.cs │ │ │ ├── ItemRelatedScriptBuilder.cs │ │ │ ├── PowerShellWrapper.cs │ │ │ ├── RunModeScriptBuilder.cs │ │ │ ├── RunningProcesses.cs │ │ │ ├── ScriptConstants.cs │ │ │ └── VerbosityScriptBuilder.cs │ │ ├── Services/ │ │ │ ├── PowerShellService.cs │ │ │ └── VsServiceProvider.cs │ │ ├── SilentFile/ │ │ │ ├── SilentFileChangerBuilder.cs │ │ │ ├── SilentFileChangerController.cs │ │ │ ├── SilentFileChangerEqualityComparer.cs │ │ │ └── SilentFileChangerModel.cs │ │ ├── Squiggle/ │ │ │ ├── SquiggleErrorTag.cs │ │ │ ├── SquiggleErrorTagger.cs │ │ │ ├── SquiggleErrorTaggerProvider.cs │ │ │ ├── SquiggleModel.cs │ │ │ ├── SquiggleViewModel.cs │ │ │ └── SquigglesFactory.cs │ │ ├── TextOperationsInterfaces/ │ │ │ ├── IDetector.cs │ │ │ └── ITextFormatter.cs │ │ └── Tooling/ │ │ └── v1/ │ │ ├── clang-build.ps1 │ │ └── psClang/ │ │ ├── get-header-references.ps1 │ │ ├── get-llvm-helper.ps1 │ │ ├── get-llvm.ps1 │ │ ├── integration-project.tests.ps1 │ │ ├── integration-projects/ │ │ │ ├── CptIntegrationProjects.sln │ │ │ └── itemgroups/ │ │ │ └── test.vcxproj │ │ ├── io.ps1 │ │ ├── io.tests.ps1 │ │ ├── itemdefinition-context.ps1 │ │ ├── jsondb-export.ps1 │ │ ├── jsondb-export.tests.ps1 │ │ ├── msbuild-expression-eval.ps1 │ │ ├── msbuild-expression-eval.tests.ps1 │ │ ├── msbuild-project-cache-repository.ps1 │ │ ├── msbuild-project-cache-repository.tests.ps1 │ │ ├── msbuild-project-data.ps1 │ │ ├── msbuild-project-data.tests.ps1 │ │ ├── msbuild-project-load.ps1 │ │ ├── msbuild-project-load.tests.ps1 │ │ ├── visualstudio-detection.ps1 │ │ ├── visualstudio-detection.tests.ps1 │ │ └── ~advinst.tests.ps1 │ ├── ClangPowerToolsUnitTests/ │ │ ├── ClangCommandTests/ │ │ │ ├── IgnoreCompileCommandTests.cs │ │ │ ├── IgnoreFormatCommandTests.cs │ │ │ └── ScriptTests.cs │ │ ├── ClangPowerToolsUnitTests.csproj │ │ ├── Constants/ │ │ │ └── IgnoreCommand.cs │ │ ├── PackageTests/ │ │ │ └── AsyncPackageTests.cs │ │ ├── Settings Tests/ │ │ │ ├── CompilerSettingsTests.cs │ │ │ ├── FormatSettingsTests.cs │ │ │ ├── GeneralSettingsTests.cs │ │ │ └── TidySettingsTests.cs │ │ ├── VSVersionTests.cs │ │ └── VsServiceProviderTests.cs │ ├── VsixAI/ │ │ └── InfoDocument.txt │ └── cert.pfx ├── LICENSE.TXT └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto ================================================ FILE: .github/workflows/Build-ClangPowerTools.yml ================================================ # This is a basic workflow to help you get started with Actions name: Build Clang Power Tools and generate vsix with Advenced Installer # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.1 - name: Restore dependencies run: dotnet restore ClangPowerTools\ClangPowerTools.sln - name: Build app for release run: msbuild ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.sln -t:rebuild -property:Configuration=Release generate-aip: runs-on: windows-latest needs: build if: github.ref == 'refs/heads/master' steps: - uses: actions/checkout@v2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.1 - name: Restore dependencies run: dotnet restore ClangPowerTools\ClangPowerTools.sln - name: Build app for release run: msbuild ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.sln -t:rebuild -property:Configuration=Release - name: Create ClangPowerTools.vsix- build AIP uses: caphyon/advinst-github-action@v1.0 with: advinst-license: ${{ secrets.ADVINST_LICENSE_KEY }} advinst-enable-automation: 'true' aip-path: ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.aip - run: | AdvancedInstaller.com /edit ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.aip /SetProperty Identifier="Caphyon.9ce239f2-d27a-432c-906c-1d55a123dbfd" AdvancedInstaller.com /edit ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.aip /SetProperty Name="Clang Power Tools 2022" AdvancedInstaller.com /edit ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.aip /SetPackageName ClangPowerTools2022 - name: Create ClangPowerTools2022.vsix - build AIP uses: caphyon/advinst-github-action@v1.0 with: advinst-license: ${{ secrets.ADVINST_LICENSE_KEY }} advinst-enable-automation: 'true' aip-path: ${{ github.workspace }}\ClangPowerTools\ClangPowerTools.aip - name: Archive production ClangPowerTools artifacts (cpt generated with advanced installer) uses: actions/upload-artifact@v4 with: name: VsixAI path: ${{ github.workspace }}\ClangPowerTools\VsixAI\ClangPowerTools.vsix - name: Archive production ClangPowerTools 2022 artifacts (cpt 2022 generated with advanced installer) uses: actions/upload-artifact@v4 with: name: VsixAI2022 path: ${{ github.workspace }}\ClangPowerTools\VsixAI\ClangPowerTools2022.vsix ================================================ FILE: .github/workflows/Run-ClangPowerTools-tests.yml ================================================ name: Run script tests # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "run-script-tests" run-script-tests: # The type of runner that the job will run on runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Check out repository code uses: actions/checkout@v2 - name: Perform Pester tests from the command-line shell: pwsh run: Invoke-Pester ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ #Nuget [Pp]ackages # Visual Studio cache/options directory .vs/ .DS_Store ClangPowerTools/ClangPowerTools/ClangPowerToolsLib16.dll ClangPowerTools/ClangPowerTools/ClangPowerToolsLib17.dll ClangPowerTools/CPTReleases/ClangPowerTools2022.vsix ClangPowerTools/CPTReleases/ClangPowerTools.vsix ClangPowerTools/ClangPowerToolsShared/Tooling/.vscode/launch.json ================================================ FILE: ClangPowerTools/Automation/full-llvm-update-instructions.md ================================================ # Copilot recipe – Update clang-format & LLVM metadata When the user says something like: > Update clang-format and LLVM version to `` with CPT previous release tag `` you must do **all** of the following steps from the **repo root** (`clang-power-tools`). > ⚠️ **Important:** > The value of `kCptGithubLlvm` is **the Clang Power Tools GitHub release that contains the previous assets** > (`#Url to assets (clang++ and clang-tidy) from previous release made by Clang Power Tools on github`). > If the user did **not** provide ``, you **must ask the user** for it before editing > `get-llvm-helper.ps1`. Do **not** guess it. --- ## 1. Run the PowerShell updater From the **repo root**, run: ```powershell & ".\ClangPowerTools\Tidy_Checks_Automation\update-clang-format.ps1" -LlvmVersion ``` Example for LLVM 21.1.6: ```powershell & ".\ClangPowerTools\Tidy_Checks_Automation\update-clang-format.ps1" -LlvmVersion 21.1.6 ``` This downloads: ``` https://github.com/llvm/llvm-project/releases/download/llvmorg-/LLVM--win64.exe ``` runs the installer into a temporary folder, then copies the new `clang-format.exe` to: ``` ClangPowerTools/ClangPowerToolsShared/Executables/clang-format.exe ``` You do **not** need to manually edit the EXE; just ensure this path is updated. --- ## 2. Update C# version lists ### 2.1 File: `ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LLVMVersionsAlternate.cs` In the `VersionAlternateUri` list, insert the new version **at the top** (as the first element), keeping the rest unchanged. Pattern: ```diff public static List VersionAlternateUri { get; } = new List { + "", "18.1.2", "17.0.1", "16.0.6", // ... }; ``` --- ### 2.2 File: `ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LlvmVersions.cs` In the `Versions` list, insert the new version **at the top** (first element), keeping the rest unchanged. Pattern: ```diff public static List Versions { get; } = new List { + "", "18.1.2", "17.0.1", "16.0.6", // ... }; ``` --- ## 3. Update the PowerShell helper script ### File: `ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/get-llvm-helper.ps1` At the top of this file there is a comment: ```powershell #Url to assets (clang++ and clang-tidy) from previous release made by Clang Power Tools on github ``` This means: - `kCptGithubLlvm` must point to the **previous Clang Power Tools GitHub release** that contains the clang++/clang-tidy assets. - `kCptGithubLlvmVersion` is a human-readable description for the LLVM version. > 🔴 **Rule for Copilot:** > If the user did **not** provide ``, you must ask: > *“What is the Clang Power Tools GitHub release tag that contains the previous clang++/clang-tidy assets (for kCptGithubLlvm)?”* > Only after the user answers, update `kCptGithubLlvm`. Once the user has provided ``, update both variables like this: ```diff -Set-Variable -name kCptGithubLlvm -value "https://github.com/Caphyon/clang-power-tools/releases/download/v2023.9.0" ` +Set-Variable -name kCptGithubLlvm -value "https://github.com/Caphyon/clang-power-tools/releases/download/" ` -option Constant -Set-Variable -name kCptGithubLlvmVersion -value "18.1.2 (LLVM 18.1.2)" -Option Constant +Set-Variable -name kCptGithubLlvmVersion -value " (LLVM )" -Option Constant ``` --- ## 4. Summary for Copilot When asked to update LLVM to ``: 1. **Run the update script** from the repo root: ```powershell & ".\ClangPowerTools\Tidy_Checks_Automation\update-clang-format.ps1" -LlvmVersion ``` 2. **Edit** `ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LLVMVersionsAlternate.cs`: - Insert `` as the first element in `VersionAlternateUri`. 3. **Edit** `ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LlvmVersions.cs`: - Insert `` as the first element in `Versions`. 4. **Edit** `get-llvm-helper.ps1`: - If `` is **not provided**, ask the user for it. - After receiving it, update: - `kCptGithubLlvm` → `"https://github.com/Caphyon/clang-power-tools/releases/download/"` - `kCptGithubLlvmVersion` → `" (LLVM )"` 5. After all changes, show diffs for: - `LLVMVersionsAlternate.cs` - `LlvmVersions.cs` - `get-llvm-helper.ps1` - Confirm the script replaced `clang-format.exe`. ================================================ FILE: ClangPowerTools/Automation/get-tidy-checks-and-format.ps1 ================================================ param( [string]$OutFile = "input_checks.txt", [string]$Url = "https://clang.llvm.org/extra/clang-tidy/checks/list.html" ) # Make sure TLS is OK on older PowerShells [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 # Download HTML $response = Invoke-WebRequest -Uri $Url $html = $response.Content # Regex: # # CHECK-NAME # $pattern = ']*class=["'']reference internal["''][^>]*>\s*]*class=["'']doc["''][^>]*>([^<]+)\s*' $matches = [regex]::Matches( $html, $pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase ) $checks = @() foreach ($m in $matches) { $name = $m.Groups[1].Value.Trim() if ([string]::IsNullOrWhiteSpace($name)) { continue } # Names can contain letters, digits, -, _, . if ($name -match '^[A-Za-z0-9_.-]+$') { $checks += $name } } # Sort & dedupe $checks = $checks | Sort-Object -Unique # Write to file $checks | Set-Content -Path $OutFile -Encoding UTF8 Write-Host "$($checks.Count) checks written to '$OutFile'" #-------------------------------------------------------------- Format here -------------------------------------------------------------------------------------------------------- # Will convert bugprone-empty-catch list in new TidyCheckModel { Name = "bugprone-empty-catch", IsChecked = false }, and remove dublicates # Input and output file paths $inputFilePath = "input_checks.txt" $outputFilePath = "output_checks.txt" # Read checks from input file $checks = Get-Content $inputFilePath # Sort the checks alphabetically $sortedChecks = $checks | Sort-Object # Create a hashtable to store unique checks $uniqueChecks = @{} # Format and add each unique check to the hashtable foreach ($check in $sortedChecks) { if (-not $uniqueChecks.ContainsKey($check)) { $uniqueChecks[$check] = "new TidyCheckModel { Name = `"$check`", IsChecked = false }," } } # Sort the unique checks alphabetically again $sortedUniqueChecks = $uniqueChecks.Values | Sort-Object # Write sorted unique checks to output file $sortedUniqueChecks | Out-File $outputFilePath Write-Host "Formatted unique checks written to $outputFilePath" ================================================ FILE: ClangPowerTools/Automation/input_checks.txt ================================================ abseil-cleanup-ctad abseil-duration-addition abseil-duration-comparison abseil-duration-conversion-cast abseil-duration-division abseil-duration-factory-float abseil-duration-factory-scale abseil-duration-subtraction abseil-duration-unnecessary-conversion abseil-faster-strsplit-delimiter abseil-no-internal-dependencies abseil-no-namespace abseil-redundant-strcat-calls abseil-str-cat-append abseil-string-find-startswith abseil-string-find-str-contains abseil-time-comparison abseil-time-subtraction abseil-upgrade-duration-conversions altera-id-dependent-backward-branch altera-kernel-name-restriction altera-single-work-item-barrier altera-struct-pack-align altera-unroll-loops android-cloexec-accept android-cloexec-accept4 android-cloexec-creat android-cloexec-dup android-cloexec-epoll-create android-cloexec-epoll-create1 android-cloexec-fopen android-cloexec-inotify-init android-cloexec-inotify-init1 android-cloexec-memfd-create android-cloexec-open android-cloexec-pipe android-cloexec-pipe2 android-cloexec-socket android-comparison-in-temp-failure-retry boost-use-ranges boost-use-to-string bugprone-argument-comment bugprone-assert-side-effect bugprone-assignment-in-if-condition bugprone-bad-signal-to-kill-thread bugprone-bitwise-pointer-cast bugprone-bool-pointer-implicit-conversion bugprone-branch-clone bugprone-capturing-this-in-member-variable bugprone-casting-through-void bugprone-chained-comparison bugprone-command-processor bugprone-compare-pointer-to-member-virtual-function bugprone-copy-constructor-init bugprone-copy-constructor-mutates-argument bugprone-crtp-constructor-accessibility bugprone-dangling-handle bugprone-default-operator-new-on-overaligned-type bugprone-derived-method-shadowing-base-method bugprone-dynamic-static-initializers bugprone-easily-swappable-parameters bugprone-empty-catch bugprone-exception-copy-constructor-throws bugprone-exception-escape bugprone-float-loop-counter bugprone-fold-init-type bugprone-forward-declaration-namespace bugprone-forwarding-reference-overload bugprone-implicit-widening-of-multiplication-result bugprone-inaccurate-erase bugprone-inc-dec-in-conditions bugprone-incorrect-enable-if bugprone-incorrect-enable-shared-from-this bugprone-incorrect-roundings bugprone-infinite-loop bugprone-integer-division bugprone-invalid-enum-default-initialization bugprone-lambda-function-name bugprone-macro-parentheses bugprone-macro-repeated-side-effects bugprone-misleading-setter-of-reference bugprone-misplaced-operator-in-strlen-in-alloc bugprone-misplaced-pointer-arithmetic-in-alloc bugprone-misplaced-widening-cast bugprone-move-forwarding-reference bugprone-multi-level-implicit-pointer-conversion bugprone-multiple-new-in-one-expression bugprone-multiple-statement-macro bugprone-narrowing-conversions bugprone-no-escape bugprone-nondeterministic-pointer-iteration-order bugprone-non-zero-enum-to-bool-conversion bugprone-not-null-terminated-result bugprone-optional-value-conversion bugprone-parent-virtual-call bugprone-pointer-arithmetic-on-polymorphic-object bugprone-posix-return bugprone-random-generator-seed bugprone-raw-memory-call-on-non-trivial-type bugprone-redundant-branch-condition bugprone-reserved-identifier bugprone-return-const-ref-from-parameter bugprone-shared-ptr-array-mismatch bugprone-signal-handler bugprone-signed-char-misuse bugprone-sizeof-container bugprone-sizeof-expression bugprone-spuriously-wake-up-functions bugprone-standalone-empty bugprone-std-namespace-modification bugprone-string-constructor bugprone-string-integer-assignment bugprone-string-literal-with-embedded-nul bugprone-stringview-nullptr bugprone-suspicious-enum-usage bugprone-suspicious-include bugprone-suspicious-memory-comparison bugprone-suspicious-memset-usage bugprone-suspicious-missing-comma bugprone-suspicious-realloc-usage bugprone-suspicious-semicolon bugprone-suspicious-string-compare bugprone-suspicious-stringview-data-usage bugprone-swapped-arguments bugprone-switch-missing-default-case bugprone-tagged-union-member-count bugprone-terminating-continue bugprone-throwing-static-initialization bugprone-throw-keyword-missing bugprone-too-small-loop-variable bugprone-unchecked-optional-access bugprone-unchecked-string-to-number-conversion bugprone-undefined-memory-manipulation bugprone-undelegated-constructor bugprone-unhandled-exception-at-new bugprone-unhandled-self-assignment bugprone-unintended-char-ostream-output bugprone-unique-ptr-array-mismatch bugprone-unsafe-functions bugprone-unused-local-non-trivial-variable bugprone-unused-raii bugprone-unused-return-value bugprone-use-after-move bugprone-virtual-near-miss cert-arr39-c cert-con36-c cert-con54-cpp cert-ctr56-cpp cert-dcl03-c cert-dcl16-c cert-dcl37-c cert-dcl50-cpp cert-dcl51-cpp cert-dcl54-cpp cert-dcl58-cpp cert-dcl59-cpp cert-env33-c cert-err09-cpp cert-err33-c cert-err34-c cert-err52-cpp cert-err58-cpp cert-err60-cpp cert-err61-cpp cert-exp42-c cert-fio38-c cert-flp30-c cert-flp37-c cert-int09-c cert-mem57-cpp cert-msc24-c cert-msc30-c cert-msc32-c cert-msc33-c cert-msc50-cpp cert-msc51-cpp cert-msc54-cpp cert-oop11-cpp cert-oop54-cpp cert-oop57-cpp cert-oop58-cpp cert-pos44-c cert-pos47-c cert-sig30-c cert-str34-c clang-analyzer-core.BitwiseShift clang-analyzer-core.CallAndMessage clang-analyzer-core.DivideZero clang-analyzer-core.NonNullParamChecker clang-analyzer-core.NullDereference clang-analyzer-core.StackAddressEscape clang-analyzer-core.UndefinedBinaryOperatorResult clang-analyzer-core.uninitialized.ArraySubscript clang-analyzer-core.uninitialized.Assign clang-analyzer-core.uninitialized.Branch clang-analyzer-core.uninitialized.CapturedBlockVariable clang-analyzer-core.uninitialized.NewArraySize clang-analyzer-core.uninitialized.UndefReturn clang-analyzer-core.VLASize clang-analyzer-cplusplus.ArrayDelete clang-analyzer-cplusplus.InnerPointer clang-analyzer-cplusplus.Move clang-analyzer-cplusplus.NewDelete clang-analyzer-cplusplus.NewDeleteLeaks clang-analyzer-cplusplus.PlacementNew clang-analyzer-cplusplus.SelfAssignment clang-analyzer-cplusplus.StringChecker clang-analyzer-deadcode.DeadStores clang-analyzer-fuchsia.HandleChecker clang-analyzer-nullability.NullableDereferenced clang-analyzer-nullability.NullablePassedToNonnull clang-analyzer-nullability.NullableReturnedFromNonnull clang-analyzer-nullability.NullPassedToNonnull clang-analyzer-nullability.NullReturnedFromNonnull clang-analyzer-optin.core.EnumCastOutOfRange clang-analyzer-optin.cplusplus.UninitializedObject clang-analyzer-optin.cplusplus.VirtualCall clang-analyzer-optin.mpi.MPI-Checker clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker clang-analyzer-optin.performance.GCDAntipattern clang-analyzer-optin.performance.Padding clang-analyzer-optin.portability.UnixAPI clang-analyzer-optin.taint.TaintedAlloc clang-analyzer-osx.API clang-analyzer-osx.cocoa.AtSync clang-analyzer-osx.cocoa.AutoreleaseWrite clang-analyzer-osx.cocoa.ClassRelease clang-analyzer-osx.cocoa.Dealloc clang-analyzer-osx.cocoa.IncompatibleMethodTypes clang-analyzer-osx.cocoa.Loops clang-analyzer-osx.cocoa.MissingSuperCall clang-analyzer-osx.cocoa.NilArg clang-analyzer-osx.cocoa.NonNilReturnValue clang-analyzer-osx.cocoa.NSAutoreleasePool clang-analyzer-osx.cocoa.NSError clang-analyzer-osx.cocoa.ObjCGenerics clang-analyzer-osx.cocoa.RetainCount clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak clang-analyzer-osx.cocoa.SelfInit clang-analyzer-osx.cocoa.SuperDealloc clang-analyzer-osx.cocoa.UnusedIvars clang-analyzer-osx.cocoa.VariadicMethodTypes clang-analyzer-osx.coreFoundation.CFError clang-analyzer-osx.coreFoundation.CFNumber clang-analyzer-osx.coreFoundation.CFRetainRelease clang-analyzer-osx.coreFoundation.containers.OutOfBounds clang-analyzer-osx.coreFoundation.containers.PointerSizedValues clang-analyzer-osx.NumberObjectConversion clang-analyzer-osx.ObjCProperty clang-analyzer-osx.SecKeychainAPI clang-analyzer-security.cert.env.InvalidPtr clang-analyzer-security.FloatLoopCounter clang-analyzer-security.insecureAPI.bcmp clang-analyzer-security.insecureAPI.bcopy clang-analyzer-security.insecureAPI.bzero clang-analyzer-security.insecureAPI.decodeValueOfObjCType clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling clang-analyzer-security.insecureAPI.getpw clang-analyzer-security.insecureAPI.gets clang-analyzer-security.insecureAPI.mkstemp clang-analyzer-security.insecureAPI.mktemp clang-analyzer-security.insecureAPI.rand clang-analyzer-security.insecureAPI.strcpy clang-analyzer-security.insecureAPI.UncheckedReturn clang-analyzer-security.insecureAPI.vfork clang-analyzer-security.PutenvStackArray clang-analyzer-security.SetgidSetuidOrder clang-analyzer-unix.API clang-analyzer-unix.BlockInCriticalSection clang-analyzer-unix.cstring.BadSizeArg clang-analyzer-unix.cstring.NullArg clang-analyzer-unix.Errno clang-analyzer-unix.Malloc clang-analyzer-unix.MallocSizeof clang-analyzer-unix.MismatchedDeallocator clang-analyzer-unix.StdCLibraryFunctions clang-analyzer-unix.Stream clang-analyzer-unix.Vfork clang-analyzer-webkit.NoUncountedMemberChecker clang-analyzer-webkit.RefCntblBaseVirtualDtor clang-analyzer-webkit.UncountedLambdaCapturesChecker concurrency-mt-unsafe concurrency-thread-canceltype-asynchronous cppcoreguidelines-avoid-capturing-lambda-coroutines cppcoreguidelines-avoid-c-arrays cppcoreguidelines-avoid-const-or-ref-data-members cppcoreguidelines-avoid-do-while cppcoreguidelines-avoid-goto cppcoreguidelines-avoid-magic-numbers cppcoreguidelines-avoid-non-const-global-variables cppcoreguidelines-avoid-reference-coroutine-parameters cppcoreguidelines-c-copy-assignment-signature cppcoreguidelines-explicit-virtual-functions cppcoreguidelines-init-variables cppcoreguidelines-interfaces-global-init cppcoreguidelines-macro-to-enum cppcoreguidelines-macro-usage cppcoreguidelines-misleading-capture-default-by-value cppcoreguidelines-missing-std-forward cppcoreguidelines-narrowing-conversions cppcoreguidelines-noexcept-destructor cppcoreguidelines-noexcept-move-operations cppcoreguidelines-noexcept-swap cppcoreguidelines-no-malloc cppcoreguidelines-non-private-member-variables-in-classes cppcoreguidelines-no-suspend-with-lock cppcoreguidelines-owning-memory cppcoreguidelines-prefer-member-initializer cppcoreguidelines-pro-bounds-array-to-pointer-decay cppcoreguidelines-pro-bounds-avoid-unchecked-container-access cppcoreguidelines-pro-bounds-constant-array-index cppcoreguidelines-pro-bounds-pointer-arithmetic cppcoreguidelines-pro-type-const-cast cppcoreguidelines-pro-type-cstyle-cast cppcoreguidelines-pro-type-member-init cppcoreguidelines-pro-type-reinterpret-cast cppcoreguidelines-pro-type-static-cast-downcast cppcoreguidelines-pro-type-union-access cppcoreguidelines-pro-type-vararg cppcoreguidelines-rvalue-reference-param-not-moved cppcoreguidelines-slicing cppcoreguidelines-special-member-functions cppcoreguidelines-use-default-member-init cppcoreguidelines-use-enum-class cppcoreguidelines-virtual-class-destructor darwin-avoid-spinlock darwin-dispatch-once-nonstatic fuchsia-default-arguments-calls fuchsia-default-arguments-declarations fuchsia-header-anon-namespaces fuchsia-multiple-inheritance fuchsia-overloaded-operator fuchsia-statically-constructed-objects fuchsia-temporary-objects fuchsia-trailing-return fuchsia-virtual-inheritance google-build-explicit-make-pair google-build-namespaces google-build-using-namespace google-default-arguments google-explicit-constructor google-global-names-in-headers google-objc-avoid-nsobject-new google-objc-avoid-throwing-exception google-objc-function-naming google-objc-global-variable-declaration google-readability-avoid-underscore-in-googletest-name google-readability-braces-around-statements google-readability-casting google-readability-function-size google-readability-namespace-comments google-readability-todo google-runtime-float google-runtime-int google-runtime-operator google-upgrade-googletest-case hicpp-avoid-c-arrays hicpp-avoid-goto hicpp-braces-around-statements hicpp-deprecated-headers hicpp-exception-baseclass hicpp-explicit-conversions hicpp-function-size hicpp-ignored-remove-result hicpp-invalid-access-moved hicpp-member-init hicpp-move-const-arg hicpp-multiway-paths-covered hicpp-named-parameter hicpp-new-delete-operators hicpp-no-array-decay hicpp-no-assembler hicpp-noexcept-move hicpp-no-malloc hicpp-signed-bitwise hicpp-special-member-functions hicpp-static-assert hicpp-undelegated-constructor hicpp-uppercase-literal-suffix hicpp-use-auto hicpp-use-emplace hicpp-use-equals-default hicpp-use-equals-delete hicpp-use-noexcept hicpp-use-nullptr hicpp-use-override hicpp-vararg linuxkernel-must-check-errs llvm-else-after-return llvm-header-guard llvm-include-order llvmlibc-callee-namespace llvmlibc-implementation-in-namespace llvmlibc-inline-function-decl llvmlibc-restrict-system-libc-headers llvm-namespace-comment llvm-prefer-isa-or-dyn-cast-in-conditionals llvm-prefer-register-over-unsigned llvm-prefer-static-over-anonymous-namespace llvm-qualified-auto llvm-twine-local llvm-use-new-mlir-op-builder llvm-use-ranges misc-confusable-identifiers misc-const-correctness misc-coroutine-hostile-raii misc-definitions-in-headers misc-header-include-cycle misc-include-cleaner misc-misleading-bidirectional misc-misleading-identifier misc-misplaced-const misc-new-delete-overloads misc-non-copyable-objects misc-non-private-member-variables-in-classes misc-no-recursion misc-override-with-different-visibility misc-predictable-rand misc-redundant-expression misc-static-assert misc-throw-by-value-catch-by-reference misc-unconventional-assign-operator misc-uniqueptr-reset-release misc-unused-alias-decls misc-unused-parameters misc-unused-using-decls misc-use-anonymous-namespace misc-use-internal-linkage modernize-avoid-bind modernize-avoid-c-arrays modernize-avoid-setjmp-longjmp modernize-avoid-variadic-functions modernize-concat-nested-namespaces modernize-deprecated-headers modernize-deprecated-ios-base-aliases modernize-loop-convert modernize-macro-to-enum modernize-make-shared modernize-make-unique modernize-min-max-use-initializer-list modernize-pass-by-value modernize-raw-string-literal modernize-redundant-void-arg modernize-replace-auto-ptr modernize-replace-disallow-copy-and-assign-macro modernize-replace-random-shuffle modernize-return-braced-init-list modernize-shrink-to-fit modernize-type-traits modernize-unary-static-assert modernize-use-auto modernize-use-bool-literals modernize-use-constraints modernize-use-default-member-init modernize-use-designated-initializers modernize-use-emplace modernize-use-equals-default modernize-use-equals-delete modernize-use-integer-sign-comparison modernize-use-nodiscard modernize-use-noexcept modernize-use-nullptr modernize-use-override modernize-use-ranges modernize-use-scoped-lock modernize-use-starts-ends-with modernize-use-std-format modernize-use-std-numbers modernize-use-std-print modernize-use-trailing-return-type modernize-use-transparent-functors modernize-use-uncaught-exceptions modernize-use-using mpi-buffer-deref mpi-type-mismatch objc-assert-equals objc-avoid-nserror-init objc-dealloc-in-category objc-forbidden-subclassing objc-missing-hash objc-nsdate-formatter objc-nsinvocation-argument-lifetime objc-property-declaration objc-super-self openmp-exception-escape openmp-use-default-none performance-avoid-endl performance-enum-size performance-faster-string-find performance-for-range-copy performance-implicit-conversion-in-loop performance-inefficient-algorithm performance-inefficient-string-concatenation performance-inefficient-vector-operation performance-move-const-arg performance-move-constructor-init performance-no-automatic-move performance-noexcept-destructor performance-noexcept-move-constructor performance-noexcept-swap performance-no-int-to-ptr performance-trivially-destructible performance-type-promotion-in-math-fn performance-unnecessary-copy-initialization performance-unnecessary-value-param portability-avoid-pragma-once portability-restrict-system-includes portability-simd-intrinsics portability-std-allocator-const portability-template-virtual-member-function readability-ambiguous-smartptr-reset-call readability-avoid-const-params-in-decls readability-avoid-nested-conditional-operator readability-avoid-return-with-void-value readability-avoid-unconditional-preprocessor-if readability-braces-around-statements readability-const-return-type readability-container-contains readability-container-data-pointer readability-container-size-empty readability-convert-member-functions-to-static readability-delete-null-pointer readability-duplicate-include readability-else-after-return readability-enum-initial-value readability-function-cognitive-complexity readability-function-size readability-identifier-length readability-identifier-naming readability-implicit-bool-conversion readability-inconsistent-declaration-parameter-name readability-isolate-declaration readability-magic-numbers readability-make-member-function-const readability-math-missing-parentheses readability-misleading-indentation readability-misplaced-array-index readability-named-parameter readability-non-const-parameter readability-operators-representation readability-qualified-auto readability-redundant-access-specifiers readability-redundant-casting readability-redundant-control-flow readability-redundant-declaration readability-redundant-function-ptr-dereference readability-redundant-inline-specifier readability-redundant-member-init readability-redundant-parentheses readability-redundant-preprocessor readability-redundant-smartptr-get readability-redundant-string-cstr readability-redundant-string-init readability-redundant-typename readability-reference-to-constructed-temporary readability-simplify-boolean-expr readability-simplify-subscript-expr readability-static-accessed-through-instance readability-static-definition-in-anonymous-namespace readability-string-compare readability-suspicious-call-argument readability-uniqueptr-delete-release readability-uppercase-literal-suffix readability-use-anyofallof readability-use-concise-preprocessor-directives readability-use-std-min-max zircon-temporary-objects ================================================ FILE: ClangPowerTools/Automation/update_clang-format.ps1 ================================================ <# .SYNOPSIS Download and update clang-format.exe for a given LLVM version. .DESCRIPTION - Downloads the official LLVM Windows installer from GitHub releases: https://github.com/llvm/llvm-project/releases/download/llvmorg-/LLVM--win64.exe - Runs the installer silently into a temporary folder. - Locates clang-format.exe in the installed tree. - Replaces: ClangPowerTools/ClangPowerToolsShared/Executables/clang-format.exe .PARAMETER LlvmVersion LLVM version, e.g. "20.1.0" or "21.1.6". .PARAMETER RepoRoot (Optional) Path to the repository root. Defaults to one level above the script location. .EXAMPLE .\update-clang-format.ps1 -LlvmVersion 21.1.6 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $LlvmVersion, [Parameter(Mandatory = $false)] [string] $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path ) # -------- Config -------- # GitHub tag prefix $GithubTagPrefix = "llvmorg" # Asset file name pattern # Example: LLVM-21.1.6-win64.exe $AssetFileName = "LLVM-$LlvmVersion-win64.exe" # Target clang-format path (relative to repo root) $TargetRelativePath = "ClangPowerTools\ClangPowerToolsShared\Executables\clang-format.exe" # -------- Derived paths & URLs -------- $tag = "$GithubTagPrefix-$LlvmVersion" $baseDownloadUrl = "https://github.com/llvm/llvm-project/releases/download/$tag" $downloadUrl = "$baseDownloadUrl/$AssetFileName" $targetPath = Join-Path $RepoRoot $TargetRelativePath # Temp folder for download & installation $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "cpt-update-clang-format-$($LlvmVersion.Replace('.','-'))" $null = New-Item -ItemType Directory -Path $tempRoot -Force $downloadPath = Join-Path $tempRoot $AssetFileName $installDir = Join-Path $tempRoot "install" Write-Host "LLVM version : $LlvmVersion" Write-Host "GitHub tag : $tag" Write-Host "Download URL : $downloadUrl" Write-Host "Repository root : $RepoRoot" Write-Host "Target exe path : $targetPath" Write-Host "" try { # -------- Download installer -------- Write-Host "Downloading LLVM installer..." Invoke-WebRequest -Uri $downloadUrl -OutFile $downloadPath -UseBasicParsing if (-not (Test-Path $downloadPath)) { throw "Download failed: file not found at $downloadPath" } # -------- Run installer silently into temp folder -------- Write-Host "Running installer silently into: $installDir" $null = New-Item -ItemType Directory -Path $installDir -Force # LLVM Windows installers are NSIS-based, which typically support: # /S = silent # /D= = install directory (no quotes, path must be last arg) # # We pass arguments as a single string where /D= is last. $installArgs = "/S /D=$installDir" $process = Start-Process -FilePath $downloadPath ` -ArgumentList $installArgs ` -Wait ` -PassThru if ($process.ExitCode -ne 0) { throw "Installer exited with code $($process.ExitCode)" } # -------- Locate clang-format.exe -------- Write-Host "Searching for clang-format.exe in installed files..." $clangFormat = Get-ChildItem -Path $installDir -Recurse -Filter "clang-format.exe" | Select-Object -First 1 if (-not $clangFormat) { throw "clang-format.exe not found under $installDir" } Write-Host "Found clang-format.exe at: $($clangFormat.FullName)" # -------- Replace target file -------- $targetDir = Split-Path $targetPath -Parent if (-not (Test-Path $targetDir)) { Write-Host "Creating target directory: $targetDir" $null = New-Item -ItemType Directory -Path $targetDir -Force } Write-Host "Copying new clang-format.exe to target..." Copy-Item -Path $clangFormat.FullName -Destination $targetPath -Force Write-Host "" Write-Host " clang-format.exe updated successfully." Write-Host " Version: $LlvmVersion" Write-Host " Location: $targetPath" } catch { Write-Error " Failed to update clang-format.exe: $_" } finally { if (Test-Path $tempRoot) { Write-Host "Cleaning up temp folder: $tempRoot" Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue } } ================================================ FILE: ClangPowerTools/CPTReleases/IncrementRevisionNumber.ps1 ================================================ param([Parameter(Mandatory=$true, HelpMessage="Increments revision number in manifest file")][string] $loc) #Get version from xml and increment revision value $filepath = "$loc\..\ClangPowerTools\source.extension.vsixmanifest" $filepathToAip = "$loc\..\ClangPowerTools.aip" if((Test-Path $filepath) -and (Test-Path $filepathToAip)) { #Get xml data from manifest file [xml] $data = Get-Content $filepath $currentVersion = [Version]::new($data.PackageManifest.Metadata.Identity.Version.ToString()) #Get xml data from aip file [xml] $aipData = Get-Content $filepathToAip #Replace old version with new one in manifest $data.PackageManifest.Metadata.Identity.Version = $currentVersion.ToString() $data.Save("$filepath") #Replace old version with new one in aip file $aipData.DOCUMENT.COMPONENT[0].ROW[7].Value = $currentVersion.ToString() $aipData.Save("$filepathToAip") $resultData = Get-Content $filepathToAip -Encoding utf8 $result = $resultData -replace " />", "/>" # $result > $filepathToAip $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False) [System.IO.File]::WriteAllLines($filepathToAip, $result, $Utf8NoBomEncoding) } else { Write-Error "Invalid manifest file path" } ================================================ FILE: ClangPowerTools/ClangPowerTools/ClangPowerTools.csproj ================================================  17.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) win latest true Key.snk Debug AnyCPU 2.0 {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} {51237463-9F4D-44DE-8BC0-587384B9E8B8} Library Properties ClangPowerTools ClangPowerTools v4.7.2 true true true false false true true Program $(DevEnvDir)devenv.exe /rootsuffix Exp true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 MVVM\Views\TidyToolWindow.cs MVVM\Views\FindToolWindow.cs True True Resource.resx Resources\[CPT]OptimizeIncludes.png Resources\TidyToolWindow\[CPT]Pinned.png Resources\TidyToolWindow\[CPT]UnPinned.png Resources\TidyToolWindow\[CTP]Pinned_dark.png Resources\TidyToolWindow\[CTP]UnPinned_dark.png Resources\TidyToolWindow\[CPT]Diff2.png Resources\TidyToolWindow\[CPT]Diff_dark.png Resources\TidyToolWindow\[CPT]Diff_disabled.png Resources\TidyToolWindow\[CPT]Fix.png Resources\TidyToolWindow\[CPT]Fix_dark.png Resources\TidyToolWindow\[CPT]Fix_disabled.png Resources\TidyToolWindow\[CPT]Refresh-Tidy.png Resources\TidyToolWindow\[CPT]Refresh_dark.png Resources\TidyToolWindow\[CPT]Refresh_disabled.png Resources\TidyToolWindow\[CPT]Remove.png Resources\TidyToolWindow\[CPT]RemoveFix.png Resources\TidyToolWindow\[CPT]RemoveFix_dark.png Resources\TidyToolWindow\[CPT]RemoveFix_disabled.png Resources\TidyToolWindow\[CPT]Remove_dark.png Resources\TidyToolWindow\[CPT]Remove_disabled.png true Always true Always Resources\SettingsBackground.png Resources\AccountAvatarIcon.png Resources\AccountIcon.png Resources\AddInput.png Resources\BannerInfo.png Resources\BannersError.png Resources\bannerWarning.png Resources\Browse.png Resources\ClangFormatIcon.png Resources\ClangPowerToolsIco.ico Always Resources\ClangSplitBackground.png Resources\CleanSearchIcon.PNG Resources\CloudIcon.png Resources\CodeInputIcon.png Resources\CompileIcon.png Resources\CPTLogo.png Executables\clang-format.exe true . Executables\Clang Format Editor.msi true . Resources\CPTLogoManageExtensionVS.png Always true Resources\DetectOnFileIcon.png Resources\EmptyIcon.png Resources\ErrorIcon.png Resources\FeedbackIcon.png Resources\FileIcon.png Resources\GenerateClangFormatFile.png Resources\GitHubMark.png Resources\iconCommercial.png Resources\iconFreeTrial.png Resources\iconPersonal.png Resources\IgnoreIcon.png Resources\InfoIcon.png Resources\JsonCompilationDatabase.png Resources\LICENSE.txt Always true Resources\LoginBackground.png Resources\LogoutIcon.png Resources\PreviewWhiteIcon.png Resources\ProjectFilesIcon.png Resources\ReleaseNotesBackground.png Resources\RemoveInputHover.png Resources\RemoveInputIdle.png Resources\ResetIcon.png Resources\RunPowerShellCommandPackage.ico true Resources\SearchIcon.PNG Resources\SettingsIcon.png Resources\SettingsLLVM.png Resources\StopCommandIcon.png Resources\StorageIcon.png Resources\TidyIcon.png Resources\WarningIcon.png Tooling\v1\clang-build.ps1 true Tooling\v1\psClang\get-llvm-helper.ps1 true Tooling\v1\psClang\get-llvm.ps1 true Tooling\v1\psClang\get-header-references.ps1 true Tooling\v1\psClang\io.ps1 true Tooling\v1\psClang\itemdefinition-context.ps1 true Tooling\v1\psClang\jsondb-export.ps1 true Tooling\v1\psClang\msbuild-expression-eval.ps1 true Tooling\v1\psClang\msbuild-project-data.ps1 true Tooling\v1\psClang\msbuild-project-load.ps1 true Tooling\v1\psClang\visualstudio-detection.ps1 true Tooling\v1\psClang\msbuild-project-cache-repository.ps1 true Designer runtime; build; native; contentfiles; analyzers; buildtransitive all 5.0.0 5.0.0 Menus.ctmenu Designer ResXFileCodeGenerator Resource.Designer.cs Designer Designer MVVM\Views\Styles\AppResources.xaml MSBuild:Compile Designer MVVM\Views\Styles\HyperlinkStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\ImageResources.xaml MSBuild:Compile Designer MVVM\Views\Styles\SettingsButtonStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\SettingsComboBoxStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\ToggleStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\YellowButtonStyle.xaml MSBuild:Compile Designer powershell.exe -executionPolicy Bypass -WindowStyle Hidden -file "$(SolutionDir)CPTReleases\IncrementRevisionNumber.ps1" -loc "$(SolutionDir)CPTReleases" ================================================ FILE: ClangPowerTools/ClangPowerTools/ClangPowerTools.csproj.bak ================================================  17.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) win latest true Key.snk Debug AnyCPU 2.0 {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} {51237463-9F4D-44DE-8BC0-587384B9E8B8} Library Properties ClangPowerTools ClangPowerTools v4.7.2 true true true false false true true Program $(DevEnvDir)devenv.exe /rootsuffix Exp true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 MVVM\Views\TidyToolWindow.cs True True Resource.resx Resources\TidyToolWindow\[CPT]Diff2.png Resources\TidyToolWindow\[CPT]Diff_dark.png Resources\TidyToolWindow\[CPT]Diff_disabled.png Resources\TidyToolWindow\[CPT]Fix.png Resources\TidyToolWindow\[CPT]Fix_dark.png Resources\TidyToolWindow\[CPT]Fix_disabled.png Resources\TidyToolWindow\[CPT]Refresh-Tidy.png Resources\TidyToolWindow\[CPT]Refresh_dark.png Resources\TidyToolWindow\[CPT]Refresh_disabled.png Resources\TidyToolWindow\[CPT]Remove.png Resources\TidyToolWindow\[CPT]RemoveFix.png Resources\TidyToolWindow\[CPT]RemoveFix_dark.png Resources\TidyToolWindow\[CPT]RemoveFix_disabled.png Resources\TidyToolWindow\[CPT]Remove_dark.png Resources\TidyToolWindow\[CPT]Remove_disabled.png true Always true Always Resources\SettingsBackground.png Resources\AccountAvatarIcon.png Resources\AccountIcon.png Resources\AddInput.png Resources\BannerInfo.png Resources\BannersError.png Resources\bannerWarning.png Resources\Browse.png Resources\ClangFormatIcon.png Resources\ClangPowerToolsIco.ico Always Resources\ClangSplitBackground.png Resources\CleanSearchIcon.PNG Resources\CloudIcon.png Resources\CodeInputIcon.png Resources\CompileIcon.png Resources\CPTLogo.png Executables\clang-format.exe true . Executables\ClangFormatEditor.exe true . Resources\CPTLogoManageExtensionVS.png Always true Resources\DetectOnFileIcon.png Resources\EmptyIcon.png Resources\ErrorIcon.png Resources\FeedbackIcon.png Resources\FileIcon.png Resources\GenerateClangFormatFile.png Resources\GitHubMark.png Resources\iconCommercial.png Resources\iconFreeTrial.png Resources\iconPersonal.png Resources\IgnoreIcon.png Resources\InfoIcon.png Resources\JsonCompilationDatabase.png Resources\LICENSE.txt Always true Resources\LoginBackground.png Resources\LogoutIcon.png Resources\PreviewWhiteIcon.png Resources\ProjectFilesIcon.png Resources\ReleaseNotesBackground.png Resources\RemoveInputHover.png Resources\RemoveInputIdle.png Resources\ResetIcon.png Resources\RunPowerShellCommandPackage.ico true Resources\SearchIcon.PNG Resources\SettingsIcon.png Resources\SettingsLLVM.png Resources\StopCommandIcon.png Resources\StorageIcon.png Resources\TeamIcon.png Resources\TidyIcon.png Resources\WarningIcon.png Tooling\v1\clang-build.ps1 true Tooling\v1\psClang\get-llvm-helper.ps1 true Tooling\v1\psClang\get-llvm.ps1 true Tooling\v1\psClang\get-header-references.ps1 true Tooling\v1\psClang\io.ps1 true Tooling\v1\psClang\itemdefinition-context.ps1 true Tooling\v1\psClang\jsondb-export.ps1 true Tooling\v1\psClang\msbuild-expression-eval.ps1 true Tooling\v1\psClang\msbuild-project-data.ps1 true Tooling\v1\psClang\msbuild-project-load.ps1 true Tooling\v1\psClang\visualstudio-detection.ps1 true Tooling\v1\psClang\msbuild-project-cache-repository.ps1 true Designer runtime; build; native; contentfiles; analyzers; buildtransitive all 5.0.0 5.0.0 Menus.ctmenu Designer ResXFileCodeGenerator Resource.Designer.cs Designer MVVM\Views\Styles\AppResources.xaml MSBuild:Compile Designer MVVM\Views\Styles\HyperlinkStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\ImageResources.xaml MSBuild:Compile Designer MVVM\Views\Styles\SettingsButtonStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\SettingsComboBoxStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\ToggleStyle.xaml MSBuild:Compile Designer MVVM\Views\Styles\YellowButtonStyle.xaml MSBuild:Compile Designer powershell.exe -executionPolicy Bypass -WindowStyle Hidden -file "$(SolutionDir)CPTReleases\IncrementRevisionNumber.ps1" -loc "$(SolutionDir)CPTReleases" ================================================ FILE: ClangPowerTools/ClangPowerTools/ClangPowerTools.vsct ================================================  Clang Power Tools DefaultDocked Clang Power Tools Clang Power Tools TextChanges Clang Tidy Clang Power Tools DefaultDocked Generate Documentation Generate Documentation ================================================ FILE: ClangPowerTools/ClangPowerTools/ClangPowerToolsPackage.cs ================================================ using ClangPowerToolsShared.MVVM.Views.ToolWindows; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { /// /// This is the class that implements the package exposed by this assembly. /// /// /// /// The minimum requirement for a class to be considered a valid package for Visual Studio /// is to implement the IVsPackage interface and register itself with the shell. /// This package uses the helper classes defined inside the Managed Package Framework (MPF) /// to do it: it derives from the Package class that provides the implementation of the /// IVsPackage interface and uses the registration attributes defined in the framework to /// register itself and its components with the shell. These attributes tell the pkgdef creation /// utility what data to put into .pkgdef file. /// /// /// To get loaded into VS, the package must be referred by <Asset Type="Microsoft.VisualStudio.VsPackage" ...> in .vsixmanifest file. /// /// [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About [ProvideMenuResource("Menus.ctmenu", 1)] [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExistsAndFullyLoaded_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideMenuResource("Menus.ctmenu", 1)] [ProvideToolWindow(typeof(TidyToolWindow), Style = VsDockStyle.Tabbed, DockedWidth = 300, Window = "DocumentWell", Orientation = ToolWindowOrientation.Left, Transient = true)] [ProvideToolWindow(typeof(FindToolWindow), Style = VsDockStyle.Tabbed, DockedWidth = 300, Window = "DocumentWell", Orientation = ToolWindowOrientation.Left, Transient = true)] [Guid(PackageGuidString)] public sealed class RunClangPowerToolsPackage2 : AsyncPackage { #region Members Object mClangPackageImpl; /// /// RunPowerShellCommandPackage GUID string. /// public const string PackageGuidString = "f564f9d3-01ae-493e-883b-18deebdb975e"; private const string cptLib16 = "ClangPowerToolsLib16.dll"; private const string cptLib17 = "ClangPowerToolsLib17.dll"; private const string WPFTextBoxAutoComplete = "WPFTextBoxAutoComplete.dll"; private const string cptNamespace = "ClangPowerTools.ClangPowerToolsPackageImpl"; private const string initializeAsync = "InitializeAsync"; #endregion #region Constructor /// /// Initializes a new instance of the class. /// public RunClangPowerToolsPackage2() { } #endregion #region Initialize Package /// /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { // Switches to the UI thread in order to consume some services used in command initialization await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var shellService = (IVsShell)await GetServiceAsync(typeof(SVsShell)); object releaseVersionObj = ""; shellService.GetProperty(-9068, out releaseVersionObj); string releaseVersion = (string)releaseVersionObj; releaseVersion = releaseVersion.Substring(0, releaseVersion.IndexOf('.')) + ".0"; string assemblyName = new Version(releaseVersion) < new Version("17.0") ? cptLib16 : cptLib17; string currentDir = Path.GetDirectoryName(GetType().Assembly.Location); Assembly assembly = Assembly.LoadFile(Path.Combine(currentDir, assemblyName)); Type type = assembly.GetType(cptNamespace); mClangPackageImpl = Activator.CreateInstance(type, this); MethodInfo method = type.GetMethod(initializeAsync); await (Task)method.Invoke(mClangPackageImpl, null); await base.InitializeAsync(cancellationToken, progress); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerTools/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ClangPowerTools")] [assembly: AssemblyDescription("A tool bringing clang-tidy magic to Visual Studio C++ developers.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Caphyon")] [assembly: AssemblyProduct("ClangPowerTools")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ClangPowerTools/ClangPowerTools/Properties/Resource.Designer.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace ClangPowerTools.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resource() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClangPowerTools.Properties.Resource", typeof(Resource).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to Deselect all. /// internal static string DeselectAllTooltipText { get { return ResourceManager.GetString("DeselectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Encoding Converter. /// internal static string EncodingConverterWindowTitle { get { return ResourceManager.GetString("EncodingConverterWindowTitle", resourceCulture); } } /// /// Looks up a localized string similar to encoding is not supported. /// internal static string EncodingError { get { return ResourceManager.GetString("EncodingError", resourceCulture); } } /// /// Looks up a localized string similar to The following files are not encoded in UTF-8. Do you want to change their encoding?. /// internal static string EncodingErrorText { get { return ResourceManager.GetString("EncodingErrorText", resourceCulture); } } /// /// Looks up a localized string similar to Select all. /// internal static string SelectAllTooltipText { get { return ResourceManager.GetString("SelectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Unicode (UTF-8). /// internal static string UTF8Encoding { get { return ResourceManager.GetString("UTF8Encoding", resourceCulture); } } } } ================================================ FILE: ClangPowerTools/ClangPowerTools/Properties/Resource.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Deselect all Encoding Converter encoding is not supported The following files are not encoded in UTF-8. Do you want to change their encoding? Select all Unicode (UTF-8) ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/clang-build.ps1 ================================================ <# .SYNOPSIS Compiles or tidies up code from Visual Studio .vcxproj project files. .DESCRIPTION This PowerShell script scans for all .vcxproj Visual Studio projects inside a source directory. One or more of these projects will be compiled or tidied up (modernized), using Clang. .PARAMETER aSolutionsPath Alias 'dir'. Source directory to find sln files. Projects will be extracted from each sln. Important: You can pass an absolute path to a sln. This way, no file searching will be done, and only the projects from this solution file will be taken into account. .PARAMETER aVcxprojToCompile Alias 'proj'. Array of project(s) to compile. If empty, all projects found in solutions are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*components'). Absolute disk paths to vcxproj files are accepted. Can be passed as comma separated values. .PARAMETER aVcxprojToIgnore Alias 'proj-ignore'. Array of project(s) to ignore, from the matched ones. If empty, all already matched projects are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*components'). Can be passed as comma separated values. .PARAMETER aVcxprojConfigPlatform Alias 'active-config'. Array of configuration-platform pairs, each pair being separated by |, to be used when processing project files. E.g. "Debug|Win32", "Debug|x64". If not specified, the first configuration-platform found in the current project is used. Projects will be processed for each configuration-platform specified, the ones that are missing will be skipped. .PARAMETER aCppToCompile Alias 'file'. What cpp(s) to compile from the found project(s). If empty, all CPPs are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*table'). Note: If any headers are given then all translation units that include them will be processed. .PARAMETER aCppToIgnore Alias 'file-ignore'. Array of file(s) to ignore, from the matched ones. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*table'). Can be passed as comma separated values. .PARAMETER aUseParallelCompile Alias 'parallel'. Switch to run in parallel mode, on all logical CPU cores. .PARAMETER aContinueOnError Alias 'continue'. Switch to continue project compilation even when errors occur. .PARAMETER aTreatAdditionalIncludesAsSystemIncludes Alias 'treat-sai'. Switch to treat project additional include directories as system includes. .PARAMETER aClangCompileFlags Alias 'clang-flags'. Flags given to clang++ when compiling project, alongside project-specific defines. .PARAMETER aTidyFlags Alias 'tidy'. If not empty clang-tidy will be called with given flags, instead of clang++. The tidy operation is applied to whole translation units, meaning all directory headers included in the CPP will be tidied up too. Changes will not be applied, only simulated. If aTidyFixFlags is present, it takes precedence over this parameter. If '.clang-tidy' value is given, configuration will be read from .clang-tidy file in the closest parent directory. .PARAMETER aTidyFixFlags Alias 'tidy-fix'. If not empty clang-tidy will be called with given flags, instead of clang++. The tidy operation is applied to whole translation units, meaning all directory headers included in the CPP will be tidied up too. Changes will be applied to the file(s). If present, this parameter takes precedence over aTidyFlags. If '.clang-tidy' value is given, configuration will be read from .clang-tidy file in the closest parent directory. .PARAMETER aAfterTidyFixFormatStyle Alias 'format-style'. Used in combination with 'tidy-fix'. If present, clang-tidy will also format the fixed file(s), using the specified style. Possible values: - not present, no formatting will be done - 'file' Literally 'file', not a placeholder. Uses .clang-format file in the closest parent directory. - 'llvm' - 'google' - 'webkit' - 'mozilla' .PARAMETER aVisualStudioVersion Alias 'vs-ver'. Version of Visual Studio (VC++) installed and that'll be used for standard library include directories. E.g. 2017. Optional. If not given, it will be inferred based on the project toolset version. .PARAMETER aVisualStudioSku Alias 'vs-sku'. Sku of Visual Studio (VC++) installed and that'll be used for standard library include directories. E.g. Professional. If not given, the first detected Visual Studio SKU will be used. .NOTES Author: Gabriel Diaconita #> #Requires -Version 5 param( [alias("proj")] [Parameter(Mandatory=$false, HelpMessage="Filter project(s) to compile/tidy")] [System.Object[]] $aVcxprojToCompile = @() , [alias("dir")] [Parameter(Mandatory=$false, HelpMessage="Source directory for finding solutions; projects will be found from each sln")] [string] $aSolutionsPath , [alias("proj-ignore")] [Parameter(Mandatory=$false, HelpMessage="Specify projects to ignore")] [System.Object[]] $aVcxprojToIgnore = @() , [alias("active-config")] [Parameter(Mandatory=$false, HelpMessage="Config/platform to be used, e.g. Debug|Win32")] [string[]] $aVcxprojConfigPlatform = @() , [alias("file")] [Parameter(Mandatory=$false, HelpMessage="Filter file(s) to compile/tidy")] [System.Object[]] $aCppToCompile = @() , [alias("file-ignore")] [Parameter(Mandatory=$false, HelpMessage="Specify file(s) to ignore")] [System.Object[]] $aCppToIgnore = @() , [alias("parallel")] [Parameter(Mandatory=$false, HelpMessage="Compile/tidy/tidy-fix projects in parallel")] [switch] $aUseParallelCompile , [alias("continue")] [Parameter(Mandatory=$false, HelpMessage="Allow CPT to continue immediately after encountering an error")] [switch] $aContinueOnError , [alias("resume")] [Parameter(Mandatory=$false, HelpMessage="Allow CPT to resume the last session (start from last active project / file number).")] [switch] $aResumeAfterError , [alias("treat-sai")] [Parameter(Mandatory=$false, HelpMessage="Treat project additional include directories as system includes")] [switch] $aTreatAdditionalIncludesAsSystemIncludes , [alias("clang-flags")] [Parameter(Mandatory=$false, HelpMessage="Specify compilation flags to CLANG")] [string[]] $aClangCompileFlags = @() , [alias("tidy")] [Parameter(Mandatory=$false, HelpMessage="Specify flags to CLANG TIDY")] [string] $aTidyFlags , [alias("tidy-fix")] [Parameter(Mandatory=$false, HelpMessage="Specify flags to CLANG TIDY & FIX")] [string] $aTidyFixFlags , [alias("header-filter")] [Parameter(Mandatory=$false, HelpMessage="Enable Clang-Tidy to run on header files")] [string] $aTidyHeaderFilter , [alias("format-style")] [Parameter(Mandatory=$false, HelpMessage="Used with 'tidy-fix'; tells CLANG TIDY-FIX to also format the fixed file(s)")] [string] $aAfterTidyFixFormatStyle , [alias("vs-ver")] [Parameter(Mandatory=$false, HelpMessage="Version of Visual Studio toolset to use for loading project")] [string] $aVisualStudioVersion , [alias("vs-sku")] [Parameter(Mandatory=$false, HelpMessage="Edition of Visual Studio toolset to use for loading project")] [string] $aVisualStudioSku , [alias("export-jsondb")] [Parameter(Mandatory=$false, HelpMessage="Switch to generate a JSON compilation database file, in the current working directory")] [switch] $aExportJsonDB , [alias("export-doc")] [Parameter(Mandatory=$false, HelpMessage="If present, specifies the type of documentation to generate, in the current working direcotory")] [ValidateSet("yaml", "md", "html")] [string] $aDocumentationExportFormat ) Set-StrictMode -version latest $ErrorActionPreference = 'Continue' # System Architecture Constants # ------------------------------------------------------------------------------------------------ Set-Variable -name kCptGithubRepoBase -value ` "https://raw.githubusercontent.com/Caphyon/clang-power-tools/master/ClangPowerTools/ClangPowerToolsShared/Tooling/v1/" ` -option Constant Set-Variable -name kPsMajorVersion -value (Get-Host).Version.Major -Option Constant # ------------------------------------------------------------------------------------------------ # Return Value Constants Set-Variable -name kScriptFailsExitCode -value 47 -option Constant # ------------------------------------------------------------------------------------------------ # File System Constants Set-Variable -name kExtensionVcxproj -value ".vcxproj" -option Constant Set-Variable -name kExtensionSolution -value ".sln" -option Constant Set-Variable -name kExtensionYaml -value ".yaml" -option Constant Set-Variable -name kExtensionClangPch -value ".clang.pch" -option Constant Set-Variable -name kExtensionC -value ".c" -option Constant # ------------------------------------------------------------------------------------------------ # Envinroment Variables for controlling logic Set-Variable -name kVarEnvClangTidyPath -value "CLANG_TIDY_PATH"-option Constant # ------------------------------------------------------------------------------------------------ # Clang-Related Constants Set-Variable -name kClangFlagSupressLINK -value @("-fsyntax-only") -option Constant Set-Variable -name kClangFlagIncludePch -value "-include-pch" -option Constant Set-Variable -name kClangFlagFasterPch -value "-fpch-instantiate-templates" -option Constant Set-Variable -name kClangFlagMinusO -value "-o" -option Constant Set-Variable -name kClangDefinePrefix -value "-D" -option Constant Set-Variable -name kClangFlagNoUnusedArg -value "-Wno-unused-command-line-argument" ` -option Constant Set-Variable -name kClangFlagNoMsInclude -value "-Wno-microsoft-include" ` -Option Constant Set-Variable -name kClangFlagFileIsCPP -value "-x c++" -option Constant Set-Variable -name kClangFlagFileIsC -value "-x c" -option Constant Set-Variable -name kClangFlagForceInclude -value "-include" -option Constant Set-Variable -name kClangTidyFixExportFixes -value "--export-fixes=" -option Constant Set-Variable -name kClangCompiler -value "clang++.exe" -option Constant Set-Variable -name kClangTidyFlags -value @("-quiet" ,"--") -option Constant Set-Variable -name kClangTidyFlagHeaderFilter -value "-header-filter=" -option Constant Set-Variable -name kClangTidyFlagChecks -value "-checks=" -option Constant Set-Variable -name kClangTidyUseFile -value ".clang-tidy" -option Constant Set-Variable -name kClangTidyFormatStyle -value "-format-style=" -option Constant Set-Variable -name kClangTidyFlagTempFile -value "" Set-Variable -name kCptRegHiveSettings -value "HKCU:SOFTWARE\Caphyon\Clang Power Tools" -option Constant Set-Variable -name kCptVsixSettings -value "${env:APPDATA}\ClangPowerTools\settings.json" -option Constant Set-Variable -name kCptTidyFixReplacementsDir -value "${env:APPDATA}\ClangPowerTools\TidyFixReplacements" -option Constant # ------------------------------------------------------------------------------------------------ Function cpt:getSetting([string] $name) { if ((Test-Path $kCptVsixSettings)) { $settingsJson = ( (Get-Content -Raw -Path $kCptVsixSettings) | ConvertFrom-Json) $settingField = $settingsJson.Where{ $_ | Get-Member $name } if (!$settingField) { return $null } return $settingField.$name } return $null } # We define this separately from the implementation in io.ps1 because that may not yet be present and # in order to download it we need the connection-status greenlight. Function cpt:testInternetConnectivity { $resp = Get-WmiObject -Class Win32_PingStatus -Filter 'Address="github.com" and Timeout=100' | Select-Object ResponseTime [bool] $hasInternetConnectivity = ($resp.ResponseTime -and $resp.ResponseTime -gt 0) return $hasInternetConnectivity } # Include required scripts, or download them from Github, if necessary Function cpt:ensureScriptExists( [Parameter(Mandatory=$true)] [string] $scriptName , [Parameter(Mandatory=$false)][bool] $forceRedownload ) { [string] $scriptFilePath = "$PSScriptRoot/psClang/$scriptName" if ( $forceRedownload -or (! (Test-Path $scriptFilePath)) ) { Write-Verbose "Download required script $scriptName ..." [string] $request = "$kCptGithubRepoBase/psClang/$scriptName" if ( ! (Test-Path "$PSScriptRoot/psClang")) { New-Item "$PSScriptRoot/psClang" -ItemType Directory > $null } # Invoke-WebRequest has an issue when displaying progress on PowerShell 7, it won't go away # and will keep nagging the user, and on PS5 it causes slow transfers => we supress it. $prevPreference = $progressPreference $ProgressPreference = "SilentlyContinue" Invoke-WebRequest -Uri $request -OutFile $scriptFilePath (Get-Content $scriptFilePath -Raw).Replace("`n","`r`n") | Set-Content $scriptFilePath -Force -NoNewline $ProgressPreference = $prevPreference if (! (Test-Path $scriptFilePath)) { Write-Error "Could not download required script file ($scriptName). Aborting..." exit 1 } } return $scriptFilePath } [bool] $shouldRedownloadForcefully = $false [Version] $cptVsixVersion = cpt:getSetting "Version" Write-Verbose "Current Clang Power Tools VSIX version: $cptVsixVersion" $kLogicalCoreCount = 4; if($Env:NUMBER_OF_PROCESSORS -match "^\d+$") { $kLogicalCoreCount = $Env:NUMBER_OF_PROCESSORS if($Env:CPT_CPULIMIT -match "^\d+$") { $kLogicalCoreCount = $Env:CPT_CPULIMIT } #Set-Variable -name kLogicalCoreCount -value $Env:CPT_CPULIMIT -option Constant } # If the main script has been updated meanwhile, we invalidate all other scripts, and force # them to update from github. We need to watch for this because older CPT VS Extensions (before v7.9) # did not updated all helper scripts, but a list of predefined ones; we need to update the new ones as well. if ( ( ![string]::IsNullOrWhiteSpace($cptVsixVersion) -and [Version]::new($cptVsixVersion) -lt [Version]::new(7, 9, 0) ) -and (Test-Path $kCptRegHiveSettings) ) { Write-Verbose "Checking to see if we should redownload script helpers..." $regHive = Get-Item -LiteralPath $kCptRegHiveSettings $currentHash = (Get-FileHash $PSCommandPath -Algorithm "SHA1").Hash $savedHash = $regHive.GetValue('ScriptContentHash'); # we used to rely on timestamps but it's unreliable so make sure to clean up the reg value if ($regHive.GetValue('ScriptTimestamp')) { Remove-ItemProperty -path $kCptRegHiveSettings -name 'ScriptTimestamp' } if (! (cpt:testInternetConnectivity) ) { Write-Verbose "No internet connectivity. Postponing helper scripts update from github..." } [string] $featureDisableValue = '42' if ( (cpt:testInternetConnectivity) -and ($savedHash -ne $currentHash) -and ($savedHash -ne $featureDisableValue) ) { Write-Verbose "Detected changes in main script. Will redownload helper scripts from Github..." Write-Verbose "Current main script SHA1: $currentHash. Saved SHA1: $savedHash" Set-ItemProperty -path $kCptRegHiveSettings -name 'ScriptContentHash' -value $currentHash $shouldRedownloadForcefully = $true } } @( "io.ps1" , "visualstudio-detection.ps1" , "msbuild-expression-eval.ps1" , "msbuild-project-data.ps1" , "msbuild-project-load.ps1" , "msbuild-project-cache-repository.ps1" , "get-header-references.ps1" , "itemdefinition-context.ps1" , "jsondb-export.ps1" , "get-llvm-helper.ps1" ) | ForEach-Object { cpt:ensureScriptExists $_ $shouldRedownloadForcefully } | ForEach-Object { . $_ } Write-InformationTimed "Imported scripts" #------------------------------------------------------------------------------------------------- # do not include in list above because it is an invokable script, dot-sourcing does not work. cpt:ensureScriptExists "get-llvm.ps1" $shouldRedownloadForcefully | Out-Null #------------------------------------------------------------------------------------------------- # we may have a custom path for Clang-Tidy. Use it if that's the case. [string] $customTidyPath = (Get-QuotedPath -path ([Environment]::GetEnvironmentVariable($kVarEnvClangTidyPath))) if (![string]::IsNullOrWhiteSpace($customTidyPath)) { Set-Variable -name kClangTidy -value $customTidyPath -option Constant } else { Set-Variable -name kClangTidy -value "clang-tidy.exe" -option Constant Set-Variable -name kClangApplyReplacements -value "clang-apply-replacements.exe" -option Constant } Set-Variable -name kCacheRepositorySaveIsNeeded -value $false #------------------------------------------------------------------------------------------------- # Custom Types Write-InformationTimed "Before .NET enum types" if ($kPsMajorVersion -lt 5) { Add-Type -TypeDefinition @" public enum WorkloadType { Compile, Tidy, TidyFix } "@ Add-Type -TypeDefinition @" public enum StopReason { Unknown, ConfigurationNotFound } "@ } else { # this is much faster if PowerShell supports enums, we will save some time Invoke-Expression @" enum WorkloadType { Compile Tidy TidyFix } enum StopReason { Unknown ConfigurationNotFound } "@ } Write-InformationTimed "Created .NET enum types" #------------------------------------------------------------------------------------------------- # Global variables # temporary files created during project processing (e.g. PCH files) [System.Collections.ArrayList] $global:FilesToDeleteWhenScriptQuits = @() # filePath-fileData for SLN files located in source directory [System.Collections.Generic.Dictionary[String,String]] $global:slnFiles = @{} # flag to signal when errors are encounteres during project processing [Boolean] $global:FoundErrors = $false # directory path where tidy fix replacement files will be stored [string] $global:tidyFixReplacementDirPath = "" # default ClangPowerTools version of visual studio to use [string] $global:cptDefaultVisualStudioVersion = "2017" [string[]] $global:cptIgnoredFilesPool = @() # holds file items to process and their contextual properties (inherited + locally defined) [System.Collections.Hashtable] $global:cptFilesToProcess = @{} #------------------------------------------------------------------------------------------------- # Global functions Function Exit-Script([Parameter(Mandatory=$false)][int] $code = 0) { Write-Verbose-Array -array $global:FilesToDeleteWhenScriptQuits ` -name "Cleaning up PCH temporaries" # Clean-up foreach ($file in $global:FilesToDeleteWhenScriptQuits) { Remove-Item -LiteralPath $file -ErrorAction SilentlyContinue > $null } if ($aTidyFixFlags) { Write-Verbose "Cleaning up temporaries tidy-fix replacements" Remove-Item -path $global:tidyFixReplacementDirPath -Recurse -ErrorAction SilentlyContinue > $null } # Restore working directory Pop-Location exit $code } Function Fail-Script([parameter(Mandatory=$false)][string] $msg = "Got errors.") { if (![string]::IsNullOrEmpty($msg)) { Write-Err $msg } Exit-Script($kScriptFailsExitCode) } Function Apply-TidyFixReplacements([Parameter(Mandatory=$true) ][WorkloadType] $workloadType) { if ($workloadType -eq [WorkloadType]::TidyFix -and (Test-Path -LiteralPath $global:tidyFixReplacementDirPath)) { Write-Verbose "Apply tidy-fix replacements" [string] $pathToBinary = (Join-Path -path $global:llvmLocation ` -ChildPath $kClangApplyReplacements) & $pathToBinary $global:tidyFixReplacementDirPath Wait-AndProcessBuildJobs } } Function Get-SourceDirectory() { [bool] $isDirectory = ($(Get-Item -LiteralPath $aSolutionsPath) -is [System.IO.DirectoryInfo]) if ($isDirectory) { return $aSolutionsPath } else { return (Get-FileDirectory -filePath $aSolutionsPath) } } function Load-Solutions() { Write-Verbose "Scanning for solution files" [string] $pathToCheck = $aSolutionsPath if ($kPsMajorVersion -lt 6) { # we need not bother with long path support in PowerShell 6+ # only in Windows PowerShell $pathToCheck = "\\?\$aSolutionsPath" } $slns = Get-ChildItem -recurse -LiteralPath $pathToCheck -Filter "*$kExtensionSolution" foreach ($sln in $slns) { Write-Verbose "Caching solution file $sln" $slnPath = $sln.FullName # remove the UNC long path prefix $slnPath = $slnPath.Replace('\\?\', '') $global:slnFiles[$slnPath] = (Get-Content -LiteralPath $slnPath) Write-Verbose "Solution full path: $slnPath" Write-Verbose "Solution data length: $($global:slnFiles[$slnPath].Length)" } Write-Verbose-Array -array $global:slnFiles.Keys -name "Solution file paths" } function Get-SolutionProjects([Parameter(Mandatory=$true)][string] $slnPath) { Write-Verbose "Retrieving project list for solution $slnPath" [string] $slnDirectory = Get-FileDirectory -file $slnPath Write-Verbose "Solution directory: $slnDirectory" $matches = [regex]::Matches($global:slnFiles[$slnPath], 'Project\([{}\"A-Z0-9\-]+\) = \".*?\",\s\"(.*?)\"') Write-Verbose "Intermediate solution project matches count: $($matches.Count)" foreach ($match in $matches) { Write-Verbose $match.Groups[1].Value } [string[]] $projectAbsolutePaths = @() foreach ($projPathMatch in $matches) { [string] $matchValue = $projPathMatch.Groups[1].Value.Replace('"','') if ([string]::IsNullOrWhiteSpace($matchValue)) { continue } $projExpandedPath = [Environment]::ExpandEnvironmentVariables($matchValue) if ( ! $projExpandedPath.EndsWith($kExtensionVcxproj)) { continue } # canonize-path is smart enough to figure out if this is a relative path or not $projExpandedPath = Canonize-Path -base $slnDirectory -child $projExpandedPath -ignoreErrors $projectAbsolutePaths += @($projExpandedPath) } Write-Verbose-Array -array $projectAbsolutePaths -name "Resolved project paths for solution $slnPath" return $projectAbsolutePaths } function Get-ProjectSolution() { foreach ($slnPath in $global:slnFiles.Keys) { [string[]] $solutionProjectPaths = @(Get-SolutionProjects $slnPath) if ($solutionProjectPaths -and $solutionProjectPaths -contains $global:vcxprojPath) { return $slnPath } } return "" } Function Get-Projects() { [string[]] $projects = @() foreach ($slnPath in $global:slnFiles.Keys) { [string[]] $solutionProjects = @(Get-SolutionProjects -slnPath $slnPath) if ($solutionProjects -and $solutionProjects.Count -gt 0) { $projects += $solutionProjects } } return ($projects | Select -Unique); } Function Get-ClangIncludeDirectories( [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories ) { [string[]] $returnDirs = @() foreach ($includeDir in $includeDirectories) { $returnDirs += ("-isystem" + (Get-QuotedPath $includeDir)) } foreach ($includeDir in $additionalIncludeDirectories) { if ($aTreatAdditionalIncludesAsSystemIncludes) { $returnDirs += ("-isystem" + (Get-QuotedPath $includeDir)) } else { $returnDirs += ("-I"+ (Get-QuotedPath $includeDir)) } } return $returnDirs } Function Get-ProjectFileLanguageFlag([Parameter(Mandatory=$true)] [string] $fileFullName) { [bool] $isCpp = $true if ($fileFullName.EndsWith($kExtensionC)) { $isCpp = $false } try { [string] $compileAsVal = (Get-ProjectFileSetting -fileFullName $fileFullName -propertyName "CompileAs") [bool] $isDefault = [string]::IsNullOrWhiteSpace($compileAsVal) -or $compileAsVal -ieq "Default" if ($isDefault) { $isCpp = ! $fileFullName.EndsWith($kExtensionC) } else { $isCpp = $compileAsVal -ine $kCProjectCompile } } catch {} [string] $languageFlag = If ($isCpp) { $kClangFlagFileIsCPP } else { $kClangFlagFileIsC } return $languageFlag } Function Generate-Pch( [Parameter(Mandatory=$true)] [string] $stdafxDir , [Parameter(Mandatory=$true)] [string] $stdafxCpp , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$true)] [string] $stdafxHeaderName , [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions) { [string] $stdafxSource = (Canonize-Path -base $stdafxDir -child $stdafxHeaderName) [string] $stdafx = $stdafxSource + ".hpp" # Clients using Perforce will have their source checked-out as readonly files, so the # PCH copy would be, by-default, readonly as well, which would present problems. Make sure to remove the RO attribute. Copy-Item -LiteralPath $stdafxSource -Destination $stdafx -PassThru | Set-ItemProperty -name isreadonly -Value $false $global:FilesToDeleteWhenScriptQuits.Add($stdafx) > $null [string] $vcxprojShortName = [System.IO.Path]::GetFileNameWithoutExtension($global:vcxprojPath); [string] $stdafxPch = (Join-Path -path (Get-SourceDirectory) ` -ChildPath "$vcxprojShortName$kExtensionClangPch") Remove-Item -LiteralPath "$stdafxPch" -ErrorAction SilentlyContinue > $null $global:FilesToDeleteWhenScriptQuits.Add($stdafxPch) > $null [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $stdafxCpp) [string[]] $compilationFlags = @((Get-QuotedPath $stdafx) ,$kClangFlagMinusO ,(Get-QuotedPath $stdafxPch) ,$languageFlag ,(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) ,$kClangFlagNoUnusedArg ,$preprocessorDefinitions ) if ($kLLVMVersion -ge 11) { # this flag gets around 15% faster PCH compilation times # https://www.phoronix.com/scan.php?page=news_item&px=LLVM-Clang-11-PCH-Instant-Temp $compilationFlags += $kClangFlagFasterPch } $compilationFlags += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories # Remove empty arguments from the list because Start-Process will complain $compilationFlags = $compilationFlags | Where-Object { $_ } | Select -Unique [string] $exeToCallVerbosePath = $kClangCompiler if (![string]::IsNullOrWhiteSpace($global:llvmLocation)) { $exeToCallVerbosePath = "$($global:llvmLocation)\$exeToCallVerbosePath" } Write-Verbose "INVOKE: $exeToCallVerbosePath $compilationFlags" $kClangWorkingDir = "$(Get-SourceDirectory)" -replace '\[', '`[' -replace ']', '`]' # We could skip the WorkingDir parameter as all paths are absolute but # Powershell 3-5 has a bug when calling Start-Process from a directory containing square brackets # in its path. This can be overcome by providing escaped brackets in the WorkingDirectory arg. # Powershell 7 does not have this limitation. [System.Diagnostics.Process] $processInfo = Start-Process -FilePath $kClangCompiler ` -ArgumentList $compilationFlags ` -WorkingDirectory $kClangWorkingDir ` -NoNewWindow ` -Wait ` -PassThru if (($processInfo.ExitCode -ne 0) -and (!$aContinueOnError)) { Fail-Script "Errors encountered during PCH creation" } if (Test-Path -LiteralPath $stdafxPch) { return $stdafxPch } else { return "" } } Function Get-ExeToCall([Parameter(Mandatory=$true)][WorkloadType] $workloadType) { switch ($workloadType) { "Compile" { return $kClangCompiler } "Tidy" { return $kClangTidy } "TidyFix" { return $kClangTidy } } } Function Get-CompileCallArguments( [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$true)][string] $fileToCompile) { [string[]] $projectCompileArgs = @() if (! [string]::IsNullOrEmpty($pchFilePath) -and ! $fileToCompile.EndsWith($kExtensionC)) { $projectCompileArgs += @($kClangFlagIncludePch , (Get-QuotedPath $pchFilePath)) } [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $fileToCompile) $projectCompileArgs += @( $languageFlag , (Get-QuotedPath $fileToCompile) , @(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) , $kClangFlagSupressLINK , $preprocessorDefinitions ) $projectCompileArgs += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories if ($forceIncludeFiles) { $projectCompileArgs += $kClangFlagNoMsInclude; foreach ($file in $forceIncludeFiles) { $projectCompileArgs += "$kClangFlagForceInclude $(Get-QuotedPath $file)" } } return $projectCompileArgs } Function Get-TidyCallArguments( [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$true)][string] $fileToTidy , [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$false)][switch] $fix) { [string[]] $tidyArgs = @() if ($fix) { # Map tidy-fix replacements temprorary file path to original file path if(![string]::IsNullOrEmpty($fileToTidy)) { [string] $tidyFixReplacementYamlPath = Join-Path -Path ($global:tidyFixReplacementDirPath) ` -ChildPath ([guid]::NewGuid().ToString() + $kExtensionYaml) $tidyArgs += $kClangTidyFixExportFixes + @((Get-QuotedPath $tidyFixReplacementYamlPath)) } } $tidyArgs += (Get-QuotedPath $fileToTidy) if (![string]::IsNullOrWhiteSpace($aTidyFlags) -and ($aTidyFlags -ne $kClangTidyUseFile) -and !(Test-Path $aTidyFlags)) { $tidyArgs += "$kClangTidyFlagChecks`"$aTidyFlags`"" } if (![string]::IsNullOrWhiteSpace($aTidyFixFlags) -and ($aTidyFixFlags -ne $kClangTidyUseFile) -and !(Test-Path $aTidyFixFlags)) { $tidyArgs += "$kClangTidyFlagChecks`"$aTidyFixFlags`"" } # The header-filter flag enables clang-tidy to run on headers too. if (![string]::IsNullOrEmpty($aTidyHeaderFilter)) { if ($aTidyHeaderFilter -eq '_') { [string] $fileNameMatch = """$(Get-FileName -path $fileToTidy -noext).*""" $tidyArgs += "$kClangTidyFlagHeaderFilter$fileNameMatch" } else { $tidyArgs += "$kClangTidyFlagHeaderFilter""$aTidyHeaderFilter""" } } if ($fix) { if (![string]::IsNullOrEmpty($aAfterTidyFixFormatStyle)) { $tidyArgs += "$kClangTidyFormatStyle$aAfterTidyFixFormatStyle" } } $tidyArgs += $kClangTidyFlags $tidyArgs += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $fileToTidy) # We reuse flags used for compilation and preprocessor definitions. $tidyArgs += @(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) $tidyArgs += $preprocessorDefinitions $tidyArgs += $languageFlag if (! [string]::IsNullOrEmpty($pchFilePath) -and ! $fileToTidy.EndsWith($kExtensionC)) { $tidyArgs += @($kClangFlagIncludePch , (Get-QuotedPath $pchFilePath)) } if ($forceIncludeFiles) { $tidyArgs += $kClangFlagNoMsInclude; foreach ($file in $forceIncludeFiles) { $tidyArgs += "$kClangFlagForceInclude $file" } } return $tidyArgs } Function Get-ExeCallArguments( [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$true) ][string] $currentFile , [Parameter(Mandatory=$true) ][WorkloadType] $workloadType) { switch ($workloadType) { Compile { return Get-CompileCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToCompile $currentFile } Tidy { return Get-TidyCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToTidy $currentFile } TidyFix { return Get-TidyCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToTidy $currentFile ` -fix} } } Function Process-ProjectResult($compileResult) { $global:cptCurrentClangJobCounter = $compileResult.JobCounter Write-Debug "Receiving results for clang job $($global:cptCurrentClangJobCounter)" if (!$compileResult.Success) { Write-Err ($compileResult.Output) if (!$aContinueOnError) { # Wait for other workers to finish. They have a lock on the PCH file Get-Job -state Running | Wait-Job | Remove-Job > $null Fail-Script } $global:FoundErrors = $true } else { if ( $compileResult.Output.Length -gt 0) { Write-Output $compileResult.Output } } } Function Wait-AndProcessBuildJobs([switch]$any) { $runningJobs = @(Get-Job -state Running) if ($any) { $runningJobs | Wait-Job -Any > $null } else { $runningJobs | Wait-Job > $null } $jobData = Get-Job -State Completed foreach ($job in $jobData) { $buildResult = Receive-Job $job Process-ProjectResult -compileResult $buildResult } Remove-Job -State Completed } Function Wait-ForWorkerJobSlot() { # We allow as many background workers as we have logical CPU cores $runningJobs = @(Get-Job -State Running) if ($runningJobs.Count -ge $kLogicalCoreCount) { Wait-AndProcessBuildJobs -any } } Function Run-ClangJobs( [Parameter(Mandatory=$true)] $clangJobs , [Parameter(Mandatory=$true)][WorkloadType] $workloadType ) { # Script block (lambda) for logic to be used when running a clang job. $jobWorkToBeDone = ` { param( $job ) Push-Location -LiteralPath $job.WorkingDirectory # This temp file will hold compilation args for clang++ and clang-tidy, not to be # confused with check-flags for clang-tidy. [string] $clangConfigFile = [System.IO.Path]::GetTempFileName() [string] $clangConfigContent = "" if ($job.FilePath -like '*tidy*') { # We have to separate Clang args from Tidy args $splitparams = $job.ArgumentList -split " -- " $clangConfigContent = $splitparams[1] # We may have an explicit .clang-tidy check-flag config file to be used if (![string]::IsNullOrWhiteSpace($job.TidyFlagsTempFile) -and (Test-Path -LiteralPath $job.TidyFlagsTempFile)) { $splitparams[0] += " --config-file=""$($job.TidyFlagsTempFile)"" " } $job.ArgumentList = "$($splitparams[0]) -- --config ""$clangConfigFile""" } else { # Tell Clang to take its compilation args from a config file $clangConfigContent = $job.ArgumentList $job.ArgumentList = "--config ""$clangConfigFile""" } # escape slashes for file paths # make sure escaped double quotes are not messed up $clangConfigContent = $clangConfigContent -replace '\\([^"])', '\\$1' # save compilation arguments to clang config file $clangConfigContent > $clangConfigFile # When PowerShell encounters errors, the first one is handled differently from consecutive ones # To circumvent this, do not execute the job directly, but execute it via cmd.exe # See also https://stackoverflow.com/a/35980675 $callOutput = cmd /c "$($job.FilePath) $($job.ArgumentList) 2>&1" | Out-String $callSuccess = $LASTEXITCODE -eq 0 if (!$callSuccess) { } Remove-Item $clangConfigFile Pop-Location return New-Object PsObject -Prop @{ "File" = $job.File ; "Success" = $callSuccess ; "Output" = $callOutput ; "JobCounter" = $job.JobCounter } } if (!$aResumeAfterError) { $global:cptCurrentClangJobCounter = $clangJobs.Count } else { if (!(VariableExists 'cptCurrentClangJobCounter')) { Write-Warning "Can't resume. Previous state is unreliable. Processing all files..." $global:cptCurrentClangJobCounter = $clangJobs.Count } else { if ($global:cptCurrentClangJobCounter -gt 0) { Write-Output "Resuming from file #$($global:cptCurrentClangJobCounter)" } } } [int] $crtJobCount = $clangJobs.Count foreach ($job in $clangJobs) { if ($global:cptCurrentClangJobCounter -ge 0 -and $crtJobCount -gt $global:cptCurrentClangJobCounter) { $crtJobCount-- continue } $job.JobCounter = $crtJobCount # Check if we must wait for background jobs to complete Wait-ForWorkerJobSlot # Inform console what CPP we are processing next Write-Output "$($crtJobCount): $($job.File)" if ($aUseParallelCompile) { Start-Job -ScriptBlock $jobWorkToBeDone ` -ArgumentList $job ` -ErrorAction Continue > $null } else { $compileResult = Invoke-Command -ScriptBlock $jobWorkToBeDone ` -ArgumentList $job Process-ProjectResult -compileResult $compileResult $global:cptCurrentClangJobCounter = $compileResult.JobCounter } $crtJobCount -= 1 } Wait-AndProcessBuildJobs $global:cptCurrentClangJobCounter = -1 # stop the mechanism after one project } Function Get-ProjectFileSetting( [Parameter(Mandatory=$true)] [string] $fileFullName , [Parameter(Mandatory=$true)] [string] $propertyName , [Parameter(Mandatory=$false)][string] $defaultValue) { if (!$global:cptFilesToProcess.ContainsKey($fileFullName)) { throw "File $aFileFullName is not in processing queue." } if ($global:cptFilesToProcess[$fileFullName].Properties -and $global:cptFilesToProcess[$fileFullName].Properties.ContainsKey($propertyName)) { return $global:cptFilesToProcess[$fileFullName].Properties[$propertyName] } if ($defaultValue -ne $null) { return $defaultValue } throw "Could not find $propertyName for $fileFullName. No default value specified." } Function Process-Project( [Parameter(Mandatory=$true)] [string] $vcxprojPath , [Parameter(Mandatory=$true)] [WorkloadType] $workloadType , [Parameter(Mandatory=$false)][string] $platformConfig ) { #----------------------------------------------------------------------------------------------- $global:cptCurrentConfigPlatform = $platformConfig $projCounter = $global:cptProjectCounter [string] $projectOutputString = ("PROJECT$(if ($projCounter -gt 1) { " #$projCounter" } else { } ): " + $vcxprojPath) [bool] $loadedFromCache = $false try { Set-Variable 'kCacheRepositorySaveIsNeeded' -value $false Write-InformationTimed "Before project load" if (Is-CacheLoadingEnabled) { Write-InformationTimed "Trying to load project from cache" $loadedFromCache = Load-ProjectFromCache $vcxprojPath if (!$loadedFromCache) { LoadProject $vcxprojPath Set-Variable 'kCacheRepositorySaveIsNeeded' -value $true } } else { LoadProject $vcxprojPath } Write-InformationTimed "After project load" Write-Output "$projectOutputString [$($global:cptCurrentConfigPlatform)]" } catch [ProjectConfigurationNotFound] { [string] $configPlatform = ([ProjectConfigurationNotFound]$_.Exception).ConfigPlatform Write-Output "$projectOutputString [$($global:cptCurrentConfigPlatform)]" Write-Output ("Skipped. Configuration not present: " + $configPlatform); Pop-Location return } Write-InformationTimed "Detecting toolset" #----------------------------------------------------------------------------------------------- # DETECT PLATFORM TOOLSET if (! $loadedFromCache) { [string] $global:platformToolset = Get-ProjectPlatformToolset Write-Verbose "Platform toolset: $platformToolset" Add-ToProjectSpecificVariables 'platformToolset' if ( $platformToolset -match "^v\d+(_xp)?$" ) { [int] $toolsetVersion = [int]$platformToolset.Remove(0, 1).Replace("_xp", "") [string] $desiredVisualStudioVer = "" # toolsets attached to specific Visual Studio versions if ($toolsetVersion -le 120) { $desiredVisualStudioVer = "2013" } elseif ($toolsetVersion -eq 140) { $desiredVisualStudioVer = "2015" } elseif ($toolsetVersion -eq 141) { $desiredVisualStudioVer = "2017" } elseif ($toolsetVersion -eq 142) { $desiredVisualStudioVer = "2019"; } elseif ($toolsetVersion -eq 143) { $desiredVisualStudioVer = "2022"; } [string] $desiredVisualStudioVerNumber = (Get-VisualStudio-VersionNumber $desiredVisualStudioVer) if ($VisualStudioVersion -ne $desiredVisualStudioVerNumber) { [bool] $shouldReload = $false if ([double]::Parse($VisualStudioVersion) -gt [double]::Parse($desiredVisualStudioVerNumber)) { # in this case we may have a newer Visual Studio with older toolsets installed [string[]] $supportedVsToolsets = Get-VisualStudioToolsets if ($supportedVsToolsets -notcontains $toolsetVersion) { $shouldReload = $true } else { Write-Verbose "[ INFO ] Detected project using older toolset ($toolsetVersion)" Write-Verbose "Loading using Visual Studio $VisualStudioVersion with toolset $toolsetVersion" } } else { # project uses a newer VS version, clearly we should reload using the newer version $shouldReload = $true } if ($shouldReload) { # We need to reload everything and use the VS version we decided upon above Write-Verbose "[ RELOAD ] Project will reload because of toolset requirements change..." Write-Verbose "Current = $VisualStudioVersion. Required = $desiredVisualStudioVerNumber." $global:cptVisualStudioVersion = $desiredVisualStudioVer LoadProject($vcxprojPath) Write-InformationTimed "Project reloaded" } } } Write-InformationTimed "Detected toolset" #----------------------------------------------------------------------------------------------- # FIND FORCE INCLUDES [string[]] $global:forceIncludeFiles = @(Get-ProjectForceIncludes) Write-Verbose-Array -array $forceIncludeFiles -name "Force includes" Add-ToProjectSpecificVariables 'forceIncludeFiles' #----------------------------------------------------------------------------------------------- # DETECT PROJECT PREPROCESSOR DEFINITIONS [string[]] $global:preprocessorDefinitions = @(Get-ProjectPreprocessorDefines) if ([int]$global:cptVisualStudioVersion -ge 2017) { # [HACK] pch generation crashes on VS 15.5 because of STL library, known bug. # Triggered by addition of line directives to improve std::function debugging. # There's a definition that supresses line directives. $preprocessorDefinitions += @('"-D_DEBUG_FUNCTIONAL_MACHINERY"') } Add-ToProjectSpecificVariables 'preprocessorDefinitions' Write-InformationTimed "Detected preprocessor definitions" Write-Verbose-Array -array $preprocessorDefinitions -name "Preprocessor definitions" #----------------------------------------------------------------------------------------------- # DETECT PROJECT ADDITIONAL INCLUDE DIRECTORIES AND CONSTRUCT INCLUDE PATHS [string[]] $global:additionalIncludeDirectories = @(Get-ProjectAdditionalIncludes) Write-Verbose-Array -array $additionalIncludeDirectories -name "Additional include directories" Add-ToProjectSpecificVariables 'additionalIncludeDirectories' [string[]] $includeDirectories = @(Get-ProjectIncludeDirectories) Write-Verbose-Array -array $includeDirectories -name "Include directories" Add-ToProjectSpecificVariables 'includeDirectories' Write-InformationTimed "Detected include directories" #----------------------------------------------------------------------------------------------- # FIND LIST OF CPPs TO PROCESS $global:projectAllCpps = @{} foreach ($fileToCompileInfo in (Get-ProjectFilesToCompile)) { if ($fileToCompileInfo.File) { $global:projectAllCpps[$fileToCompileInfo.File] = $fileToCompileInfo } } Add-ToProjectSpecificVariables 'projectAllCpps' Write-InformationTimed "Detected cpps to process" } # past the caching boundary here, we must see what else needs to be computed live $global:cptFilesToProcess = $global:projectAllCpps # reset to full project cpp list #----------------------------------------------------------------------------------------------- # LOCATE STDAFX.H DIRECTORY [string] $stdafxCpp = "" [string] $stdafxDir = "" [string] $stdafxHeader = "" [string] $stdafxHeaderFullPath = "" [bool] $kPchIsNeeded = $global:cptFilesToProcess.Keys.Count -ge 2 if ($kPchIsNeeded) { # if we have only one rooted file in the script parameters, then we don't need to detect PCH if ($aCppToCompile.Count -eq 1 -and [System.IO.Path]::IsPathRooted($aCppToCompile[0])) { $kPchIsNeeded = $false } } foreach ($projCpp in $global:cptFilesToProcess.Keys) { if ( (Get-ProjectFileSetting -fileFullName $projCpp -propertyName 'PrecompiledHeader') -ieq 'Create') { $stdafxCpp = $projCpp } } if (![string]::IsNullOrEmpty($stdafxCpp)) { Write-Verbose "PCH cpp name: $stdafxCpp" if ($forceIncludeFiles.Count -gt 0) { $stdafxHeader = $forceIncludeFiles[0] } if (!$stdafxHeader) { $stdafxHeader = Get-PchCppIncludeHeader -pchCppFile $stdafxCpp } if (!$stdafxHeader) { try { $stdafxHeader = Get-ProjectFileSetting -fileFullName $stdafxCpp -propertyName 'PrecompiledHeaderFile' } catch {} } Write-Verbose "PCH header name: $stdafxHeader" $stdafxDir = Get-ProjectStdafxDir -pchHeaderName $stdafxHeader ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories } if ([string]::IsNullOrEmpty($stdafxDir)) { Write-Verbose ("No PCH information for this project!") $kPchIsNeeded = $false } else { Write-Verbose ("PCH directory: $stdafxDir") $includeDirectories = @(Remove-PathTrailingSlash -path $stdafxDir) + $includeDirectories $stdafxHeaderFullPath = Canonize-Path -base $stdafxDir -child $stdafxHeader -ignoreErrors if (!$kPchIsNeeded) { Write-Verbose "PCH is disabled for this project. Will not generate." } } Write-InformationTimed "Detected PCH information" #----------------------------------------------------------------------------------------------- # FILTER LIST OF CPPs TO PROCESS if ($global:cptFilesToProcess.Count -gt 0 -and $aCppToIgnore.Count -gt 0) { [System.Collections.Hashtable] $filteredCpps = @{} foreach ($cpp in $global:cptFilesToProcess.Keys) { if ( ! (Should-IgnoreFile -file $cpp) ) { $filteredCpps[$cpp] = $global:cptFilesToProcess[$cpp] } } $global:cptFilesToProcess = $filteredCpps } if ($global:cptFilesToProcess.Count -gt 0 -and $aCppToCompile.Count -gt 0) { [System.Collections.Hashtable] $filteredCpps = @{} [bool] $dirtyStdafx = $false foreach ($cpp in $aCppToCompile) { if ($cpp -ieq $stdafxHeaderFullPath) { # stdafx modified => compile all $dirtyStdafx = $true break } if (![string]::IsNullOrEmpty($cpp)) { if ([System.IO.Path]::IsPathRooted($cpp)) { if ($global:cptFilesToProcess.ContainsKey($cpp)) { # really fast, use cache $filteredCpps[$cpp] = $global:cptFilesToProcess[$cpp] } } else { # take the slow road and check if it matches $global:cptFilesToProcess.Keys | Where-Object { IsFileMatchingName -filePath $_ -matchName $cpp } | ` ForEach-Object { $filteredCpps[$_] = $global:cptFilesToProcess[$_] } } } } if (!$dirtyStdafx) { $global:cptFilesToProcess = $filteredCpps } else { Write-Verbose "PCH header has been targeted as dirty. Building entire project" } } Write-InformationTimed "Filtered out CPPs from bucket" Write-Verbose ("Processing " + $global:cptFilesToProcess.Count + " cpps") #----------------------------------------------------------------------------------------------- # CREATE PCH IF NEED BE, ONLY FOR TWO CPPS OR MORE # # JSON Compilation Database file will outlive this execution run, while the PCH is temporary # so we disable PCH creation for that case as well. if ($kPchIsNeeded -and $global:cptFilesToProcess.Count -lt 2) { $kPchIsNeeded = $false } [string] $pchFilePath = "" if ($kPchIsNeeded -and !$aExportJsonDB) { # COMPILE PCH Write-Verbose "Generating PCH..." $pchFilePath = Generate-Pch -stdafxDir $stdafxDir ` -stdafxCpp $stdafxCpp ` -stdafxHeaderName $stdafxHeader ` -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories Write-Verbose "PCH: $pchFilePath" if ([string]::IsNullOrEmpty($pchFilePath) -and $aContinueOnError) { Write-Output "Skipping project. Reason: cannot create PCH." return } Write-InformationTimed "Created PCH" } if ($kCacheRepositorySaveIsNeeded) { Write-InformationTimed "Before serializing project" Save-ProjectToCacheRepo Write-InformationTimed "After serializing project" } #----------------------------------------------------------------------------------------------- # PROCESS CPP FILES. CONSTRUCT COMMAND LINE JOBS TO BE INVOKED $clangJobs = @() # Create directory where to store tidy fix replacements if ($aTidyFixFlags) { $global:tidyFixReplacementDirPath = (Join-Path -path $kCptTidyFixReplacementsDir ` -ChildPath (Split-Path (Get-SourceDirectory) -Leaf)) ` + "_" + ([guid]::NewGuid().ToString()) # check if SolutionDir for tidy fix replacements already exists if (Test-Path -LiteralPath $global:tidyFixReplacementDirPath) { Remove-Item $global:tidyFixReplacementDirPath -Recurse New-Item -Path $global:tidyFixReplacementDirPath -ItemType "directory" > $null } else { New-Item -Path $global:tidyFixReplacementDirPath -ItemType "directory" > $null } } foreach ($cpp in $global:cptFilesToProcess.Keys) { [string] $cppPchSetting = Get-ProjectFileSetting -propertyName 'PrecompiledHeader' -fileFullName $cpp -defaultValue 'Use' if ($cppPchSetting -ieq 'Create') { continue # no point in compiling the PCH CPP } [string[]] $cppForceIncludes = Get-FileForceIncludes -fileFullName $cpp [string] $exeToCall = Get-ExeToCall -workloadType $workloadType [string] $finalPchPath = $pchFilePath if ($cppPchSetting -ieq 'NotUsing') { $finalPchPath = "" Write-Verbose "`n[PCH] Will ignore precompiled headers for $cpp`n" } [string] $exeArgs = Get-ExeCallArguments -workloadType $workloadType ` -pchFilePath $finalPchPath ` -preprocessorDefinitions $preprocessorDefinitions ` -forceIncludeFiles $cppForceIncludes ` -currentFile $cpp ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories $newJob = New-Object PsObject -Prop @{ 'FilePath' = $exeToCall ; 'WorkingDirectory' = Get-SourceDirectory ; 'ArgumentList' = $exeArgs ; 'File' = $cpp ; 'JobCounter' = 0 <# will be lazy initialized #> ; 'TidyFlagsTempFile' = $kClangTidyFlagTempFile } $clangJobs += $newJob } Write-InformationTimed "Created job workers" #----------------------------------------------------------------------------------------------- # PRINT DIAGNOSTICS if ($clangJobs.Count -ge 1) { [string] $exeToCallVerbosePath = $exeToCall if (![string]::IsNullOrWhiteSpace($global:llvmLocation)) { $exeToCallVerbosePath = "$($global:llvmLocation)\$exeToCallVerbosePath" } Write-Verbose "INVOKE: $exeToCallVerbosePath $($clangJobs[0].ArgumentList)" } Write-InformationTimed "Running workers" #----------------------------------------------------------------------------------------------- # RUN CLANG JOBS if ($aExportJsonDB) { foreach ($job in $clangJobs) { [string] $clangToolPath = $job.FilePath if (Exists-Command $clangToolPath) { # see precisely what path the tool has, to prevent ambiguities. $clangToolPath = (Get-Command $job.FilePath).Source } [string] $clangCommand = """$clangToolPath"" $($job.ArgumentList)" JsonDB-Push -directory $job.WorkingDirectory -file $job.File -command $clangCommand } } else { Run-ClangJobs -clangJobs $clangJobs -workloadType $workloadType Apply-TidyFixReplacements -workloadType $workloadType } } #------------------------------------------------------------------------------------------------- # Script entry point Clear-Host # clears console Write-InformationTimed "Cleared console. Let's begin..." #------------------------------------------------------------------------------------------------- # If we didn't get a location to run CPT at, use the current working directory if (!$aSolutionsPath) { $aSolutionsPath = (Get-Location).Path } # ------------------------------------------------------------------------------------------------ # Load param values from configuration file (if exists) Update-ParametersFromConfigFile Write-InformationTimed "Updated script parameters from cpt.config" # ------------------------------------------------------------------------------------------------ # Initialize the Visual Studio version variable $global:cptVisualStudioVersion = If ( $aVisualStudioVersion ) ` { $aVisualStudioVersion } Else ` { $global:cptDefaultVisualStudioVersion } #------------------------------------------------------------------------------------------------- # Print script parameters Print-InvocationArguments Write-InformationTimed "Print args" [WorkloadType] $workloadType = [WorkloadType]::Compile if (![string]::IsNullOrEmpty($aTidyFlags)) { $workloadType = [WorkloadType]::Tidy if (Test-Path -LiteralPath $aTidyFlags) { $kClangTidyFlagTempFile = $aTidyFlags } } if (![string]::IsNullOrEmpty($aTidyFixFlags)) { $workloadType = [WorkloadType]::TidyFix if (Test-Path -LiteralPath $aTidyFixFlags) { $kClangTidyFlagTempFile = $aTidyFixFlags } } #------------------------------------------------------------------------------------------------- # Script entry point Write-Verbose "CPU logical core count: $kLogicalCoreCount" # If LLVM is not in PATH try to detect it automatically [string] $global:llvmLocation = "" $clangToolWeNeed = Get-ExeToCall -workloadType $workloadType $global:llvmLocation = Ensure-LLVMTool-IsPresent $clangToolWeNeed if ($aTidyFixFlags) { Ensure-LLVMTool-IsPresent $kClangApplyReplacements } if (![string]::IsNullOrEmpty($global:llvmLocation)) { $env:Path += ";" + $global:llvmLocation } Set-Variable -name "kLLVMVersion" -value (Get-ClangVersion $clangToolWeNeed) -scope Global # initialize JSON compilation db support, if required if ($aExportJsonDB) { JsonDB-Init } Push-Location -LiteralPath (Get-SourceDirectory) Write-InformationTimed "Searching for solutions" # fetch .sln paths and data Load-Solutions Write-InformationTimed "End solution search" # This PowerShell process may already have completed jobs. Discard them. Remove-Job -State Completed Write-InformationTimed "Discarded already finished jobs" Write-Verbose "Source directory: $(Get-SourceDirectory)" Write-Verbose "Scanning for project files" Write-InformationTimed "Searching for project files" [System.IO.FileInfo[]] $projects = @(Get-Projects) [int] $initialProjectCount = $projects.Count Write-Verbose ("Found $($projects.Count) projects") Write-InformationTimed "End project files search" # ------------------------------------------------------------------------------------------------ # If we get headers in the -file arg we have to detect CPPs that include that header if ($aCppToCompile -and $aCppToCompile.Count -gt 0) { # We've been given particular files to compile. If headers are among them # we'll find all source files that include them and tag them for processing. Write-Progress -Activity "#Include discovery" -Status "Detecting CPPs which include the specified headers..." [string[]] $headerRefs = @(Get-HeaderReferences -files $aCppToCompile) Write-Progress -Activity "#Include discovery" -Completed if ($headerRefs.Count -gt 0) { Write-Verbose-Array -name "Detected referenced source files to process" -array $headerRefs $aCppToCompile += @($headerRefs | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } } if ($aCppToIgnore -and $aCppToIgnore.Count -gt 0) { # We've been given particular files to ignore. If headers are among them # we'll find all source files that include them and tag them to be ignored. Write-Progress -Activity "CPP Ignore Detection" -Status "Detecting CPPs which include the specified ignore-headers..." [string[]] $headerRefs = @(Get-HeaderReferences -files $aCppToIgnore) Write-Progress -Activity "CPP Ignore Detection" -Completed if ($headerRefs.Count -gt 0) { Write-Verbose-Array -name "Detected referenced source files to ignore" -array $headerRefs $global:cptIgnoredFilesPool += @($headerRefs | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } } # ------------------------------------------------------------------------------------------------ Write-InformationTimed "Starting projects" [System.IO.FileInfo[]] $projectsToProcess = @() [System.IO.FileInfo[]] $ignoredProjects = @() if (!$aVcxprojToCompile -and !$aVcxprojToIgnore) { $projectsToProcess = $projects # we process all projects } else { # some filtering has to be done if ($aVcxprojToCompile) { $projects = $projects | Where-Object { Should-CompileProject -vcxprojPath $_.FullName } $projectsToProcess = @($projects) } if ($aVcxprojToIgnore) { $projectsToProcess = @($projects | ` Where-Object { !(Should-IgnoreProject -vcxprojPath $_.FullName ) }) $ignoredProjects = ($projects | Where-Object { $projectsToProcess -notcontains $_ }) } } if ($projectsToProcess.Count -eq 0) { Write-Err "Cannot find given project(s)" } if ($aCppToCompile -and $projectsToProcess.Count -gt 1) { # We've been given particular files to compile, we can narrow down # the projects to be processed (those that include any of the particular files) # For obvious performance reasons, no filtering is done when there's only one project to process. [System.IO.FileInfo[]] $projectsThatIncludeFiles = @(Get-SourceCodeIncludeProjects -projectPool $projectsToProcess ` -files $aCppToCompile) Write-Verbose-Array -name "Detected projects" -array $projectsThatIncludeFiles # some projects include files using wildcards, we won't match anything in them # so when matching nothing we don't do filtering at all if ($projectsThatIncludeFiles) { $projectsToProcess = $projectsThatIncludeFiles } } if ($projectsToProcess.Count -eq $initialProjectCount) { Write-Verbose "PROCESSING ALL PROJECTS" } else { if ($projectsToProcess.Count -gt 1) { Write-Array -name "PROJECTS" -array $projectsToProcess } if ($ignoredProjects) { Write-Array -name "IGNORED PROJECTS" -array $ignoredProjects } } # ------------------------------------------------------------------------------------------------ if (!$aResumeAfterError) { $global:cptProjectCounter = $projectsToProcess.Length } else { if (!(VariableExists 'cptProjectCounter') -or !(VariableExists 'cptProjectsBucket')) { Write-Warning "Can't resume. Previous state is unreliable. Processing all projects..." $global:cptProjectCounter = $projectsToProcess.Length } elseif ((Compare-Object $projectsToProcess $global:cptProjectsBucket)) { Write-Warning "Can't resume. Previous state is unreliable. Processing all projects...`n`nREMINDER: Don't change arguments when adding -resume.`n`n" $global:cptProjectCounter = $projectsToProcess.Length } else { Write-Output "Resuming from project #$($global:cptProjectCounter)" } } [System.IO.FileInfo[]] $global:cptProjectsBucket = $projectsToProcess [int] $localProjectCounter = $projectsToProcess.Length; foreach ($project in $projectsToProcess) { if ($localProjectCounter -gt $global:cptProjectCounter) { $localProjectCounter--; continue } [string] $vcxprojPath = $project.FullName; [string[]] $configPlatforms = $aVcxprojConfigPlatform if ($configPlatforms.Count -eq 0) { $configPlatforms += @("") } foreach ($crtPlatformConfig in $configPlatforms) { Write-InformationTimed "Before project process" Process-Project -vcxprojPath $vcxprojPath -workloadType $workloadType -platformConfig $crtPlatformConfig Write-InformationTimed "After project process" Write-Output "" # empty line separator } $localProjectCounter -= 1 $global:cptProjectCounter = $localProjectCounter } if ($aExportJsonDB) { JsonDB-Finalize } Write-InformationTimed "Goodbye" if ($global:FoundErrors) { Fail-Script } else { Exit-Script } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/get-header-references.ps1 ================================================ # line limit for scanning files for #include [int] $global:cpt_header_include_line_limit = 30 # after the line limit, if any includes are still found we # extend the limit with this value [int] $global:cpt_header_include_line_extension = 10 [string[]] $global:headerExtensions = @('h', 'hh', 'hpp', 'hxx') [string[]] $global:sourceExtensions = @('c', 'cc', 'cpp', 'cxx') Function detail:FindHeaderReferences( [Parameter(Mandatory = $false)] [string[]] $headers , [Parameter(Mandatory = $false)] [System.IO.FileInfo[]] $filePool , [Parameter(Mandatory = $false)] [System.Collections.Hashtable] $alreadyFound = @{} ) { if (!$headers) { return @() } [string] $regexHeaders = @($headers | ForEach-Object { ([System.IO.FileInfo]$_).BaseName } ` | Select-Object -Unique ` | Where-Object { $_ -ine "stdafx" -and $_ -ine "resource" } ` ) -join '|' if ($regexHeaders.Length -eq 0) { return @() } [string] $regex = "[/""]($regexHeaders)\.($($global:headerExtensions -join '|'))""" Write-Debug "Regex for header reference find: $regex`n" [string[]] $returnRefs = @() if (!$filePool) { # initialize pool of files that we look into [string[]] $allFileExts = @(($global:sourceExtensions + ` $global:headerExtensions) | ForEach-Object { "*.$_" }) $filePool = Get-ChildItem -recurse -include $allFileExts } foreach ($file in $filePool) { if ($alreadyFound.ContainsKey($file.FullName)) { continue } [int] $lineCount = 0 [int] $lineLimit = $global:cpt_header_include_line_limit foreach($line in [System.IO.File]::ReadLines($file)) { if ([string]::IsNullOrWhiteSpace($line)) { # skip empty lines continue } if ($line -match $regex) { if ( ! $alreadyFound.ContainsKey($file.FullName)) { $alreadyFound[$file.FullName] = $true $returnRefs += $file.FullName } if ($lineCount -eq $lineLimit) { # we still have includes to scan $lineLimit += $global:cpt_header_include_line_extension } } if ( (++$lineCount) -gt $lineLimit) { break } } } if ($returnRefs.Count -gt 0) { [string[]] $headersLeftToSearch = @($returnRefs | Where-Object ` { FileHasExtension -filePath $_ ` -ext $global:headerExtensions } ) if ($headersLeftToSearch.Count -gt 0) { Write-Debug "[!] Recursive reference detection in progress for: " Write-Debug ($headersLeftToSearch -join "`n") $returnRefs += detail:FindHeaderReferences -headers $headersLeftToSearch ` -filePool $filePool ` -alreadyFound $alreadyFound } } $returnRefs = $returnRefs | Select-Object -Unique Write-Debug "Found header refs (regex $regex)" Write-Debug ($returnRefs -join "`n") return $returnRefs } <# .SYNOPSIS Detects source files that reference given headers. Returns an array with full paths of files that reference the header(s). .DESCRIPTION When modifying a header, all translation units that include that header have to compiled. This function detects those files that include it. .PARAMETER files Header files of which we want references to be found Any files that are not headers will be ignored. #> Function Get-HeaderReferences([Parameter(Mandatory = $false)][string[]] $files) { if ($files.Count -eq 0) { return @() } # we take interest only in files that reference headers $files = @($files | Where-Object { FileHasExtension -filePath $_ ` -ext $global:headerExtensions }) if ($files.Count -eq 0) { return @() } [string[]] $refs = @() if ($files.Count -gt 0) { Write-Verbose-Timed "Headers changed. Detecting which source files to process..." $refs = detail:FindHeaderReferences -headers $files Write-Verbose-Timed "Finished detecting source files." $refs = $refs | Where-Object { ! [string]::IsNullOrWhiteSpace($_) } } return $refs } <# .SYNOPSIS Detects projects that reference given source files (i.e. cpps). Returns an array with full paths of detected projects. .DESCRIPTION When modifying a file, only projects that reference that file should be recompiled. .PARAMETER projectPool Projects in which to look .PARAMETER files Source files to be found in projects. #> Function Get-SourceCodeIncludeProjects([Parameter(Mandatory = $false)][System.IO.FileInfo[]] $projectPool, [Parameter(Mandatory = $false)][string[]] $files) { [System.Collections.Hashtable] $fileCache = @{} foreach ($file in $files) { if ($file) { $fileCache[$file.Trim().ToLower()] = $true } } [System.IO.FileInfo[]] $matchedProjects = @() [string] $clPrefix = '' [string] $endGroupTag = '' foreach ($proj in $projectPool) { [string] $projDir = $proj.Directory.FullName [bool] $inClIncludeSection = $false foreach($line in [System.IO.File]::ReadLines($proj.FullName)) { $line = $line.Trim() if ($line.StartsWith($clPrefix)) { if (!$inClIncludeSection) { $inClIncludeSection = $true } [string] $filePath = $line.Substring($clPrefix.Length, ` $line.Length - $clPrefix.Length - $clSuffix.Length) if (![System.IO.Path]::IsPathRooted($filePath)) { $filePath = Canonize-Path -base $projDir -child $filePath -ignoreErrors } if ([string]::IsNullOrEmpty($filePath)) { continue } [System.IO.FileInfo] $sourceFile = $filePath if ($fileCache.ContainsKey($sourceFile.FullName.Trim().ToLower()) -or ` $fileCache.ContainsKey($sourceFile.Name.Trim().ToLower())) { $matchedProjects += $proj break } } if ($inClIncludeSection -and $line -eq $endGroupTag) { # nothing more to check in this project break } } } return $matchedProjects } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/get-llvm-helper.ps1 ================================================ # This helper makes sure we have the LLVM tool we require present on disk. # If it's not available then we download it from GitHub. # REQUIRES "io.ps1" to be included # ------------------------------------------------------------------------------------------------ # Default install locations of LLVM. If present there, we automatically use it Set-Variable -name kLLVMInstallLocations -value @("${Env:ProgramW6432}\LLVM\bin" ,"${Env:ProgramFiles(x86)}\LLVM\bin" ) -option Constant #Url to assets (clang++ and clang-tidy) from previous release made by Clang Power Tools on github Set-Variable -name kCptGithubLlvm -value "https://github.com/Caphyon/clang-power-tools/releases/download/v2023.6.0" ` -option Constant Set-Variable -name kCptGithubLlvmVersion -value "16.0.6 (LLVM 16.0.6)" -Option Constant # Clang Constants Set-Variable -name kCss -value "clang-doc-default-stylesheet.css" -option Constant Set-Variable -name kClangDoc -value "clang-doc.exe" -option Constant Set-Variable -name kIndex -value "index.js" -option Constant Function Move-Tool-To-LlvmBin([Parameter(Mandatory = $true)][string] $clangToolWeNeed, [Parameter(Mandatory = $true)][string] $llvmLiteBinDir) { $llvmLiteDir = (get-item $llvmLiteBinDir).Parent.FullName if(Test-Path "$llvmLiteDir\$clangToolWeNeed") { Move-Item -Path "$llvmLiteDir\$clangToolWeNeed" -Destination "$llvmLiteBinDir\$clangToolWeNeed" } } Function Ensure-LLVMTool-IsPresent([Parameter(Mandatory = $true)][string] $clangToolWeNeed) { [string] $ret = "" # see if we can reach the tool through PATH if (Exists-Command $clangToolWeNeed ) { [System.IO.FileInfo] $toolPath = (Get-Command $clangToolWeNeed).Source return $toolPath.Directory.FullName } # search in predefined locations foreach ($locationLLVM in $kLLVMInstallLocations) { if (Test-Path -LiteralPath "$locationLLVM\$clangToolWeNeed") { return $locationLLVM } } # download read-to-use binary from github [string] $llvmLiteDirParent = "${env:APPDATA}\ClangPowerTools" [string] $llvmLiteDir = "$llvmLiteDirParent\LLVM_Lite\Bin" [string] $llvmLiteToolPath = "$llvmLiteDir\$clangToolWeNeed" if (Test-Path $llvmLiteToolPath) { $versionPresent = (Get-Item $llvmLiteToolPath).VersionInfo.ProductVersion if ($versionPresent -eq $kCptGithubLlvmVersion) { # we already have downloaded the latest standalone tool, reuse it return $llvmLiteDir } } if (Test-InternetConnectivity) { if ([string]::IsNullOrEmpty($ret)) { if (!(Test-Path $llvmLiteDirParent)) { New-Item -Path $llvmLiteDirParent -ItemType Directory | Out-Null } if (!(Test-Path $llvmLiteDir)) { New-Item -Path $llvmLiteDir -ItemType Directory | Out-Null } # check if tool already exists Llvm_lite folder, to move it in Llvm_lite/bin Move-Tool-To-LlvmBin $clangToolWeNeed $llvmLiteDir # the displayed progress slows downloads considerably, so disable it $prevPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' [string] $clangCompilerWebPath = "$kCptGithubLlvm/$clangToolWeNeed" if (Test-Path $llvmLiteToolPath) { # we have an older version downloaded, remove it first Remove-Item $llvmLiteToolPath -Force } Write-Verbose "Downloading $clangToolWeNeed $kCptGithubLlvmVersion ..." # grab ready-to-use LLVM binaries from Github Invoke-WebRequest -Uri $clangCompilerWebPath -OutFile $llvmLiteToolPath # download css file if needed tool is clang-doc.exe if($clangToolWeNeed -eq $kClangDoc) { [string] $parentDirLite = (get-item $llvmLiteDir ).Parent.FullName [string] $llvmLiteCssFolderPath = "$parentDirLite\share\clang" if (!(Test-Path $llvmLiteCssFolderPath)) { New-Item $llvmLiteCssFolderPath -ItemType Directory | Out-Null } Invoke-WebRequest -Uri "$kCptGithubLlvm/$kCss" -OutFile "$llvmLiteCssFolderPath\$kCss" Invoke-WebRequest -Uri "$kCptGithubLlvm/$kIndex" -OutFile "$llvmLiteCssFolderPath\$kIndex" } $ProgressPreference = $prevPreference $ret = $llvmLiteDir } } return $ret } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/get-llvm.ps1 ================================================ <# .SYNOPSIS Downloads ready-to-use one or more LLVM binaries, if not already available on system. .DESCRIPTION Purpose of this script is to ensure that LLVM binaries are available for use. The strategy used, for each tool, is: * search in PATH * search in Program Files * search in %APPDATA%\ClangPowerTools\LLVM_Lite * if not found, download tool and save in LLVM_Lite location .PARAMETER aTool Alias 'tool'. The LLVM tool(s) to potentially download. .NOTES Author: Gabriel Diaconita, Marina Rusu #> #Requires -Version 3 param( [alias("tool")] [Parameter(Mandatory=$false, HelpMessage="LLVM tool(s) to ensure exist")] [string[]] $aTools = @() ) Set-StrictMode -version latest $ErrorActionPreference = 'Continue' . "$PSScriptRoot\io.ps1" . "$PSScriptRoot\get-llvm-helper.ps1" $ret = @() foreach ($tool in $aTools) { [string] $toolLocation = Ensure-LLVMTool-IsPresent $tool $ret += @($toolLocation) } Write-Output $ret ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/io.ps1 ================================================ #Console IO # ------------------------------------------------------------------------------------------------ Function Write-Message([parameter(Mandatory = $true)][string] $msg , [Parameter(Mandatory = $true)][System.ConsoleColor] $color) { $foregroundColor = $host.ui.RawUI.ForegroundColor $host.ui.RawUI.ForegroundColor = $color Write-Output $msg $host.ui.RawUI.ForegroundColor = $foregroundColor } function Write-InformationTimed($message) { if ($InformationPreference -eq "SilentlyContinue") { return } [DateTime] $lastTime = [DateTime]::Now [string] $kTimeStampVar = "lastCptTimestamp" if (VariableExists -name $kTimeStampVar) { $lastTime = (Get-Variable -name $kTimeStampVar -scope Global).Value } Set-Variable -name $kTimeStampVar -scope Global -value ([DateTime]::Now) [DateTime] $now = [DateTime]::Now; [System.TimeSpan] $delta = $now - $lastTime Write-Information "$message at $([DateTime]::Now.ToString("mm:ss:fff")). dt = $($delta.TotalMilliseconds)" } # Writes an error without the verbose PowerShell extra-info (script line location, etc.) Function Write-Err([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Message -msg $msg -color Red } Function Write-Success([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Message -msg $msg -color Green } Function Write-Array($array, $name) { Write-Output "$($name):" $array | ForEach-Object { Write-Output " $_" } Write-Output "" # empty line separator } Function Write-Verbose-Array($array, $name) { if ($VerbosePreference -eq "SilentlyContinue") { return } Write-Verbose "$($name):" $array | ForEach-Object { Write-Verbose " $_" } Write-Verbose "" # empty line separator } Function Write-Verbose-Timed([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Verbose "$([DateTime]::Now.ToString("[HH:mm:ss]")) $msg" } Function Print-InvocationArguments() { if ($VerbosePreference -eq "SilentlyContinue") { return } $bParams = $PSCmdlet.MyInvocation.BoundParameters if ($bParams) { [string] $paramStr = "clang-build.ps1 invocation args: `n" foreach ($key in $bParams.Keys) { $paramStr += " $($key) = $($bParams[$key]) `n" } Write-Verbose $paramStr } } Function Print-CommandParameters([Parameter(Mandatory = $true)][string] $command) { $params = @() foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters)) { if (!$param.HelpMessage) { continue } $params += New-Object PsObject -Prop @{ "Option" = "-$($param.Aliases[0])" ; "Description" = $param.HelpMessage } } $params | Sort-Object -Property "Option" | Out-Default } # Function that gets the name of a command argument when it is only known by its alias # For streamlining purposes, it also accepts the name itself. Function Get-CommandParameterName([Parameter(Mandatory = $true)][string] $command ,[Parameter(Mandatory = $true)][string] $nameOrAlias) { foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters)) { if ($param.Name -eq $nameOrAlias -or $param.Aliases -contains $nameOrAlias) { return $param.Name } } return "" } Function VariableExists([Parameter(Mandatory = $true)][string] $name) { if ( ! ( Get-Variable $name -ErrorAction 'Ignore') ) { return $false } return $true } Function VariableExistsAndNotEmpty([Parameter(Mandatory = $true)][string] $name) { if ( ! (VariableExists $name) ) { return $false } if ( [string]::IsNullOrWhiteSpace( (Get-Variable $name).Value ) ) { return $false } return $true } function HasProperty($object, $property) { return ($property -in $object.PSobject.Properties.Name) } # File IO # ------------------------------------------------------------------------------------------------ Function Get-QuotedPath([Parameter(Mandatory = $false)][string] $path) { if ([string]::IsNullOrWhiteSpace($path)) { return $path } [string] $returnPath = $path if (!$path.StartsWith('"')) { $returnPath = """$path""" } return $returnPath } Function Get-UnquotedPath([Parameter(Mandatory = $false)][string] $path) { [string] $retPath = $path if ( ! [string]::IsNullOrWhiteSpace($retPath) -and $retPath.StartsWith('"') ) { $retPath = $retPath.Remove(0, 1); if ( $retPath.EndsWith('"') ) { $retPath = $retPath.Remove($retPath.Length - 1, 1) } else { # if it begins with double quote, should end with double quote... # something else may be going on, return the original path. $retPath = $path } } return $retPath } Function Remove-PathTrailingSlash([Parameter(Mandatory = $true)][string] $path) { return $path -replace '\\$', '' } Function Get-FileDirectory([Parameter(Mandatory = $true)][string] $filePath) { return ([System.IO.Path]::GetDirectoryName($filePath) + "\") } Function Get-FileName( [Parameter(Mandatory = $false)][string] $path , [Parameter(Mandatory = $false)][switch] $noext) { if ($noext) { return ([System.IO.Path]::GetFileNameWithoutExtension($path)) } else { return ([System.IO.Path]::GetFileName($path)) } } Function IsFileMatchingName( [Parameter(Mandatory = $true)][string] $filePath , [Parameter(Mandatory = $true)] $matchName) { [string] $matchString = $matchName.ToString() # works for both strings and regex types if ($matchName -is [string]) { if ([System.IO.Path]::IsPathRooted($matchString)) { if ($matchName.Length -le $filePath.Length -and ($filePath.Substring(0, $matchName.Length) -ieq $matchName)) { return $true } } [string] $fileName = (Get-FileName -path $filePath) if ($fileName -ieq $matchString) { return $true } [string] $fileNameNoExt = (Get-FileName -path $filePath -noext) if ($fileNameNoExt -ieq $matchString) { return $true } if ($filePath.ToLower().EndsWith($matchName.ToLower())) { return $true } while (![string]::IsNullOrWhiteSpace($filePath)) { if ($filePath.ToLower().EndsWith($matchName.ToLower())) { return $true } $filePath = [System.IO.Path]::GetDirectoryName($filePath) } return $false } elseif ($matchName -is [regex]) { return $filePath -match $matchString } else { throw "Unsupported match object type $($matchName.GetType().ToString())" } } Function FileHasExtension( [Parameter(Mandatory = $true)][string] $filePath , [Parameter(Mandatory = $true)][string[]] $ext ) { foreach ($e in $ext) { if ($filePath.EndsWith($e)) { return $true } } return $false } Function Get-RandomString( [Parameter(Mandatory=$false)][int] $aLength = 10) { return (-Join ((65..90) + (97..122) | Get-Random -Count $aLength | % { [char] $_ })) } <# .DESCRIPTION Merges an absolute and a relative file path. .EXAMPLE Having base = C:\Windows\System32 and child = .. we get C:\Windows .EXAMPLE Having base = C:\Windows\System32 and child = ..\..\..\.. we get C:\ (cannot go further up) .PARAMETER base The absolute path from which we start. .PARAMETER child The relative path(s) to be merged into base. If multiple paths are specified, they can be separated semicolon or space. .PARAMETER ignoreErrors If this switch is not present, an error will be triggered if the resulting path is not present on disk (e.g. c:\Windows\System33). If present and the resulting path does not exist, the function returns an empty string. #> Function Canonize-Path( [Parameter(Mandatory = $true)][string] $base , [Parameter(Mandatory = $true)][string] $child , [switch] $ignoreErrors) { [string[]] $children = @() $tokensBySemicolon = $child.Trim().Split(';') foreach ($semicolonTok in $tokensBySemicolon) { if ([string]::IsNullOrWhiteSpace($semicolonTok)) { continue } $tokensBySpace = $semicolonTok.Trim().Split(' ') $currentToken = "" foreach ($tok in $tokensBySpace) { if ($tok -match "[A-Z]:.*") { if ( ! [string]::IsNullOrWhiteSpace($currentToken)) { $children += $currentToken } $currentToken = $tok } else { if ($tok -ne $tokensBySpace[0]) { $currentToken += ' ' } $currentToken += $tok } } $children += $currentToken } Write-Debug "Canonizing for base = $base and children = $children" [string[]] $retPaths = @() [string] $errorAction = If ($ignoreErrors) {"SilentlyContinue"} Else {"Stop"} if (Test-Path -LiteralPath $base) { # Join-Path doesn't support LiteralPath so make sure we sanitize # the base path for unsupported characters $base = $base.Replace('[', '`['); $base = $base.Replace(']', '`]'); } foreach ($childPath in $children) { $childPath = Get-UnquotedPath $childPath $childPath = $childPath -replace "`r", "" $childPath = $childPath -replace "`n", "" if ([System.IO.Path]::IsPathRooted($childPath)) { if ((Test-Path -LiteralPath $childPath)) { $retPaths += @($childPath) } } else { [string[]] $paths = @(Join-Path -Path "$base" -ChildPath "$childPath" -Resolve -ErrorAction $errorAction) $retPaths += $paths } } return $retPaths } function cpt::HasTrailingSlash([Parameter(Mandatory = $true)][string] $str) { return $str.EndsWith('\') -or $str.EndsWith('/') } function EnsureTrailingSlash([Parameter(Mandatory = $true)][string] $str) { [string] $ret = If (cpt::HasTrailingSlash($str)) { $str } else { "$str\" } return $ret } function cpt::Exists([Parameter(Mandatory = $false)][string] $path) { if ([string]::IsNullOrEmpty($path)) { return $false } return Test-Path -LiteralPath $path } function cpt::MakePathRelative( [Parameter(Mandatory = $true)][string] $base , [Parameter(Mandatory = $true)][string] $target ) { Push-Location "$base\" [string] $relativePath = (Resolve-Path -Relative $target) -replace '^\.\\','' Pop-Location if ( (cpt::HasTrailingSlash $target) -or $target.EndsWith('.') ) { $relativePath += '\' } return "$relativePath" } function cpt::GetDirNameOfFileAbove( [Parameter(Mandatory = $true)][string] $startDir , [Parameter(Mandatory = $true)][string] $targetFile ) { if ($targetFile.Contains('$')) { $targetFile = Invoke-Expression $targetFile } if ($startDir.Contains('$')) { $startDir = Invoke-Expression $startDir } [string] $base = $startDir while ([string]::IsNullOrEmpty((Canonize-Path -base $base ` -child $targetFile ` -ignoreErrors))) { $base = [System.IO.Path]::GetDirectoryName($base) if ([string]::IsNullOrEmpty($base)) { return "" } } return $base } function cpt::GetPathOfFileAbove([Parameter(Mandatory = $true)][string] $targetFile, [Parameter(Mandatory = $true)][string] $startDir ) { if ($targetFile.Contains('$')) { $targetFile = Invoke-Expression $targetFile } $base = (cpt::GetDirNameOfFileAbove -targetFile $targetFile -startDir $startDir) if ([string]::IsNullOrWhiteSpace($base)) { return "" } return "$(EnsureTrailingSlash $base)$targetFile" } # Command IO # ------------------------------------------------------------------------------------------------ Function Exists-Command([Parameter(Mandatory = $true)][string] $command) { try { Get-Command -name $command -ErrorAction Stop | out-null return $true } catch { return $false } } Function Get-ClangVersion([Parameter(Mandatory = $true)][string] $toolToCheck) { if (Exists-Command $toolToCheck) { [string] $s = &"$toolToCheck" --version $regexMatch = [regex]::match($s, 'version (\d+).') if ($regexMatch) { return ($regexMatch.Groups[1].Value -as [int]) } } return 0 } Function Test-InternetConnectivity { $resp = Get-WmiObject -Class Win32_PingStatus -Filter 'Address="github.com" and Timeout=100' | Select-Object ResponseTime [bool] $hasInternetConnectivity = ($resp.ResponseTime -and $resp.ResponseTime -gt 0) return $hasInternetConnectivity } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/itemdefinition-context.ps1 ================================================ # Powershell code for creating item definition group contexts [System.Collections.Hashtable] $global:itemProperties = @{} [string] $global:itemPropertyNamespace = "" function Reset-ProjectItemContext() { $global:itemProperties = @{} $global:itemPropertyNamespace = "" } function Push-ProjectItemContext([Parameter(Mandatory = $true)][string] $name) { [string] $toAdd = "" if ($global:itemPropertyNamespace.Length -gt 0) { $toAdd = "."; } $toAdd += $name $global:itemPropertyNamespace += $toAdd Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Pop-ProjectItemContext() { [int] $dotPos = $global:itemPropertyNamespace.LastIndexOf(".") if ($dotPos -ge 0) { $global:itemPropertyNamespace = $global:itemPropertyNamespace.Substring(0, $dotPos) } else { $global:itemPropertyNamespace = "" } Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Set-ProjectItemContext([Parameter(Mandatory = $true)][AllowEmptyString()][string] $name) { if ( (VariableExists 'itemPropertyNameSpace') -and ($global:itemPropertyNamespace -eq $name) ) { return } $global:itemPropertyNamespace = $name Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Get-ProjectItemContext() { return $global:itemPropertyNamespace } function Get-ProjectItemProperty([Parameter(Mandatory = $false)][string] $propertyName) { if (! $global:itemProperties.ContainsKey($global:itemPropertyNamespace)) { return $null } [System.Collections.Hashtable] $propMap = $global:itemProperties[$global:itemPropertyNamespace] if (!$propertyName) { return $propMap } if (! $propMap.ContainsKey($propertyName)) { return $null } return $propMap[$propertyName] } function Set-ProjectItemProperty([Parameter(Mandatory = $true)][string] $propertyName, [Parameter(Mandatory = $true)] $value) { if (! $global:itemProperties.ContainsKey($global:itemPropertyNamespace)) { $global:itemProperties.Add($global:itemPropertyNamespace, @{}) $global:ProjectSpecificVariables.Add('itemProperties') | out-null } [System.Collections.Hashtable] $propMap = $global:itemProperties[$global:itemPropertyNamespace] if (! $propMap.ContainsKey($propertyName)) { $propMap.Add($propertyName, $value) } else { $propMap[$propertyName] = $value } Write-Verbose "[CONTEXT] propSet: $propertyName = $value" } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/jsondb-export.ps1 ================================================ function JsonDB-Init() { [string] $outputPath = (EnsureTrailingSlash( Get-SourceDirectory )) $outputPath += "compile_commands.json" Set-Variable -name "kJsonCompilationDbPath" -value $outputPath -option Constant -scope Global Set-Variable -name "kJsonCompilationDbCount" -value 0 -scope Global "[" | Out-File $kJsonCompilationDbPath -Encoding "UTF8" } function JsonDB-Append($text) { $text | Out-File $kJsonCompilationDbPath -append -Encoding "UTF8" } function JsonDB-Finalize() { JsonDB-Append "]" Write-Output "Exported JSON Compilation Database to $kJsonCompilationDbPath" } function JsonDB-Push($directory, $file, $command) { if ($kJsonCompilationDbCount -ge 1) { JsonDB-Append " ," } # use only slashes $command = $command.Replace('\', '/') $file = $file.Replace('\', '/') $directory = $directory.Replace('\', '/') # escape double quotes $command = $command.Replace('"', '\"') # make paths relative to directory $command = $command.Replace("$directory/", "") $file = $file.Replace("$directory/", "") JsonDB-Append " {`r`n ""directory"": ""$directory"",`r`n ""command"": ""$command"",`r`n ""file"": ""$file""`r`n }" Set-Variable -name "kJsonCompilationDbCount" -value ($kJsonCompilationDbCount + 1) -scope Global } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/msbuild-expression-eval.ps1 ================================================ # REQUIRES io.ps1 to be included [string[]] $buildUtilPaths = @( ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ) foreach ($buildUtilPath in $buildUtilPaths) { if (Test-Path -LiteralPath $buildUtilPath) { Add-Type -path $buildUtilPath Write-Verbose "Loaded assembly $buildUtilPath" break } } Set-Variable -name "kMsbuildExpressionToPsRules" <#-option Constant#> ` -value @( ` <# backticks are control characters in PS, replace them #> ` ('`' , '''' )` <# Temporarily replace $( #> ` , ('\$\s*\(' , '!@#' )` <# Escape $ #> ` , ('\$' , '`$' )` <# Put back $( #> ` , ('!@#' , '$(' )` <# Various operators #> ` , ("([\s\)\'""])!=" , '$1 -ne ' )` , ("([\s\)\'""])<=" , '$1 -le ' )` , ("([\s\)\'""])>=" , '$1 -ge ' )` , ("([\s\)\'""])==" , '$1 -eq ' )` , ("([\s\)\'""])<" , '$1 -lt ' )` , ("([\s\)\'""])>" , '$1 -gt ' )` , ("([\s\)\'""])or" , '$1 -or ' )` , ("([\s\)\'""])and" , '$1 -and ' )` <# Use only double quotes #> ` , ("\'" , '"' )` , ("Exists\((.*?)\)(\s|$)" , '(cpt::Exists($1))$2' )` , ("HasTrailingSlash\((.*?)\)(\s|$)" , '(cpt::HasTrailingSlash($1))$2')` , ("(\`$\()(Registry:)(.*?)(\))" , '$$(GetRegValue("$3"))' )` , ("\[MSBuild\]::GetDirectoryNameOfFileAbove\((.+?),\s*`"?'?((\$.+?\))|(.+?))((|`"|')\))+"` ,'cpt::GetDirNameOfFileAbove -startDir $1 -targetFile ''$2'')' )` , ("\(\[MSBuild\]::GetPathOfFileAbove\(`"?(.+?)`"?,\s*((`"(.+)`"\)+)|((\$\(.+?\))\)*))"` ,'(cpt::GetPathOfFileAbove -startDir "$4$6" -targetFile ''$1'')' )` , ("\[MSBuild\]::MakeRelative\((.+?),\s*""?'?((\$.+?\))|(.+?))((|""|')\)\))+"` ,'cpt::MakePathRelative -base $1 -target "$2")' )` , ('SearchOption\.', '[System.IO.SearchOption]::' )` , ("@\((.*?)\)", '$(Get-Project-Item("$1"))' )` , ("%\((.*?)\)", '$(Get-ProjectItemProperty("$1"))' )` , ('\$\(HOME\)', '$(CPT_SHIM_HOME)' )` <# Rules for making sure the $ sign is put on correctly in expressions #> ` , ('\$\(([a-zA-Z_][a-zA-Z0-9_\-]+)\)', '$${$1}' )` , ('\(([a-zA-Z_][a-zA-Z0-9_\-]+\.)', '($$$1' )` ) function GetRegValue([Parameter(Mandatory = $true)][string] $regPath) { Write-Debug "REG_READ $regPath" [int] $separatorIndex = $regPath.IndexOf('@') [string] $valueName = "" if ($separatorIndex -gt 0) { [string] $valueName = $regPath.Substring($separatorIndex + 1) $regPath = $regPath.Substring(0, $separatorIndex) } if ([string]::IsNullOrEmpty($valueName)) { throw "Cannot retrieve an empty registry value" } $regPath = $regPath -replace "HKEY_LOCAL_MACHINE\\", "HKLM:\" if (Test-Path $regPath) { return (Get-Item $regPath).GetValue($valueName) } else { return "" } } function Initialize-ExpressionVariables([string] $expression) { # expressions that call member functions of unintialized variables will throw # unless we initialize those variables $regexMatches = [regex]::matches($expression, '\$(\w+)\.') if ($regexMatches.Count -gt 0) { foreach ($regexMatch in $regexMatches) { $varName = $regexMatch.Groups[1].Value if (! ( Get-Variable $varName -ErrorAction 'Ignore') ) { Write-Debug "Initializing expression variable $varName to empty value" Set-Var -name $varName -value "" } } } } function Evaluate-MSBuildExpression([string] $expression, [switch] $isCondition) { # A lot of MSBuild expressions refer uninitialized variables Set-StrictMode -Off Write-Debug "Start evaluate MSBuild expression $expression" foreach ($rule in $kMsbuildExpressionToPsRules) { $expression = $expression -replace $rule[0], $rule[1] } if ( !$isCondition -and ($expression.IndexOf('$') -lt 0)) { # we can stop here, further processing is not required return $expression } Write-Debug "Intermediate PS expression: $expression" Initialize-ExpressionVariables $expression [string] $res = "" try { if ( ($expression.IndexOf('::') -ge 0) -or $isCondition) { try { $resInvokeResult = Invoke-Expression $expression if ($resInvokeResult -is [array]) { $res = $resInvokeResult -join ';' } else { $res = $resInvokeResult } } catch { Write-Verbose $_.Exception.Message $res = $ExecutionContext.InvokeCommand.ExpandString($expression) } } else { $res = $ExecutionContext.InvokeCommand.ExpandString($expression) } } catch { Write-Verbose $_.Exception.Message } Write-Debug "Evaluated expression to: $res" return $res } function Evaluate-MSBuildCondition([Parameter(Mandatory = $true)][string] $condition) { Write-Debug "Evaluating condition $condition" try { [string] $expression = Evaluate-MSBuildExpression -expression $condition -isCondition } catch { Write-Verbose $_.Exception.Message return $false } if ($expression -ieq "true") { return $true } if ($expression -ieq "false") { return $false } $expression = $expression -replace 'False', '$false' $expression = $expression -replace 'True', '$true' try { [bool] $res = (Invoke-Expression $expression) -eq $true } catch { Write-Verbose $_.Exception.Message return $false } Write-Debug "Evaluated condition to $res" return $res } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/msbuild-project-cache-repository.ps1 ================================================ Set-Variable -name kCptCacheRepo -value "$env:APPDATA\ClangPowerTools\CacheRepository" -option Constant Function Is-CacheLoadingEnabled() { if ("${Env:CPT_CACHEREPO}" -eq "0") { return $false } # if the cache repository directory exists, then we use caching return (Test-Path $kCptCacheRepo) } Function Remove-CachedProjectFile([Parameter(Mandatory = $true)][string] $aCachedFilePath) { if ($aCachedFilePath.StartsWith($kCptCacheRepo)) { Remove-Item $aCachedFilePath | Out-Null } } Function Get-CacheRepositoryIndex() { Write-Verbose "Loading project cache repository index" [System.Collections.Hashtable] $cacheIndex = @{} if (Is-CacheLoadingEnabled) { [string] $cptCacheRepoIndex = "$kCptCacheRepo\index.dat" if (Test-Path $cptCacheRepoIndex) { try { $cacheIndex = [System.Management.Automation.PSSerializer]::Deserialize((Get-Content $cptCacheRepoIndex)) } catch { Write-Verbose "Error: Could not deserialize corrupted cache repository index. Rebuilding from scratch..." return $cacheIndex } } } return $cacheIndex } Function Save-CacheRepositoryIndex([Parameter(Mandatory = $true)][System.Collections.Hashtable] $cacheIndex) { Write-Verbose "Saving project cache repository index" if (! (Is-CacheLoadingEnabled) ) { return } [System.Collections.ArrayList] $indexKeys = @() foreach ($keyIndex in $cacheIndex.Keys) { # make sure we don't invalidate the cacheIndex.Keys collection iterators when modifying it $indexKeys.Add($keyIndex) > $null } foreach ($indexKey in $indexKeys) { [string] $CachedDataPath = $cacheIndex[$indexKey].CachedDataPath if (! (Test-Path $CachedDataPath)) { Write-Verbose "Pruning zombie entry ($($indexKey) : $($CachedDataPath)) from cache repository index" $cacheIndex.Remove($indexKey) > $null } } [string] $cptCacheRepoIndex = "$kCptCacheRepo\index.dat" $serialized = [System.Management.Automation.PSSerializer]::Serialize($cacheIndex) $serialized > $cptCacheRepoIndex } Function Join-ConfigurationPlatformScriptArgs() { return ($aVcxprojConfigPlatform -join ",") } Function Save-ProjectToCacheRepo() { Write-Verbose "Saving current project data to cache repository" if (! (Is-CacheLoadingEnabled) ) { return } Write-Verbose "Collecting $($global:ProjectSpecificVariables.Count) project specific variables" [System.Collections.Hashtable] $projectVariablesMap = @{} foreach ($varName in $global:ProjectSpecificVariables) { $projectVariablesMap[$varName] = Get-Variable -name $varName -ValueOnly } [System.Collections.Hashtable] $genericVariablesMap = @{} $genericVariablesMap['cptVisualStudioVersion' ] = Get-Variable 'cptVisualStudioVersion' -scope Global -ValueOnly $genericVariablesMap['cptCurrentConfigPlatform'] = Get-Variable 'cptCurrentConfigPlatform' -scope Global -ValueOnly $dataToSerialize = New-Object PsObject -Prop @{ "ProjectSpecificVariables" = $projectVariablesMap ; "GenericVariables" = $genericVariablesMap } [string] $pathToSave = "" while ($true) { [string] $pathToSave = "$kCptCacheRepo\$(Get-RandomString).dat" # make sure we don't overwrite an already existing cache entry if (! (Test-Path $pathToSave)) { break } } $serialized = [System.Management.Automation.PSSerializer]::Serialize($dataToSerialize) $serialized > $pathToSave Write-Verbose "Wrote project to cache repository using moniker $pathToSave" [System.Collections.Hashtable] $projectFilesHashes = @{} foreach ($projectFile in $global:ProjectInputFiles) { $projectFilesHashes[$projectFile] = (Get-FileHash $projectFile -Algorithm "SHA1").Hash } [System.Collections.Hashtable] $cacheIndex = Get-CacheRepositoryIndex $cacheObject = New-Object PsObject -Prop @{ "ProjectFilesHashes" = $projectFilesHashes ; "CachedDataPath" = $pathToSave ; "ConfigurationPlatform" = Join-ConfigurationPlatformScriptArgs ; "CptCacheSyntaxVersion" = $kCacheSyntaxVer } $cacheIndex[$MSBuildProjectFullPath] = $cacheObject Save-CacheRepositoryIndex $cacheIndex } Function Load-ProjectFromCache([Parameter(Mandatory = $true)][string] $aVcxprojPath) { Write-Verbose "Trying to load project $aVcxprojPath from cache repository" if (! (Is-CacheLoadingEnabled) ) { Write-Verbose "Cache repository not enabled in %APPDATA%/ClangPowerTools/CacheRepository" return $false } [System.Collections.Hashtable] $cacheIndex = Get-CacheRepositoryIndex if ( ! $cacheIndex.ContainsKey($aVcxprojPath)) { Write-Verbose "Cache repository does not contain record of project" return $false } $projectCacheObject = $cacheIndex[$aVcxprojPath] if ( ! (Test-Path $projectCacheObject.CachedDataPath)) { Write-Verbose "Error: Cache repository contains record of project but cached file no longer exists" return $false } if ($projectCacheObject.CptCacheSyntaxVersion -ne $kCacheSyntaxVer) { Write-Verbose "Cached version of project uses older syntax version. Discarding..." # the cached version uses an outdated syntax, safely discard it Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } [System.Collections.Hashtable] $projectFilesHashes = $projectCacheObject.ProjectFilesHashes foreach ($projectFilePath in $projectFilesHashes.Keys) { Write-Verbose "Checking hash of project file $projectFilePath" $newFileHash = (Get-FileHash $projectFilePath -Algorithm "SHA1").Hash if ($newFileHash -ne $projectFilesHashes[$projectFilePath]) { Write-Verbose "Cached version of project has different file hash. Discarding..." # project file hash not matching, safely discard cached version Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } } if ($projectCacheObject.ConfigurationPlatform -ne (Join-ConfigurationPlatformScriptArgs)) { Write-Verbose "Cached version of project uses different configuration platform. Discarding..." # config-platform not maching, safely discard cached version Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } # Clean global variables that have been set by a previous project load Clear-Vars $global:vcxprojPath = $aVcxprojPath Write-Verbose "Loading cached project from $($projectCacheObject.CachedDataPath)" [string] $data = Get-Content $projectCacheObject.CachedDataPath $deserialized = $null try { $deserialized = [System.Management.Automation.PSSerializer]::Deserialize($data) } catch { Write-Verbose "Error: Failure to deserialize cached project data. Discarding corrupted file" Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } [System.Collections.Hashtable] $projectSpecificVariablesMap = $deserialized.ProjectSpecificVariables [System.Collections.Hashtable] $genericVariablesMap = $deserialized.GenericVariables Write-Verbose "Cached version of project has $($projectSpecificVariablesMap.Count) variables to load" if ($projectSpecificVariablesMap.Keys -notcontains "MSBuildThisFileFullPath") { Write-Verbose "Cached project does not contain MSBuildThisFileFullPath. Discarding..." Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } if ( $projectSpecificVariablesMap['MSBuildThisFileFullPath'] -ne $aVcxprojPath ) { Write-Verbose "Cached project looks to be a different project ($($projectSpecificVariablesMap['MSBuildThisFileFullPath'])). Discarding..." Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } foreach ($var in $projectSpecificVariablesMap.Keys) { Set-Var -name $var -value $projectSpecificVariablesMap[$var] } # these variables should be garbage collected between projects # using our custom Set-Var would allow that to happen foreach ($var in $genericVariablesMap.Keys) { Set-Variable -name $var -value $genericVariablesMap[$var] -scope Global } Write-Verbose "Cache repository - project load was successful" return $true } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/msbuild-project-data.ps1 ================================================ #------------------------------------------------------------------------------------------------- # PlatformToolset constants Set-Variable -name kDefinesUnicode -value @('"-DUNICODE"' ,'"-D_UNICODE"' ) ` -option Constant Set-Variable -name kDefinesClangXpTargeting ` -value @('"-D_USING_V110_SDK71_"') ` -option Constant Set-Variable -name kIncludePathsXPTargetingSDK ` -value "${Env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v7.1A\Include" ` -option Constant Set-Variable -name kVStudioDefaultPlatformToolset -Value "v141" -option Constant Set-Variable -name kClangFlag32BitPlatform -value "-m32" -option Constant # ------------------------------------------------------------------------------------------------ # Default platform sdks and standard Set-Variable -name kVSDefaultWinSDK -value '8.1' -option Constant Set-Variable -name kVSDefaultWinSDK_XP -value '7.0' -option Constant Set-Variable -name kDefaultCppStd -value "stdcpp14" -option Constant # ------------------------------------------------------------------------------------------------ Set-Variable -name kCProjectCompile -value "CompileAsC" -option Constant Function Should-CompileProject([Parameter(Mandatory = $true)][string] $vcxprojPath) { if ($aVcxprojToCompile -eq $null) { return $true } foreach ($projMatch in $aVcxprojToCompile) { if (IsFileMatchingName -filePath $vcxprojPath -matchName $projMatch) { return $true } } return $false } Function Should-IgnoreProject([Parameter(Mandatory = $true)][string] $vcxprojPath) { if ($aVcxprojToIgnore -eq $null) { return $false } foreach ($projIgnoreMatch in $aVcxprojToIgnore) { if (IsFileMatchingName -filePath $vcxprojPath -matchName $projIgnoreMatch) { return $true } } return $false } Function Should-IgnoreFile([Parameter(Mandatory = $true)][string] $file) { if ($aCppToIgnore -eq $null) { return $false } foreach ($projIgnoreMatch in $aCppToIgnore) { if (IsFileMatchingName -filePath $file -matchName $projIgnoreMatch) { return $true } } foreach ($projIgnoreMatch in $global:cptIgnoredFilesPool) { if (IsFileMatchingName -filePath $file -matchName $projIgnoreMatch) { return $true } } return $false } Function Get-ProjectFilesToCompile() { $projectCompileItems = @(Get-Project-ItemList "ClCompile") if (!$projectCompileItems) { Write-Verbose "Project does not have any items to compile" return @() } $files = @() foreach ($item in $projectCompileItems) { [System.Collections.Hashtable] $itemProps = $item[1]; if ($itemProps -and $itemProps.ContainsKey('ExcludedFromBuild')) { if ($itemProps['ExcludedFromBuild'] -ieq 'true') { Write-Verbose "Skipping $($item[0]) because it is excluded from build" continue } } [string[]] $matchedFiles = @(Canonize-Path -base $ProjectDir -child $item[0] -ignoreErrors) if ($matchedFiles.Count -gt 0) { foreach ($file in $matchedFiles) { $files += New-Object PsObject -Prop @{ "File" = $file ; "Properties" = $itemProps } } } } return $files } Function Get-ProjectHeaders() { $projectCompileItems = @(Get-Project-ItemList "ClInclude") [string[]] $headerPaths = @() foreach ($item in $projectCompileItems) { [string[]] $paths = @(Canonize-Path -base $ProjectDir -child $item[0] -ignoreErrors) if ($paths.Count -gt 0) { $headerPaths += $paths } } return $headerPaths } Function Get-Project-SDKVer() { if (! (VariableExists 'WindowsTargetPlatformVersion')) { return "" } if ([string]::IsNullOrEmpty($WindowsTargetPlatformVersion)) { return "" } return $WindowsTargetPlatformVersion.Trim() } Function Get-Project-MultiThreaded-Define() { Set-ProjectItemContext "ClCompile" [string] $runtimeLibrary = Get-ProjectItemProperty "RuntimeLibrary" # /MT or /MTd if (@("MultiThreaded", "MultiThreadedDebug") -contains $runtimeLibrary) { return @('"-D_MT"') } return @('"-D_MT"', '"-D_DLL"') # default value /MD } Function Is-Project-Unicode() { if (VariableExists 'CharacterSet') { return $CharacterSet -ieq "Unicode" } return $false } Function Get-Project-CppStandard() { Set-ProjectItemContext "ClCompile" $cppStd = Get-ProjectItemProperty "LanguageStandard" if (!$cppStd) { $cppStd = $kDefaultCppStd } $cppStdMap = @{ 'stdcpplatest' = 'c++20' ; 'stdcpp14' = 'c++14' ; 'stdcpp17' = 'c++17' ; 'stdcpp20' = 'c++20' } if ($kLLVMVersion -ge 13) { $cppStdMap['stdcpplatest'] = 'c++2b' } [string] $cppStdClangValue = $cppStdMap[$cppStd] return $cppStdClangValue } Function Get-ClangCompileFlags([Parameter(Mandatory = $false)][bool] $isCpp = $true) { [string[]] $flags = $aClangCompileFlags if ($isCpp -and !($flags -match "-std=.*")) { [string] $cppStandard = Get-Project-CppStandard $flags = @("-std=$cppStandard") + $flags } if ($Platform -ieq "x86" -or $Platform -ieq "Win32") { $flags += @($kClangFlag32BitPlatform) } return $flags } Function Get-ProjectPlatformToolset() { if (VariableExists 'PlatformToolset') { return $PlatformToolset } else { return $kVStudioDefaultPlatformToolset } } function Get-LatestSDKVersion() { [string] $parentDir = "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\" if (!(Test-Path -LiteralPath $parentDir)) { Write-Verbose "Windows 10 SDK parent directory could not be located" return "" } [System.IO.DirectoryInfo[]]$subdirs = @( get-childitem -path $parentDir | ` where { $_.Name.StartsWith("10.") } | ` sort -Descending -Property Name ) if ($subdirs.Count -eq 0) { Write-Verbose "[ERR] Could not detect latest Windows 10 SDK location" return "" } return $subdirs[0].Name } Function Get-ProjectIncludesFromIncludePathVar { [string[]] $returnArray = @() if ( (VariableExists 'IncludePath') ) { $returnArray += ($IncludePath -split ";") | ` Where-Object { ![string]::IsNullOrWhiteSpace($_) } | ` ForEach-Object { Canonize-Path -base $ProjectDir -child $_.Trim() -ignoreErrors } | ` Where-Object { ![string]::IsNullOrEmpty($_) } | ` ForEach-Object { $_ -replace '\\$', '' } } return $returnArray } Function Get-ProjectIncludeDirectories() { [string[]] $returnArray = @() [string] $vsPath = Get-VisualStudio-Path Write-Verbose "Visual Studio location: $vsPath" [string] $platformToolset = Get-ProjectPlatformToolset if (([int] $global:cptVisualStudioVersion) -lt 2017) { $returnArray += Get-VisualStudio-Includes -vsPath $vsPath } else { $mscVer = Get-MscVer -visualStudioPath $vsPath Write-Verbose "MSCVER: $mscVer" $returnArray += Get-VisualStudio-Includes -vsPath $vsPath -mscVer $mscVer } $sdkVer = Get-Project-SDKVer # We did not find a WinSDK version in the vcxproj. We use Visual Studio's defaults if ([string]::IsNullOrEmpty($sdkVer)) { if ($platformToolset.EndsWith("xp")) { $sdkVer = $kVSDefaultWinSDK_XP } else { $sdkVer = $kVSDefaultWinSDK } } Write-Verbose "WinSDK version: $sdkVer" # ---------------------------------------------------------------------------------------------- # Windows 10 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("10"))) { if ($sdkVer -eq "10.0") { # Project uses the latest Win10 SDK. We have to detect its location. $sdkVer = Get-LatestSDKVersion } $returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\ucrt") if ($platformToolset.EndsWith("xp")) { $returnArray += @($kIncludePathsXPTargetingSDK) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\um" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\shared" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\winrt" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\cppwinrt" ) } } # ---------------------------------------------------------------------------------------------- # Windows 8 / 8.1 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("8."))) { $returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt") if ($platformToolset.EndsWith("xp")) { $returnArray += @($kIncludePathsXPTargetingSDK) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\um" , "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\shared" , "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\winrt" ) } } # ---------------------------------------------------------------------------------------------- # Windows 7 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("7.0"))) { $returnArray += @("$vsPath\VC\Auxiliary\VS\include") if ($platformToolset.EndsWith("xp")) { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt" , $kIncludePathsXPTargetingSDK ) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\7.0\ucrt") } } if ($env:CPT_LOAD_ALL -eq '1') { return @(Get-ProjectIncludesFromIncludePathVar) } else { $returnArray += @(Get-ProjectIncludesFromIncludePathVar) } return ( $returnArray | ForEach-Object { Remove-PathTrailingSlash -path $_ } ) } <# .DESCRIPTION Retrieve array of preprocessor definitions for a given project, in Clang format (-DNAME ) #> Function Get-ProjectPreprocessorDefines() { [string[]] $defines = @() if (Is-Project-Unicode) { $defines += $kDefinesUnicode } $defines += @(Get-Project-MultiThreaded-Define) if ( (VariableExists 'UseOfMfc') -and $UseOfMfc -ieq "Dynamic") { $defines += @('"-D_AFXDLL"') } [string] $platformToolset = Get-ProjectPlatformToolset if ($platformToolset.EndsWith("xp")) { $defines += $kDefinesClangXpTargeting } Set-ProjectItemContext "ClCompile" $preprocDefNodes = Get-ProjectItemProperty "PreprocessorDefinitions" if (!$preprocDefNodes) { return $defines } [string[]] $tokens = @($preprocDefNodes -split ";") # make sure we add the required prefix and escape double quotes $defines += @( $tokens | ` ForEach-Object { $_.Trim() } | ` Where-Object { $_ } | ` ForEach-Object { '"' + $(($kClangDefinePrefix + $_) -replace '"', '\"') + '"' } ) return $defines } Function Get-ProjectAdditionalIncludes() { Set-ProjectItemContext "ClCompile" $data = Get-ProjectItemProperty "AdditionalIncludeDirectories" [string[]] $tokens = @($data -split ";") foreach ($token in $tokens) { if ([string]::IsNullOrWhiteSpace($token)) { continue } [string] $includePath = Canonize-Path -base $ProjectDir -child $token.Trim() -ignoreErrors if (![string]::IsNullOrEmpty($includePath)) { $includePath -replace '\\$', '' } } } Function Get-ProjectForceIncludes() { Set-ProjectItemContext "ClCompile" $forceIncludes = Get-ProjectItemProperty "ForcedIncludeFiles" if ($forceIncludes) { return @($forceIncludes -split ";" | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } return $null } Function Get-FileForceIncludes([Parameter(Mandatory=$true)] [string] $fileFullName) { try { [string] $forceIncludes = Get-ProjectFileSetting -fileFullName $fileFullName -propertyName "ForcedIncludeFiles" return ($forceIncludes -split ";") | ` Where-Object { ![string]::IsNullOrWhiteSpace($_) } | ` ForEach-Object { Canonize-Path -base $ProjectDir -child $_.Trim() -ignoreErrors } | ` Where-Object { ![string]::IsNullOrEmpty($_) } | ` ForEach-Object { $_ -replace '\\$', '' } } catch { return $null } } <# .DESCRIPTION Retrieve directory in which stdafx.h resides #> Function Get-ProjectStdafxDir( [Parameter(Mandatory = $true)] [string] $pchHeaderName , [Parameter(Mandatory = $false)] [string[]] $includeDirectories , [Parameter(Mandatory = $false)] [string[]] $additionalIncludeDirectories ) { [string] $stdafxPath = "" [string[]] $projectHeaders = @(Get-ProjectHeaders) if ($projectHeaders.Count -gt 0) { # we need to use only backslashes so that we can match against file header paths $pchHeaderName = $pchHeaderName.Replace("/", "\") $stdafxPath = $projectHeaders | Where-Object { (Get-FileName -path $_) -eq $pchHeaderName } } if ([string]::IsNullOrEmpty($stdafxPath)) { [string[]] $searchPool = @($ProjectDir); if ($includeDirectories.Count -gt 0) { $searchPool += $includeDirectories } if ($additionalIncludeDirectories.Count -gt 0) { $searchPool += $additionalIncludeDirectories } foreach ($dir in $searchPool) { [string] $stdafxPath = Canonize-Path -base $dir -child $pchHeaderName -ignoreErrors if (![string]::IsNullOrEmpty($stdafxPath)) { break } } } if ([string]::IsNullOrEmpty($stdafxPath)) { return "" } else { [string] $stdafxDir = Get-FileDirectory($stdafxPath) return $stdafxDir } } Function Get-PchCppIncludeHeader([Parameter(Mandatory = $true)][string] $pchCppFile) { [string] $cppPath = Canonize-Path -base $ProjectDir -child $pchCppFile [string[]] $fileLines = @(Get-Content -LiteralPath $cppPath) foreach ($line in $fileLines) { $regexMatch = [regex]::match($line, '^\s*#include\s+"(\S+)"') if ($regexMatch.Success) { return $regexMatch.Groups[1].Value } } return "" } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/msbuild-project-load.ps1 ================================================ #------------------------------------------------------------------------------------------------- # Global variables # vcxproj and property sheet files declare MsBuild properties (e.g. $(MYPROP)). # they are used in project xml nodes expressions. we have a # translation engine (MSBUILD-POWERSHELL) for these. it relies on # PowerShell to evaluate these expressions. We have to inject project # properties in the PowerShell runtime context. We keep track of them in # this list, so that each project can know to clean previous vars before loading begins. if (! (Test-Path variable:global:ProjectSpecificVariables)) { [System.Collections.ArrayList] $global:ProjectSpecificVariables = @() } if (! (Test-Path variable:global:ProjectInputFiles)) { [System.Collections.ArrayList] $global:ProjectInputFiles = @{} } Function Add-ToProjectSpecificVariables([Parameter(Mandatory = $true)] [string] $variableName) { $global:ProjectSpecificVariables.Add($variableName) > $null } if (! (Test-Path variable:global:ScriptParameterBackupValues)) { [System.Collections.Hashtable] $global:ScriptParameterBackupValues = @{} } # path of current project [string] $global:vcxprojPath = ""; Set-Variable -name "kRedundantSeparatorsReplaceRules" -option Constant ` -value @( <# handle multiple consecutive separators #> ` (";+" , ";") ` <# handle separator at end #> ` , (";$" , "") ` <# handle separator at beginning #> ` , ("^;" , "") ` ) Set-Variable -name "kCacheSyntaxVer" -Option Constant -value "1" Add-Type -TypeDefinition @" public class ProjectConfigurationNotFound : System.Exception { public string ConfigPlatform; public string Project; public ProjectConfigurationNotFound(string proj, string configPlatform) { this.Project = proj; this.ConfigPlatform = configPlatform; } } "@ Function Set-Var([parameter(Mandatory = $false)][string] $name ,[parameter(Mandatory = $false)] $value ,[parameter(Mandatory = $false)][switch] $asScriptParameter ) { if ($name -ieq "home") { Write-Verbose "Shimming HOME variable" # the HOME PowerShell variable is protected and we can't overwrite it $name = "CPT_SHIM_HOME" } if ($asScriptParameter) { if (Test-Path "variable:$name") { $oldVar = Get-Variable $name $oldValue = $oldVar.Value if ($oldValue -and $oldValue.GetType() -and $oldValue.GetType().ToString() -eq "System.Management.Automation.SwitchParameter") { $oldValue = $oldValue.ToBool() } $global:ScriptParameterBackupValues[$name] = $oldValue } else { $global:ScriptParameterBackupValues[$name] = $null } } Write-Verbose "SET_VAR $($name): $value" if ($asScriptParameter) { Set-Variable -name $name -Value $value -Scope Script } else { Set-Variable -name $name -Value $value -Scope Global } if (!$asScriptParameter -and !$global:ProjectSpecificVariables.Contains($name)) { Add-ToProjectSpecificVariables $name } } Function Add-Project-Item([parameter(Mandatory = $false)][string] $name ,[parameter(Mandatory = $false)] $value ,[parameter(Mandatory = $false)] $properties = $null) { if (!$value) { return } $itemVarName = "CPT_PROJITEM_$name" if (!(Get-Variable $itemVarName -ErrorAction SilentlyContinue)) { $itemList = New-Object System.Collections.ArrayList Set-Var -name $itemVarName -value $itemList } $itemList = (Get-Variable $itemVarName).Value if ($value -is [array]) { foreach ($arrayValue in $value) { $itemList.Add( @($arrayValue, $properties) ) > $null } } else { $itemList.Add(@($value, $properties)) > $null } } Function Get-Project-Item([parameter(Mandatory = $true)][string] $name) { $itemVarName = "CPT_PROJITEM_$name" $itemVar = Get-Variable $itemVarName -ErrorAction SilentlyContinue if ($itemVar) { $retStr = "" if ($itemVar.Value.GetType().Name -ieq "ArrayList") { foreach ($v in $itemVar.Value) { if ($retStr) { $retStr += ";" } $retStr += $v[0] # index0 = item; index1 = properties } } else { $retStr = $itemVar.Value[0] # index0 = item; index1 = properties } return $retStr } return $null } Function Get-Project-ItemList([parameter(Mandatory = $true)][string] $name) { $retList = New-Object System.Collections.ArrayList $itemVarName = "CPT_PROJITEM_$name" $itemVar = Get-Variable $itemVarName -ErrorAction SilentlyContinue if ($itemVar) { $retStr = "" if ($itemVar.Value.GetType().Name -ieq "ArrayList") { foreach ($v in $itemVar.Value) { if ($retStr) { $retStr += ";" } $retList.Add($v) > $null # v is a pair. index0 = item; index1 = properties } } else { $retList.Add($itemVar.Value) > $null } } return $retList } Function Clear-Vars() { Write-Verbose-Array -array $global:ProjectSpecificVariables ` -name "Deleting variables initialized by previous project" foreach ($var in $global:ProjectSpecificVariables) { Remove-Variable -name $var -scope Global -ErrorAction SilentlyContinue } foreach ($varName in $global:ScriptParameterBackupValues.Keys) { Write-Verbose "Restoring $varName to old value $($ScriptParameterBackupValues[$varName])" Set-Variable -name $varName -value $ScriptParameterBackupValues[$varName] } $global:ScriptParameterBackupValues.Clear() $global:ProjectSpecificVariables.Clear() $global:ProjectInputFiles.Clear() Reset-ProjectItemContext } Function UpdateScriptParameter([Parameter(Mandatory = $true)] [string] $paramName ,[Parameter(Mandatory = $false)][string] $paramValue) { [bool] $isSwitch = $false $evalParamValue = "" # no type specified because we don't know it yet if ($paramValue) # a parameter { $evalParamValue = Invoke-Expression $paramValue # evaluate expression to get actual value } else # a switch { $isSwitch = $true } # the parameter name we detected may be an alias => translate it into the real name [string] $realParamName = Get-CommandParameterName -command "$PSScriptRoot\..\clang-build.ps1" ` -nameOrAlias $paramName if (!$realParamName) { Write-Output "OVERVIEW: Clang Power Tools: compiles or tidies up code from Visual Studio .vcxproj project files`n" Write-Output "USAGE: clang-build.ps1 [options]`n" Write-Output "OPTIONS: " Print-CommandParameters "$PSScriptRoot\..\clang-build.ps1" Fail-Script "Unsupported option '$paramName'. Check cpt.config." } if ($isSwitch) { Set-Var -name $realParamName -value $true -asScriptParameter } else { Set-Var -name $realParamName -value $evalParamValue -asScriptParameter } } Function Get-ConfigFileParameters() { [System.Collections.Hashtable] $retArgs = @{} [string] $startDir = If ( VariableExistsAndNotEmpty 'ProjectDir' ) { $ProjectDir } else { $aSolutionsPath } [string] $configFile = (cpt::GetDirNameOfFileAbove -startDir $startDir -targetFile "cpt.config") + "\cpt.config" if (!(Test-Path -LiteralPath $configFile)) { return $retArgs } Write-Verbose "Found cpt.config in $configFile" [xml] $configXml = Get-Content $configFile $configXpathNS= New-Object System.Xml.XmlNamespaceManager($configXml.NameTable) $configXpathNS.AddNamespace("ns", $configXml.DocumentElement.NamespaceURI) [System.Xml.XmlElement[]] $argElems = $configXml.SelectNodes("/ns:cpt-config/*", $configXpathNS) foreach ($argEl in $argElems) { if ($argEl.Name.StartsWith("vsx-")) { continue # settings for the Visual Studio Extension } if ($argEl.HasAttribute("Condition")) { [bool] $isApplicable = Evaluate-MSBuildCondition -condition $argEl.GetAttribute("Condition") if (!$isApplicable) { continue } } $retArgs[$argEl.Name] = $argEl.InnerText } return $retArgs } Function Update-ParametersFromConfigFile() { [System.Collections.Hashtable] $configParams = Get-ConfigFileParameters if (!$configParams) { return } foreach ($paramName in $configParams.Keys) { UpdateScriptParameter -paramName $paramName -paramValue $configParams[$paramName] } } Function InitializeMsBuildProjectProperties() { Write-Verbose "Importing environment variables into current scope" foreach ($var in (Get-ChildItem Env:)) { Set-Var -name $var.Name -value $var.Value } Set-Var -name "MSBuildProjectFullPath" -value $global:vcxprojPath Set-Var -name "ProjectDir" -value (Get-FileDirectory -filePath $global:vcxprojPath) Set-Var -name "MSBuildProjectExtension" -value ([IO.Path]::GetExtension($global:vcxprojPath)) Set-Var -name "MSBuildProjectFile" -value (Get-FileName -path $global:vcxprojPath) Set-Var -name "MSBuildProjectName" -value (Get-FileName -path $global:vcxprojPath -noext) Set-Var -name "MSBuildProjectDirectory" -value (Get-FileDirectory -filePath $global:vcxprojPath) Set-Var -name "MSBuildProgramFiles32" -value "${Env:ProgramFiles(x86)}" # defaults for projectname and targetname, may be overriden by project settings Set-Var -name "ProjectName" -value $MSBuildProjectName Set-Var -name "TargetName" -value $MSBuildProjectName Set-Var -name "UserRootDir" -value "$LocalAppData\Microsoft\MSBuild\v4.0" # These would enable full project platform references parsing, experimental right now if ($env:CPT_LOAD_ALL -eq '1') { Set-Var -name "ConfigurationType" -value "Application" Set-Var -name "VCTargetsPath" -value "$(Get-VisualStudio-Path)\Common7\IDE\VC\VCTargets\" Set-Var -name "VsInstallRoot" -value (Get-VisualStudio-Path) Set-Var -name "MSBuildExtensionsPath" -value "$(Get-VisualStudio-Path)\MSBuild" Set-Var -name "LocalAppData" -value $env:LOCALAPPDATA Set-Var -name "UniversalCRT_IncludePath" -value "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt" } [string] $vsVer = (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) Set-Var -name "VisualStudioVersion" -value $vsVer Set-Var -name "MSBuildToolsVersion" -value $vsVer [string] $projectSlnPath = Get-ProjectSolution [string] $projectSlnDir = Get-FileDirectory -filePath $projectSlnPath Set-Var -name "SolutionDir" -value $projectSlnDir [string] $projectSlnName = Get-FileName -path $projectSlnPath -noext Set-Var -name "SolutionName" -value $projectSlnName # pre-initialize Configuration and Platform properties if ( VariableExistsAndNotEmpty -name 'aVcxprojConfigPlatform') { Detect-ProjectDefaultConfigPlatform } Update-ParametersFromConfigFile } Function InitializeMsBuildCurrentFileProperties([Parameter(Mandatory = $true)][string] $filePath) { Set-Var -name "MSBuildThisFileFullPath" -value $filePath Set-Var -name "MSBuildThisFileExtension" -value ([IO.Path]::GetExtension($filePath)) Set-Var -name "MSBuildThisFile" -value (Get-FileName -path $filePath) Set-Var -name "MSBuildThisFileName" -value (Get-FileName -path $filePath -noext) Set-Var -name "MSBuildThisFileDirectory" -value (Get-FileDirectory -filePath $filePath) } <# .DESCRIPTION Sets the Configuration and Platform project properties so that conditions can be properly evaluated. #> function Detect-ProjectDefaultConfigPlatform() { [string] $configPlatformName = "" # detect the first platform/config pair from the project itemgroup $configItems = @(Get-Project-ItemList "ProjectConfiguration") if (![string]::IsNullOrWhiteSpace($global:cptCurrentConfigPlatform)) { # we have script parameters we can use to set the platform/config $configPlatformName = $global:cptCurrentConfigPlatform } if ((!$configItems -or $configItems.Count -eq 0)) { if ([string]::IsNullOrWhiteSpace($configPlatformName)) { throw [ProjectConfigurationNotFound]::new($global:vcxprojPath, ""); } } else { $targetConfiguration = $null if ([string]::IsNullOrEmpty($configPlatformName)) { $targetConfiguration = $configItems[0] } else { foreach ($configItem in $configItems) { [string] $platformName = $configItem[0] if ($platformName -ieq $configPlatformName) { $targetConfiguration = $configItem break } } if ($null -eq $targetConfiguration) { throw [ProjectConfigurationNotFound]::new($global:vcxprojPath, $configPlatformName); } } $configPlatformName = $targetConfiguration[0] } $global:cptCurrentConfigPlatform = $configPlatformName [string[]] $configAndPlatform = $configPlatformName.Split('|') Set-Var -Name "Configuration" -Value $configAndPlatform[0] Set-Var -Name "Platform" -Value $configAndPlatform[1] } function SanitizeProjectNode([System.Xml.XmlNode] $node) { if ($node.Name -ieq "#comment") { return } [System.Collections.ArrayList] $nodesToRemove = @() if ($node.Name -ieq "#text" -and $node.InnerText.Length -gt 0) { # evaluate node content $node.InnerText = Evaluate-MSBuildExpression $node.InnerText } if ($node.Name -ieq "Import") { [string] $relPath = Evaluate-MSBuildExpression $node.GetAttribute("Project") if (!$relPath) { return } [string[]] $paths = @(Canonize-Path -base (Get-Location) -child $relPath -ignoreErrors) [bool] $loadedProjectSheet = $false foreach ($path in $paths) { if (![string]::IsNullOrEmpty($path) -and (Test-Path -LiteralPath $path)) { Write-Verbose "Property sheet: $path" ParseProjectFile($path) $loadedProjectSheet = $true } } if (!$loadedProjectSheet) { Write-Verbose "Could not find property sheet $relPath" if ($relPath -like "\Microsoft.Cpp.props") { # now we can begin to evaluate directory.build.props XML element conditions, load it LoadDirectoryBuildPropSheetFile } } } if ( ($node.Name -ieq "ClCompile" -or $node.Name -ieq "ClInclude") -and ![string]::IsNullOrEmpty($node.GetAttribute("Include")) ) { [string] $expandedAttr = Evaluate-MSBuildExpression $node.GetAttribute("Include") $node.Attributes["Include"].Value = $expandedAttr } if ($node.Name -ieq "Otherwise") { [System.Xml.XmlElement[]] $siblings = @($node.ParentNode.ChildNodes | ` Where-Object { $_.GetType().Name -ieq "XmlElement" -and $_ -ne $node }) if ($siblings.Count -gt 0) { # means there's a element that matched # should not be evaluated, we could set unwated properties return } } if ($node.Name -ieq "ItemGroup") { [string] $oldItemContextName = Get-ProjectItemContext foreach ($child in $node.ChildNodes) { if ($child.GetType().Name -ine "XmlElement") { continue } [string] $childEvaluatedValue = Evaluate-MSBuildExpression $child.GetAttribute("Include") $itemProperties = @{} Set-ProjectItemContext $child.Name $contextProperties = Get-ProjectItemProperty if ($contextProperties -ne $null) { foreach ($k in $contextProperties.Keys) { $itemProperties[$k] = $contextProperties[$k] } } foreach ($nodePropChild in $child.ChildNodes) { if ($nodePropChild.GetType().Name -ine "XmlElement") { continue } if ($nodePropChild.HasAttribute("Condition")) { [string] $nodeCondition = $nodePropChild.GetAttribute("Condition") [bool] $conditionSatisfied = ((Evaluate-MSBuildCondition($nodeCondition)) -eq $true) if (!$conditionSatisfied) { continue } } $itemProperties[$nodePropChild.Name] = Evaluate-MSBuildExpression $nodePropChild.InnerText } Add-Project-Item -name $child.Name -value $childEvaluatedValue -properties $itemProperties } Set-ProjectItemContext $oldItemContextName if ($node.GetAttribute("Label") -ieq "ProjectConfigurations") { Detect-ProjectDefaultConfigPlatform } } if ($node.Name -ieq "ItemDefinitionGroup") { foreach ($child in $node.ChildNodes) { if ($child.GetType().Name -ine "XmlElement") { continue } Push-ProjectItemContext $child.Name foreach ($propNode in $child.ChildNodes) { if ($propNode.GetType().Name -ine "XmlElement") { continue } [string] $propVal = Evaluate-MSBuildExpression $propNode.InnerText Set-ProjectItemProperty $propNode.Name $propVal } Pop-ProjectItemContext } } if ($node.ParentNode -and $node.ParentNode.Name -ieq "PropertyGroup") { # set new property value [string] $propertyName = $node.Name [string] $propertyValue = Evaluate-MSBuildExpression $node.InnerText Set-Var -Name $propertyName -Value $propertyValue return } if ($node.ChildNodes.Count -eq 0) { return } foreach ($child in $node.ChildNodes) { [bool] $validChild = $true if ($child.GetType().Name -ieq "XmlElement") { if ($child.HasAttribute("Condition")) { # process node condition [string] $nodeCondition = $child.GetAttribute("Condition") $validChild = ((Evaluate-MSBuildCondition($nodeCondition)) -eq $true) if ($validChild) { $child.RemoveAttribute("Condition") } } } if (!$validChild) { $nodesToRemove.Add($child) > $null continue } else { SanitizeProjectNode($child) } } foreach ($nodeToRemove in $nodesToRemove) { $nodeToRemove.ParentNode.RemoveChild($nodeToRemove) > $null } } <# .DESCRIPTION Parses a project file and loads data into corresponding data structures. Project elements that are conditioned will be evaluated and discarded if their condition is evaluted to False. #> function ParseProjectFile([string] $projectFilePath) { # keep current file path, we'll need to restore it [string] $currentFile = "" if (VariableExistsAndNotEmpty 'MSBuildThisFileFullPath') { $currentFile = $MSBuildThisFileFullPath } Write-Verbose "`nSanitizing $projectFilePath" [xml] $fileXml = Get-Content -LiteralPath $projectFilePath $global:ProjectInputFiles.Add($projectFilePath) > $null Push-Location -LiteralPath (Get-FileDirectory -filePath $projectFilePath) InitializeMsBuildCurrentFileProperties -filePath $projectFilePath SanitizeProjectNode($fileXml.Project) Pop-Location # restore previous path if (![string]::IsNullOrWhiteSpace(($currentFile))) { Write-Verbose "[INFO] Restoring project file properties localstate to parent file" InitializeMsBuildCurrentFileProperties -filePath $currentFile } } function LoadDirectoryBuildPropSheetFile() { if ($env:CPT_LOAD_ALL -ne "1") { # Tries to find a Directory.Build.props property sheet, starting from the # project directory, going up. When one is found, the search stops. # Multiple Directory.Build.props sheets are not supported. [string] $directoryBuildSheetPath = (cpt::GetDirNameOfFileAbove -startDir $ProjectDir ` -targetFile "Directory.Build.props") + "\Directory.Build.props" if (Test-Path -LiteralPath $directoryBuildSheetPath) { ParseProjectFile($directoryBuildSheetPath) } [string] $vcpkgIncludePath = "$env:LOCALAPPDATA\vcpkg\vcpkg.user.targets" if (Test-Path -LiteralPath $vcpkgIncludePath) { ParseProjectFile($vcpkgIncludePath) } } } <# .DESCRIPTION Loads vcxproj and property sheets into memory. This needs to be called only once when processing a project. Accessing project data can be done using ItemGroups and Properties #> function LoadProject([string] $vcxprojPath) { # Clean global variables that have been set by a previous project load Clear-Vars $global:vcxprojPath = $vcxprojPath InitializeMsBuildProjectProperties ParseProjectFile -projectFilePath $global:vcxprojPath } ================================================ FILE: ClangPowerTools/ClangPowerTools/Tooling/v1/psClang/visualstudio-detection.ps1 ================================================ # ------------------------------------------------------------------------------------------------ # Helpers for locating Visual Studio on the computer # VsWhere is available starting with Visual Studio 2017 version 15.2. Set-Variable -name kVsWhereLocation ` -value "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" #` #-option Constant Function Convert-MSVCFolderName2Toolset([Parameter(Mandatory = $true)][string] $internalVer) { # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering $internalVer = $internalVer.Replace('.', ''); return $internalVer.Substring(0, 3); } Function Convert-PlatformToolset2VsVer([Parameter(Mandatory = $true)][string] $toolset) { switch ($toolset) { "141" { "2017" } "142" { "2019" } "143" { "2022" } } } Function Get-VisualStudioToolsets() { $toolsetFolders = (Get-Item "$(Get-VisualStudio-Path)\VC\Tools\MSVC\" | Get-ChildItem) [string[]] $toolsets = @() foreach ($folder in $toolsetFolders) { $toolsets += @(Convert-MSVCFolderName2Toolset -internalVer $folder.Name) } return ($toolsets | Where-Object { ![string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique) } Function Get-MscVer() { [string[]] $mscVerFolders = ((Get-Item "$(Get-VisualStudio-Path)\VC\Tools\MSVC\" | Get-ChildItem).Name | Sort-Object -Descending) foreach ($mscVerFolderName in $mscVerFolders) { # get the latest toolset (mscver) that matches our target Visual Studio version [string] $platformToolset = Convert-MSVCFolderName2Toolset $mscVerFolderName [string] $vsTargetVer = Convert-PlatformToolset2VsVer $platformToolset if ($vsTargetVer -eq $global:cptVisualStudioVersion) { return $mscVerFolderName } } } Function Get-VisualStudio-Includes([Parameter(Mandatory = $true)][string] $vsPath, [Parameter(Mandatory = $false)][string] $mscVer) { [string] $mscVerToken = "" If (![string]::IsNullOrEmpty($mscVer)) { $mscVerToken = "Tools\MSVC\$mscVer\" } return @( "$vsPath\VC\$($mscVerToken)include" , "$vsPath\VC\$($mscVerToken)atlmfc\include" , "$vsPath\VC\Auxiliary\VS\include" ) } Function Get-VsWhere-VisualStudio-Version() { switch ($global:cptVisualStudioVersion) { "2013" { return "[12.0, 13)" } "2015" { return "[14.0, 15)" } "2017" { return "[15.0, 16)" } "2019" { return "[16.0, 17)" } "2022" { return "[17.0, 18)" } default { throw "Unsupported Visual Studio version: $cptVisualStudioVersion" } } } Function Get-VisualStudio-VersionNumber([Parameter(Mandatory = $true)][string] $vsYearVersion) { switch ($vsYearVersion) { "2013" { return "12.0" } "2015" { return "14.0" } "2017" { return "15.0" } "2019" { return "16.0" } "2022" { return "17.0" } default { throw "Unsupported Visual Studio version: $vsYearVersion" } } } # Newer Visual Studio versions support installing older toolset versions, for compatibility reasons. # Returns default instalation path of the current VS version/toolset. Function Get-VisualStudio-CompatiblityToolset-InstallLocation() { if ( ([int] $global:cptVisualStudioVersion) -le 2022) { return "${Env:ProgramFiles}\Microsoft Visual Studio " + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } return "${Env:ProgramFiles(x86)}\Microsoft Visual Studio " + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } Function Get-VisualStudio-RegistryLocation() { if ( ([int] $global:cptVisualStudioVersion) -le 2022) { return "HKLM:SOFTWARE\Microsoft\VisualStudio\" + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } return "HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\" + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } Function Get-VisualStudio-Path() { # Depending of the version of Visual Studio, we have different approaches to locating it. if ( ([int] $global:cptVisualStudioVersion) -le 2015 ) { # Older Visual Studio (<= 2015). VSWhere is not available. [string] $installLocation = (Get-Item (Get-VisualStudio-RegistryLocation)).GetValue("InstallDir") if ($installLocation) { $installLocation = Canonize-Path -base $installLocation -child "..\.." -ignoreErrors } if ($installLocation) { return $installLocation } # we may have a newer VS installation with an older toolset feature installed [string] $toolsetDiskLocation = (Get-VisualStudio-CompatiblityToolset-InstallLocation) [string] $iostreamLocation = Canonize-Path -base toolsetDiskLocation ` -child "VC\include\iostream" -ignoreErrors if ($iostreamLocation) { return $toolsetDiskLocation } Write-Err "Visual Studio $($global:cptVisualStudioVersion) installation location could not be detected" } else { # modern Visual Studio (> 2017). Use VSWhere to locate it. if (Test-Path -LiteralPath $kVsWhereLocation) { [string] $product = "*" if (![string]::IsNullOrEmpty($aVisualStudioSku)) { $product = "Microsoft.VisualStudio.Product.$aVisualStudioSku" } [string] $version = Get-VsWhere-VisualStudio-Version [string[]] $output = @(& "$kVsWhereLocation" -nologo ` -property installationPath ` -products $product ` -version $version ` -prerelease) # the -prerelease switch is not available on older VS2017 versions if (($output -join "").Contains("0x57")) <# error code for unknown parameter #> { $output = (& "$kVsWhereLocation" -nologo ` -property installationPath ` -version $version ` -products $product) } if (!$output) { throw "VsWhere could not detect Visual Studio $($global:cptVisualStudioVersion) $product." } [string] $installationPath = $output[0] Write-Verbose "Detected (vswhere) VisualStudio installation path: $installationPath" return $installationPath } if ( ([int] $global:cptVisualStudioVersion) -le 2022) { [string] $kVsDefaultLocation = "${Env:ProgramFiles}\Microsoft Visual Studio\$global:cptVisualStudioVersion\$aVisualStudioSku" } else { [string] $kVsDefaultLocation = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\$global:cptVisualStudioVersion\$aVisualStudioSku" } if (Test-Path -LiteralPath $kVsDefaultLocation) { return $kVsDefaultLocation } throw "Cannot locate Visual Studio $($global:cptVisualStudioVersion)" } } ================================================ FILE: ClangPowerTools/ClangPowerTools/VSPackage.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 RunPowerShellCommand Extension RunPowerShellCommand Visual Studio Extension Detailed Info ================================================ FILE: ClangPowerTools/ClangPowerTools/cpt.config ================================================ "-Werror" , "-Wall" , "-fms-compatibility-version=19.10" , "-Wmicrosoft" , "-Wno-invalid-token-paste" , "-Wno-unknown-pragmas" , "-Wno-unused-value" '.*' ================================================ FILE: ClangPowerTools/ClangPowerTools/source.extension.vsixmanifest ================================================  Clang Power Tools A tool bringing clang-tidy magic to Visual Studio C++ developers. http://www.clangpowertools.com/QaA Resources\LICENSE.txt http://www.clangpowertools.com http://www.clangpowertools.com/CHANGELOG Resources\CPTLogoManageExtensionVS.png Resources\CPTLogoManageExtensionVS.png clang;clang-tidy;clang-format;compile;modernize;CoreGuidelines;static analysis;tidy;C++;cpp;analyze x86 amd64 x86 amd64 x86 amd64 ================================================ FILE: ClangPowerTools/ClangPowerTools.aip ================================================ ================================================ FILE: ClangPowerTools/ClangPowerTools.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.0 MinimumVisualStudioVersion = 15.0.0 Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ClangPowerToolsShared", "ClangPowerToolsShared\ClangPowerToolsShared.shproj", "{A0CEA277-F6A1-4F62-862C-357C8C5654AA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangPowerTools", "ClangPowerTools\ClangPowerTools.csproj", "{51237463-9F4D-44DE-8BC0-587384B9E8B8}" ProjectSection(ProjectDependencies) = postProject {C866AF9F-8754-4C75-8A47-A8055F7E2D3A} = {C866AF9F-8754-4C75-8A47-A8055F7E2D3A} {B71297DD-B444-4AA5-AC7B-99BD812E9129} = {B71297DD-B444-4AA5-AC7B-99BD812E9129} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangPowerToolsLib16", "ClangPowerToolsLib16\ClangPowerToolsLib16.csproj", "{C866AF9F-8754-4C75-8A47-A8055F7E2D3A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangPowerToolsLib17", "ClangPowerToolsLib17\ClangPowerToolsLib17.csproj", "{B71297DD-B444-4AA5-AC7B-99BD812E9129}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|Any CPU.Build.0 = Debug|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|x64.ActiveCfg = Debug|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|x64.Build.0 = Debug|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|x86.ActiveCfg = Debug|x86 {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Debug|x86.Build.0 = Debug|x86 {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|Any CPU.Build.0 = Release|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|x64.ActiveCfg = Release|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|x64.Build.0 = Release|Any CPU {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|x86.ActiveCfg = Release|x86 {51237463-9F4D-44DE-8BC0-587384B9E8B8}.Release|x86.Build.0 = Release|x86 {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|x64.ActiveCfg = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|x64.Build.0 = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|x86.ActiveCfg = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Debug|x86.Build.0 = Debug|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|Any CPU.Build.0 = Release|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|x64.ActiveCfg = Release|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|x64.Build.0 = Release|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|x86.ActiveCfg = Release|Any CPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A}.Release|x86.Build.0 = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|Any CPU.Build.0 = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|x64.ActiveCfg = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|x64.Build.0 = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|x86.ActiveCfg = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Debug|x86.Build.0 = Debug|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|Any CPU.ActiveCfg = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|Any CPU.Build.0 = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|x64.ActiveCfg = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|x64.Build.0 = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|x86.ActiveCfg = Release|Any CPU {B71297DD-B444-4AA5-AC7B-99BD812E9129}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {15C5DC16-7442-43C6-8076-5E27B900176B} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution ClangPowerToolsShared\ClangPowerToolsShared.projitems*{a0cea277-f6a1-4f62-862c-357c8c5654aa}*SharedItemsImports = 13 ClangPowerToolsShared\ClangPowerToolsShared.projitems*{b71297dd-b444-4aa5-ac7b-99bd812e9129}*SharedItemsImports = 4 ClangPowerToolsShared\ClangPowerToolsShared.projitems*{c866af9f-8754-4c75-8a47-a8055f7e2d3a}*SharedItemsImports = 4 EndGlobalSection EndGlobal ================================================ FILE: ClangPowerTools/ClangPowerToolsLib16/ClangPowerToolsLib16.csproj ================================================  17.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) win latest true Key.snk Debug AnyCPU {C866AF9F-8754-4C75-8A47-A8055F7E2D3A} Library Properties ClangPowerTools ClangPowerToolsLib16 v4.7.2 512 true true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 15.9.28307 runtime; build; native; contentfiles; analyzers; buildtransitive all 5.0.0 5.0.0 True True Resource.resx ResXFileCodeGenerator Resource.Designer.cs xcopy "$(TargetPath)" "$(SolutionDir)ClangPowerTools" /y ================================================ FILE: ClangPowerTools/ClangPowerToolsLib16/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ClangPowerToolsLib16")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClangPowerToolsLib16")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("c866af9f-8754-4c75-8a47-a8055f7e2d3a")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ClangPowerTools/ClangPowerToolsLib16/Properties/Resource.Designer.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace ClangPowerTools.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resource() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClangPowerTools.Properties.Resource", typeof(Resource).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to Deselect all. /// internal static string DeselectAllTooltipText { get { return ResourceManager.GetString("DeselectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Encoding Converter. /// internal static string EncodingConverterWindowTitle { get { return ResourceManager.GetString("EncodingConverterWindowTitle", resourceCulture); } } /// /// Looks up a localized string similar to encoding is not supported. /// internal static string EncodingError { get { return ResourceManager.GetString("EncodingError", resourceCulture); } } /// /// Looks up a localized string similar to The following files are not encoded in UTF-8. Do you want to change their encoding?. /// internal static string EncodingErrorText { get { return ResourceManager.GetString("EncodingErrorText", resourceCulture); } } /// /// Looks up a localized string similar to Select all. /// internal static string SelectAllTooltipText { get { return ResourceManager.GetString("SelectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Unicode (UTF-8). /// internal static string UTF8Encoding { get { return ResourceManager.GetString("UTF8Encoding", resourceCulture); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsLib16/Properties/Resource.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Deselect all Encoding Converter encoding is not supported The following files are not encoded in UTF-8. Do you want to change their encoding? Select all Unicode (UTF-8) ================================================ FILE: ClangPowerTools/ClangPowerToolsLib17/ClangPowerToolsLib17.csproj ================================================  17.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) win latest true Key.snk Debug AnyCPU {B71297DD-B444-4AA5-AC7B-99BD812E9129} Library Properties ClangPowerTools ClangPowerToolsLib17 v4.7.2 512 true true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 runtime; build; native; contentfiles; analyzers; buildtransitive all 5.0.0 8.0.0 True True Resource.resx ResXFileCodeGenerator Resource.Designer.cs xcopy "$(TargetPath)" "$(SolutionDir)ClangPowerTools" /y ================================================ FILE: ClangPowerTools/ClangPowerToolsLib17/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ClangPowerToolsLib16")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ClangPowerToolsLib16")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("c866af9f-8754-4c75-8a47-a8055f7e2d3a")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ClangPowerTools/ClangPowerToolsLib17/Properties/Resource.Designer.cs ================================================ //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace ClangPowerTools.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resource() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClangPowerTools.Properties.Resource", typeof(Resource).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to Deselect all. /// internal static string DeselectAllTooltipText { get { return ResourceManager.GetString("DeselectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Encoding Converter. /// internal static string EncodingConverterWindowTitle { get { return ResourceManager.GetString("EncodingConverterWindowTitle", resourceCulture); } } /// /// Looks up a localized string similar to encoding is not supported. /// internal static string EncodingError { get { return ResourceManager.GetString("EncodingError", resourceCulture); } } /// /// Looks up a localized string similar to The following files are not encoded in UTF-8. Do you want to change their encoding?. /// internal static string EncodingErrorText { get { return ResourceManager.GetString("EncodingErrorText", resourceCulture); } } /// /// Looks up a localized string similar to Select all. /// internal static string SelectAllTooltipText { get { return ResourceManager.GetString("SelectAllTooltipText", resourceCulture); } } /// /// Looks up a localized string similar to Unicode (UTF-8). /// internal static string UTF8Encoding { get { return ResourceManager.GetString("UTF8Encoding", resourceCulture); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsLib17/Properties/Resource.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Deselect all Encoding Converter encoding is not supported The following files are not encoded in UTF-8. Do you want to change their encoding? Select all Unicode (UTF-8) ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Attributes/ClangCheckAttribute.cs ================================================ using System; namespace ClangPowerTools { [AttributeUsage(AttributeTargets.Property)] public class ClangCheckAttribute : Attribute { public bool IsFlag { get; private set; } public ClangCheckAttribute(bool aIsFlag) { IsFlag = aIsFlag; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Attributes/ClangFormatPathAttribute.cs ================================================ using System; namespace ClangPowerTools { [AttributeUsage(AttributeTargets.Property)] public class ClangFormatPathAttribute : Attribute { public bool Activate { get; set; } public ClangFormatPathAttribute(bool aActivate) { Activate = aActivate; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Attributes/ClangTidyPathAttribute.cs ================================================ using System; namespace ClangPowerTools { [AttributeUsage(AttributeTargets.Property)] public class ClangTidyPathAttribute : Attribute { public bool Activate { get; set; } public ClangTidyPathAttribute(bool aActivate) { Activate = aActivate; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Builder/IAsyncBuilder.cs ================================================ using System.Threading.Tasks; namespace ClangPowerTools.Builder { public interface IBuilderAsync { Task BuildAsync(); T GetAsyncResult(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Builder/IBuilder.cs ================================================ namespace ClangPowerTools.Builder { public interface IBuilder { void Build(); T GetResult(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/CMake/CMakeBuilder.cs ================================================ using ClangPowerTools.Helpers; using System.IO; namespace ClangPowerTools.CMake { public class CMakeBuilder { #region Members private readonly string directoryName = "CPTCMakeBuild"; private FileStream VcxprojFile; #endregion #region Public Methods /// /// Create the build directory("CPTCMakeBuild") for the current CMake project /// /// The name of the created directory /// The full path of the created directory /// True if the directory is created successfully. False otherwise. public bool CreateBuildDirectory(string newDirName, out string dirPath) { dirPath = null; SolutionInfo.GetSolutionInfo(out string dir, out _, out _); if (Directory.Exists(dir) == false) return false; dirPath = Path.Combine(dir, newDirName); if (Directory.Exists(dirPath)) return true; Directory.CreateDirectory(dirPath); return true; } /// /// Build the current CMake project. The process will generate one .sln file and posible more .vcxproj files. /// public void Build() { if (CreateBuildDirectory(directoryName, out string dirPath) == false) return; LockVcxprojFile(); var command = "cmake -G \"Visual Studio 16 2019\" .."; using (System.Diagnostics.Process process = new System.Diagnostics.Process() { StartInfo = new System.Diagnostics.ProcessStartInfo() { CreateNoWindow = true, WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden, WorkingDirectory = dirPath, FileName = "cmd.exe", Arguments = "/c " + command, UseShellExecute = false } }) { process.Start(); process.WaitForExit(); } UnlockVcxprojFile(); } /// /// Locks vcxproj file by opening it. This function is used before generating /// .sln and .vcxproj, because if user already have a /// .vcxproj generated, this file will be overriden. /// We need to lock user .vcxproj file and gerenate .sln /// and .vcxproj in a temp folder /// private void LockVcxprojFile() { SolutionInfo.GetSolutionInfo(out string dir, out _, out _); if (Directory.Exists(dir) == false) return; var dirName = new DirectoryInfo(dir).Name; var vcxprojPath = Path.Combine(dir, dirName, dirName + ScriptConstants.kProjectFileExtension); if(File.Exists(vcxprojPath)) VcxprojFile = File.Open(vcxprojPath, FileMode.Open, FileAccess.Write); } private void UnlockVcxprojFile() { if (VcxprojFile != null) { VcxprojFile.Close(); VcxprojFile.Dispose(); } } /// /// Delete from the disk the CMake build directory and all its content. /// public void ClearBuildCashe() { CreateBuildDirectory(directoryName, out string dirPath); if (string.IsNullOrWhiteSpace(dirPath)) return; Directory.Delete(dirPath, true); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/ClangPowerToolsPackage.cs ================================================ using ClangPowerTools.Commands; using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Views; using ClangPowerTools.Output; using ClangPowerTools.Services; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.CommandBars; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { /// /// This is the class that implements the package exposed by this assembly. /// /// /// /// The minimum requirement for a class to be considered a valid package for Visual Studio /// is to implement the IVsPackage interface and register itself with the shell. /// This package uses the helper classes defined inside the Managed Package Framework (MPF) /// to do it: it derives from the Package class that provides the implementation of the /// IVsPackage interface and uses the registration attributes defined in the framework to /// register itself and its components with the shell. These attributes tell the pkgdef creation /// utility what data to put into .pkgdef file. /// /// /// To get loaded into VS, the package must be referred by <Asset Type="Microsoft.VisualStudio.VsPackage" ...> in .vsixmanifest file. /// /// [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About [ProvideMenuResource("Menus.ctmenu", 1)] [ProvideToolWindow(typeof(TidyToolWindow), Style = VsDockStyle.Tabbed, DockedWidth = 300, Window = "DocumentWell", Orientation = ToolWindowOrientation.Left)] [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExistsAndFullyLoaded_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string, PackageAutoLoadFlags.BackgroundLoad)] [ProvideMenuResource("Menus.ctmenu", 1)] [ProvideToolWindow(typeof(TidyToolWindow), Style = VsDockStyle.Tabbed, DockedWidth = 300, Window = "DocumentWell", Orientation = ToolWindowOrientation.Left, Transient = true)] [Guid(PackageGuidString)] public sealed class RunClangPowerToolsPackage : AsyncPackage, IVsSolutionEvents, IVsSolutionLoadEvents, IVsSolutionEvents7 { #region Members /// /// RunPowerShellCommandPackage GUID string. /// public const string PackageGuidString = "f564f9d3-01ae-493e-883b-18deebdb975e"; private uint mHSolutionEvents = uint.MaxValue; private RunningDocTableEvents mRunningDocTableEvents; private ErrorWindowController mErrorWindowController; private OutputWindowController mOutputWindowController; private CommandController mCommandController; private CommandEvents mCommandEvents; private BuildEvents mBuildEvents; private DTEEvents mDteEvents; private WindowEvents windowEvents; #endregion #region Constructor /// /// Initializes a new instance of the class. /// public RunClangPowerToolsPackage() { // Inside this method you can place any initialization code that does not require // any Visual Studio service because at this point the package object is created but // not sited yet inside Visual Studio environment. The place to do all the other // initialization is the Initialize method. } #endregion #region Initialize Package /// /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { // Switches to the UI thread in order to consume some services used in command initialization await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); await RegisterVsServicesAsync(); mCommandController = new CommandController(this); CommandControllerInstance.CommandController = mCommandController; var vsOutputWindow = VsServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow; mOutputWindowController = new OutputWindowController(); mOutputWindowController.Initialize(this, vsOutputWindow); mRunningDocTableEvents = new RunningDocTableEvents(this); mErrorWindowController = new ErrorWindowController(this); #region Get Pointer to IVsSolutionEvents if (VsServiceProvider.TryGetService(typeof(SVsSolution), out object vsSolutionService)) { var vsSolution = vsSolutionService as IVsSolution; UnadviseSolutionEvents(vsSolution); AdviseSolutionEvents(vsSolution); } #endregion // Get-Set the build and command events from DTE if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var dte2 = dte as DTE2; mBuildEvents = dte2.Events.BuildEvents; mCommandEvents = dte2.Events.CommandEvents; mDteEvents = dte2.Events.DTEEvents; windowEvents = dte2.Events.WindowEvents; } var settingsHandler = new SettingsHandler(); settingsHandler.InitializeSettings(); await settingsHandler.InitializeAccountSettingsAsync(); string version = SettingsProvider.GeneralSettingsModel.Version; ShowToolbar(version); UpdateVersion(version); await mCommandController.InitializeCommandsAsync(this); await RegisterToEventsAsync(); await base.InitializeAsync(cancellationToken, progress); } //public override IVsAsyncToolWindowFactory GetAsyncToolWindowFactory(Guid toolWindowType) //{ // return toolWindowType.Equals(Guid.Parse(TidyToolWindow.WindowGuidString)) ? this : null; //} //protected override string GetToolWindowTitle(Type toolWindowType, int id) //{ // return toolWindowType == typeof(TidyToolWindow) ? TidyToolWindow.Title : base.GetToolWindowTitle(toolWindowType, id); //} #endregion #region Get Pointer to IVsSolutionEvents private void AdviseSolutionEvents(IVsSolution aVsSolution) { try { aVsSolution?.AdviseSolutionEvents(this, out mHSolutionEvents); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void UnadviseSolutionEvents(IVsSolution aVsSolution) { if (null == aVsSolution) return; if (uint.MaxValue != mHSolutionEvents) { aVsSolution.UnadviseSolutionEvents(mHSolutionEvents); mHSolutionEvents = uint.MaxValue; } aVsSolution = null; } #endregion #region IVsSolutionEvents Implementation public int OnAfterOpenProject(IVsHierarchy aPHierarchy, int aFAdded) { CreateCacheRepository(); return VSConstants.S_OK; } public int OnQueryCloseProject(IVsHierarchy aPHierarchy, int aFRemoving, ref int aPfCancel) { DeleteTempSolution(); HideToolWindow(); DeleteCacheReporitory(); return VSConstants.S_OK; } public int OnBeforeCloseProject(IVsHierarchy aPHierarchy, int aFRemoved) { aPHierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out object projectObject); if (projectObject is Project project) mErrorWindowController.RemoveErrors(aPHierarchy); return VSConstants.S_OK; } public int OnAfterLoadProject(IVsHierarchy aPStubHierarchy, IVsHierarchy aPRealHierarchy) { DeleteTempSolution(); HideToolWindow(); DeleteCacheReporitory(); return VSConstants.S_OK; } public int OnQueryUnloadProject(IVsHierarchy aPRealHierarchy, ref int aPfCancel) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnBeforeUnloadProject(IVsHierarchy aPRealHierarchy, IVsHierarchy aPStubHierarchy) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnAfterOpenSolution(object aPUnkReserved, int aFNewSolution) { CreateCacheRepository(); return VSConstants.S_OK; } public int OnQueryCloseSolution(object aPUnkReserved, ref int aPfCancel) { return VSConstants.S_OK; } public int OnBeforeCloseSolution(object aPUnkReserved) { DeleteTempSolution(); var tidyToolWindow = FindToolWindow(typeof(TidyToolWindow), 0, false); if (tidyToolWindow is null) return VSConstants.S_OK; var window = tidyToolWindow.Frame as IVsWindowFrame; window.Hide(); return VSConstants.S_OK; } public int OnAfterCloseSolution(object aPUnkReserved) { return VSConstants.S_OK; } #endregion #region IVsSolutionLoadEvents implementation public int OnBeforeOpenSolution(string pszSolutionFilename) { return VSConstants.S_OK; } public int OnBeforeBackgroundSolutionLoadBegins() { return VSConstants.S_OK; } public int OnQueryBackgroundLoadProjectBatch(out bool pfShouldDelayLoadToNextIdle) { pfShouldDelayLoadToNextIdle = false; return VSConstants.S_OK; } public int OnBeforeLoadProjectBatch(bool fIsBackgroundIdleBatch) { return VSConstants.S_OK; } public int OnAfterLoadProjectBatch(bool fIsBackgroundIdleBatch) { return VSConstants.S_OK; } public int OnAfterBackgroundSolutionLoadComplete() { return VSConstants.S_OK; } #endregion #region IVsSolution7 implementation public void OnAfterOpenFolder(string folderPath) { } public void OnBeforeCloseFolder(string folderPath) { } public void OnQueryCloseFolder(string folderPath, ref int pfCancel) { } public void OnAfterCloseFolder(string folderPath) { } public void OnAfterLoadAllDeferredProjects() { } #endregion #region Private Methods private void UpdateVersion(string version) { var generalSettingsModel = SettingsProvider.GeneralSettingsModel; string currentVersion = PackageUtility.GetVersion(); if (string.IsNullOrWhiteSpace(currentVersion) == false && 0 > string.Compare(version, currentVersion)) { generalSettingsModel.Version = currentVersion; var settingsHandler = new SettingsHandler(); settingsHandler.SaveSettings(); //var freeTrialController = new FreeTrialController(); //bool activeLicense = await new LocalLicenseValidator().ValidateAsync(); //if (activeLicense) // freeTrialController.MarkAsExpired(); ReleaseNotesView.WasShown = false; } } private void ShowToolbar(string version) { // Detect the first install if (!string.IsNullOrWhiteSpace(version)) return; // Show the toolbar on the first install if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var cbs = ((CommandBars)(dte as DTE2).CommandBars); CommandBar cb = cbs["Clang Power Tools"]; cb.Enabled = true; cb.Visible = true; } } private async Task RegisterVsServicesAsync() { // Get DTE service async var dte = await GetServiceAsync(typeof(DTE)) as DTE2; VsServiceProvider.Register(typeof(DTE2), dte); // Get VS Output Window service async var vsOutputWindow = await GetServiceAsync(typeof(SVsOutputWindow)); VsServiceProvider.Register(typeof(SVsOutputWindow), vsOutputWindow); // Get the status bar service async var vsStatusBar = await GetServiceAsync(typeof(SVsStatusbar)); VsServiceProvider.Register(typeof(SVsStatusbar), vsStatusBar); // Get Vs Running Document Table service async var vsRunningDocumentTable = await GetServiceAsync(typeof(SVsRunningDocumentTable)); VsServiceProvider.Register(typeof(SVsRunningDocumentTable), vsRunningDocumentTable); // Get Vs File Change service async var vsFileChange = await GetServiceAsync(typeof(SVsFileChangeEx)); VsServiceProvider.Register(typeof(SVsFileChangeEx), vsFileChange); // Get VS Solution service async var vsSolution = await GetServiceAsync(typeof(SVsSolution)); VsServiceProvider.Register(typeof(SVsSolution), vsSolution); } private async Task RegisterToEventsAsync() { //await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.Run(async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); RegisterToCPTEvents(); RegisterToVsEvents(); }); } private void RegisterToCPTEvents() { mCommandController.ClangCommandMessageEvent += mOutputWindowController.Write; mCommandController.ClearOutputWindowEvent += mOutputWindowController.ClearPanel; mCommandController.HierarchyDetectedEvent += mOutputWindowController.OnFileHierarchyDetected; mCommandController.HasEncodingErrorEvent += mOutputWindowController.OnEncodingErrorDetected; mOutputWindowController.HasEncodingErrorEvent += mCommandController.OnEncodingErrorDetected; mCommandController.ClearErrorListEvent += mErrorWindowController.OnClangCommandBegin; CompileCommand.Instance.HierarchyDetectedEvent += mCommandController.OnFileHierarchyChanged; TidyCommand.Instance.HierarchyDetectedEvent += mCommandController.OnFileHierarchyChanged; mCommandController.ErrorDetectedEvent += mOutputWindowController.OnErrorDetected; mOutputWindowController.ErrorDetectedEvent += mErrorWindowController.OnErrorDetected; mOutputWindowController.JsonCompilationDbFilePathEvent += JsonCompilationDatabaseCommand.Instance.OpenInFileExplorer; CompileCommand.Instance.CloseDataStreamingEvent += mCommandController.OnAfterRunCommand; TidyCommand.Instance.CloseDataStreamingEvent += mCommandController.OnAfterRunCommand; JsonCompilationDatabaseCommand.Instance.CloseDataStreamingEvent += mCommandController.OnAfterRunCommand; FormatCommand.Instance.FormatEvent += mCommandController.OnAfterFormatCommand; CompileCommand.Instance.ActiveDocumentEvent += mCommandController.OnActiveDocumentCheck; TidyCommand.Instance.ActiveDocumentEvent += mCommandController.OnActiveDocumentCheck; CompileCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; TidyCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; FormatCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; PowerShellWrapper.DataHandler += mOutputWindowController.OutputDataReceived; PowerShellWrapper.DataErrorHandler += mOutputWindowController.OutputDataErrorReceived; PowerShellWrapper.ExitedHandler += mOutputWindowController.ClosedDataConnection; } private void RegisterToVsEvents() { if (null != mBuildEvents) { mBuildEvents.OnBuildBegin += mErrorWindowController.OnBuildBegin; mBuildEvents.OnBuildBegin += mCommandController.OnMSVCBuildBegin; mBuildEvents.OnBuildDone += mCommandController.OnMSVCBuildDone; } if (null != mCommandEvents) mCommandEvents.BeforeExecute += mCommandController.CommandEventsBeforeExecute; if (null != mRunningDocTableEvents) mRunningDocTableEvents.BeforeSave += mCommandController.OnBeforeSave; if (null != mDteEvents) mDteEvents.OnBeginShutdown += UnregisterFromEvents; if (windowEvents != null) windowEvents.WindowActivated += mCommandController.OnWindowActivated; } private void UnregisterFromEvents() { UnregisterFromCPTEvents(); UnregisterFromVsEvents(); } private void UnregisterFromCPTEvents() { mCommandController.ClangCommandMessageEvent -= mOutputWindowController.Write; mCommandController.ClearOutputWindowEvent -= mOutputWindowController.ClearPanel; mCommandController.HierarchyDetectedEvent -= mOutputWindowController.OnFileHierarchyDetected; mCommandController.HasEncodingErrorEvent -= mOutputWindowController.OnEncodingErrorDetected; mOutputWindowController.HasEncodingErrorEvent -= mCommandController.OnEncodingErrorDetected; mCommandController.ClearErrorListEvent -= mErrorWindowController.OnClangCommandBegin; CompileCommand.Instance.HierarchyDetectedEvent -= mCommandController.OnFileHierarchyChanged; TidyCommand.Instance.HierarchyDetectedEvent -= mCommandController.OnFileHierarchyChanged; mCommandController.ErrorDetectedEvent -= mOutputWindowController.OnErrorDetected; mOutputWindowController.ErrorDetectedEvent -= mErrorWindowController.OnErrorDetected; mOutputWindowController.JsonCompilationDbFilePathEvent -= JsonCompilationDatabaseCommand.Instance.OpenInFileExplorer; CompileCommand.Instance.CloseDataStreamingEvent -= mCommandController.OnAfterRunCommand; TidyCommand.Instance.CloseDataStreamingEvent -= mCommandController.OnAfterRunCommand; JsonCompilationDatabaseCommand.Instance.CloseDataStreamingEvent += mCommandController.OnAfterRunCommand; FormatCommand.Instance.FormatEvent -= mCommandController.OnAfterFormatCommand; CompileCommand.Instance.ActiveDocumentEvent -= mCommandController.OnActiveDocumentCheck; TidyCommand.Instance.ActiveDocumentEvent -= mCommandController.OnActiveDocumentCheck; CompileCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; TidyCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; FormatCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; PowerShellWrapper.DataHandler -= mOutputWindowController.OutputDataReceived; PowerShellWrapper.DataErrorHandler -= mOutputWindowController.OutputDataErrorReceived; PowerShellWrapper.ExitedHandler -= mOutputWindowController.ClosedDataConnection; } private void DeleteTempSolution() { var solutionPath = Path.Combine(TidyConstants.TempsFolderPath, TidyConstants.SolutionTempGuid); if (Directory.Exists(solutionPath)) { Directory.Delete(TidyConstants.LongFilePrefix + solutionPath, true); } } private int HideToolWindow() { var tidyToolWindow = FindToolWindow(typeof(TidyToolWindow), 0, false); if (tidyToolWindow is null) return VSConstants.S_OK; var window = tidyToolWindow.Frame as IVsWindowFrame; window.Hide(); return VSConstants.S_OK; } private void DeleteCacheReporitory() { //Delete cache repository; if (Directory.Exists(PathConstants.CacheRepositoryPath)) { Directory.Delete(PathConstants.CacheRepositoryPath, true); } } private void CreateCacheRepository() { //Create cache repository if (Directory.Exists(PathConstants.CacheRepositoryPath)) { DeleteCacheReporitory(); } Directory.CreateDirectory(PathConstants.CacheRepositoryPath); } private void UnregisterFromVsEvents() { if (null != mBuildEvents) { mBuildEvents.OnBuildBegin -= mErrorWindowController.OnBuildBegin; mBuildEvents.OnBuildBegin -= mCommandController.OnMSVCBuildBegin; mBuildEvents.OnBuildDone -= mCommandController.OnMSVCBuildDone; } if (null != mCommandEvents) mCommandEvents.BeforeExecute -= mCommandController.CommandEventsBeforeExecute; if (null != mRunningDocTableEvents) mRunningDocTableEvents.BeforeSave -= mCommandController.OnBeforeSave; if (null != mDteEvents) mDteEvents.OnBeginShutdown -= UnregisterFromEvents; if (windowEvents != null) windowEvents.WindowActivated -= mCommandController.OnWindowActivated; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/ClangPowerToolsPackageImpl.cs ================================================ using ClangPowerTools.Commands; using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Views; using ClangPowerTools.Output; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.Helpers; using ClangPowerToolsShared.MVVM; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Provider; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.CommandBars; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.IO; using System.Linq; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { public class ClangPowerToolsPackageImpl : IVsSolutionEvents, IVsSolutionLoadEvents, IVsSolutionEvents7 { #region Members /// /// RunPowerShellCommandPackage GUID string. /// public const string PackageGuidString = "f564f9d3-01ae-493e-883b-18deebdb975e"; private uint mHSolutionEvents = uint.MaxValue; private RunningDocTableEvents mRunningDocTableEvents; private ErrorWindowController mErrorWindowController; private CommandController mCommandController; private CommandEvents mCommandEvents; private BuildEvents mBuildEvents; private DTEEvents mDteEvents; private WindowEvents windowEvents; private AsyncPackage mPackage; #endregion #region Constructor /// /// Initializes a new instance of the class. /// public ClangPowerToolsPackageImpl(AsyncPackage aPackage) { mPackage = aPackage; } #endregion #region Initialize Package /// /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// public async Task InitializeAsync() { try { await RegisterVsServicesAsync(); mCommandController = new CommandController(mPackage); CommandControllerInstance.CommandController = mCommandController; var vsOutputWindow = VsServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow; PowerShellWrapper.mOutputWindowController = new OutputWindowController(); PowerShellWrapper.mOutputWindowController.Initialize(mPackage, vsOutputWindow); mRunningDocTableEvents = new RunningDocTableEvents(mPackage); mErrorWindowController = new ErrorWindowController(mPackage); #region Get Pointer to IVsSolutionEvents if (VsServiceProvider.TryGetService(typeof(SVsSolution), out object vsSolutionService)) { var vsSolution = vsSolutionService as IVsSolution; UnadviseSolutionEvents(vsSolution); AdviseSolutionEvents(vsSolution); } #endregion // Get-Set the build and command events from DTE if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var dte2 = dte as DTE2; mBuildEvents = dte2.Events.BuildEvents; mCommandEvents = dte2.Events.CommandEvents; mDteEvents = dte2.Events.DTEEvents; windowEvents = dte2.Events.WindowEvents; } var findToolWindowHandler = new FindToolWindowHandler(); findToolWindowHandler.Initialize(); var settingsHandler = new SettingsHandler(); settingsHandler.InitializeSettings(); await settingsHandler.InitializeAccountSettingsAsync(); string version = SettingsProvider.GeneralSettingsModel.Version; ShowToolbar(version); UpdateVersion(version); await mCommandController.InitializeCommandsAsync(mPackage); await RegisterToEventsAsync(); } catch (Exception ex) { } } #endregion #region Get Pointer to IVsSolutionEvents private void AdviseSolutionEvents(IVsSolution aVsSolution) { try { aVsSolution?.AdviseSolutionEvents(this, out mHSolutionEvents); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void UnadviseSolutionEvents(IVsSolution aVsSolution) { if (null == aVsSolution) return; if (uint.MaxValue != mHSolutionEvents) { aVsSolution.UnadviseSolutionEvents(mHSolutionEvents); mHSolutionEvents = uint.MaxValue; } aVsSolution = null; } #endregion #region IVsSolutionEvents Implementation public int OnAfterOpenProject(IVsHierarchy aPHierarchy, int aFAdded) { CreateCacheRepository(); return VSConstants.S_OK; } public int OnQueryCloseProject(IVsHierarchy aPHierarchy, int aFRemoving, ref int aPfCancel) { DeleteTempSolution(); HideToolWindow(); DeleteCacheReporitory(); DeleteFromFindToolWindowHistory(); return VSConstants.S_OK; } public int OnBeforeCloseProject(IVsHierarchy aPHierarchy, int aFRemoved) { aPHierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out object projectObject); if (projectObject is Project project) mErrorWindowController.RemoveErrors(aPHierarchy); return VSConstants.S_OK; } public int OnAfterLoadProject(IVsHierarchy aPStubHierarchy, IVsHierarchy aPRealHierarchy) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnQueryUnloadProject(IVsHierarchy aPRealHierarchy, ref int aPfCancel) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnBeforeUnloadProject(IVsHierarchy aPRealHierarchy, IVsHierarchy aPStubHierarchy) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnAfterOpenSolution(object aPUnkReserved, int aFNewSolution) { CreateCacheRepository(); return VSConstants.S_OK; } public int OnQueryCloseSolution(object aPUnkReserved, ref int aPfCancel) { return VSConstants.S_OK; } public int OnBeforeCloseSolution(object aPUnkReserved) { DeleteTempSolution(); HideToolWindow(); return VSConstants.S_OK; } public int OnAfterCloseSolution(object aPUnkReserved) { return VSConstants.S_OK; } #endregion #region IVsSolutionLoadEvents implementation public int OnBeforeOpenSolution(string pszSolutionFilename) { CreateCacheRepository(); return VSConstants.S_OK; } public int OnBeforeBackgroundSolutionLoadBegins() { return VSConstants.S_OK; } public int OnQueryBackgroundLoadProjectBatch(out bool pfShouldDelayLoadToNextIdle) { pfShouldDelayLoadToNextIdle = false; return VSConstants.S_OK; } public int OnBeforeLoadProjectBatch(bool fIsBackgroundIdleBatch) { return VSConstants.S_OK; } public int OnAfterLoadProjectBatch(bool fIsBackgroundIdleBatch) { return VSConstants.S_OK; } public int OnAfterBackgroundSolutionLoadComplete() { return VSConstants.S_OK; } #endregion #region IVsSolution7 implementation public void OnAfterOpenFolder(string folderPath) { } public void OnBeforeCloseFolder(string folderPath) { } public void OnQueryCloseFolder(string folderPath, ref int pfCancel) { } public void OnAfterCloseFolder(string folderPath) { } public void OnAfterLoadAllDeferredProjects() { } #endregion #region Private Methods private void UpdateVersion(string version) { var generalSettingsModel = SettingsProvider.GeneralSettingsModel; string currentVersion = PackageUtility.GetVersion(); if (string.IsNullOrWhiteSpace(currentVersion) == false && 0 > string.Compare(version, currentVersion)) { generalSettingsModel.Version = currentVersion; var findToolWindowHandler = new FindToolWindowHandler(); findToolWindowHandler.SaveMatchersHistoryData(); var settingsHandler = new SettingsHandler(); settingsHandler.SaveSettings(); //var freeTrialController = new FreeTrialController(); //bool activeLicense = await new LocalLicenseValidator().ValidateAsync(); //if (activeLicense) // freeTrialController.MarkAsExpired(); ReleaseNotesView.WasShown = false; } } private void ShowToolbar(string version) { // Detect the first install if (!string.IsNullOrWhiteSpace(version)) return; // Show the toolbar on the first install if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var cbs = ((CommandBars)(dte as DTE2).CommandBars); CommandBar cb = cbs["Clang Power Tools"]; cb.Enabled = true; cb.Visible = true; } } private async Task RegisterVsServicesAsync() { // Get DTE service async var dte = await mPackage.GetServiceAsync(typeof(DTE)) as DTE2; VsServiceProvider.Register(typeof(DTE2), dte); // Get VS Output Window service async var vsOutputWindow = await mPackage.GetServiceAsync(typeof(SVsOutputWindow)); VsServiceProvider.Register(typeof(SVsOutputWindow), vsOutputWindow); // Get the status bar service async var vsStatusBar = await mPackage.GetServiceAsync(typeof(SVsStatusbar)); VsServiceProvider.Register(typeof(SVsStatusbar), vsStatusBar); // Get Vs Running Document Table service async var vsRunningDocumentTable = await mPackage.GetServiceAsync(typeof(SVsRunningDocumentTable)); VsServiceProvider.Register(typeof(SVsRunningDocumentTable), vsRunningDocumentTable); // Get Vs File Change service async var vsFileChange = await mPackage.GetServiceAsync(typeof(SVsFileChangeEx)); VsServiceProvider.Register(typeof(SVsFileChangeEx), vsFileChange); // Get VS Solution service async var vsSolution = await mPackage.GetServiceAsync(typeof(SVsSolution)); VsServiceProvider.Register(typeof(SVsSolution), vsSolution); } private async Task RegisterToEventsAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); RegisterToCPTEvents(); RegisterToVsEvents(); } private void RegisterToCPTEvents() { mCommandController.ClangCommandMessageEvent += PowerShellWrapper.mOutputWindowController.Write; mCommandController.ClearOutputWindowEvent += PowerShellWrapper.mOutputWindowController.ClearPanel; mCommandController.HierarchyDetectedEvent += PowerShellWrapper.mOutputWindowController.OnFileHierarchyDetected; mCommandController.HasEncodingErrorEvent += PowerShellWrapper.mOutputWindowController.OnEncodingErrorDetected; PowerShellWrapper.mOutputWindowController.HasEncodingErrorEvent += mCommandController.OnEncodingErrorDetected; mCommandController.ClearErrorListEvent += mErrorWindowController.OnClangCommandBegin; CompileCommand.Instance.HierarchyDetectedEvent += mCommandController.OnFileHierarchyChanged; TidyCommand.Instance.HierarchyDetectedEvent += mCommandController.OnFileHierarchyChanged; OptimizeIncludesCommand.Instance.HierarchyDetectedEvent += mCommandController.OnFileHierarchyChanged; mCommandController.ErrorDetectedEvent += PowerShellWrapper.mOutputWindowController.OnErrorDetected; PowerShellWrapper.mOutputWindowController.ErrorDetectedEvent += mErrorWindowController.OnErrorDetected; PowerShellWrapper.mOutputWindowController.JsonCompilationDbFilePathEvent += JsonCompilationDatabaseCommand.Instance.OpenInFileExplorer; RunController.CloseDataStreamingEvent += mCommandController.OnAfterRunCommand; FormatCommand.Instance.FormatEvent += mCommandController.OnAfterFormatCommand; CompileCommand.Instance.ActiveDocumentEvent += mCommandController.OnActiveDocumentCheck; TidyCommand.Instance.ActiveDocumentEvent += mCommandController.OnActiveDocumentCheck; OptimizeIncludesCommand.Instance.ActiveDocumentEvent += mCommandController.OnActiveDocumentCheck; CompileCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; TidyCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; OptimizeIncludesCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; FormatCommand.Instance.IgnoredItemsEvent += mCommandController.OnItemIgnore; PowerShellWrapper.DataHandler += PowerShellWrapper.mOutputWindowController.OutputDataReceived; PowerShellWrapper.DataErrorHandler += PowerShellWrapper.mOutputWindowController.OutputDataErrorReceived; PowerShellWrapper.ExitedHandler += PowerShellWrapper.mOutputWindowController.ClosedDataConnection; PowerShellWrapper.ExitedHandler += GenerateDocumentation.ClosedDataConnection; } private void RegisterToVsEvents() { if (null != mBuildEvents) { mBuildEvents.OnBuildBegin += mErrorWindowController.OnBuildBegin; mBuildEvents.OnBuildBegin += mCommandController.OnMSVCBuildBegin; mBuildEvents.OnBuildDone += mCommandController.OnMSVCBuildDone; } if (null != mCommandEvents) mCommandEvents.BeforeExecute += mCommandController.CommandEventsBeforeExecute; if (null != mRunningDocTableEvents) mRunningDocTableEvents.BeforeSave += mCommandController.OnBeforeSave; if (null != mDteEvents) mDteEvents.OnBeginShutdown += UnregisterFromEvents; if (windowEvents != null) windowEvents.WindowActivated += mCommandController.OnWindowActivated; } private void UnregisterFromEvents() { UnregisterFromCPTEvents(); UnregisterFromVsEvents(); } private void UnregisterFromCPTEvents() { mCommandController.ClangCommandMessageEvent -= PowerShellWrapper.mOutputWindowController.Write; mCommandController.ClearOutputWindowEvent -= PowerShellWrapper.mOutputWindowController.ClearPanel; mCommandController.HierarchyDetectedEvent -= PowerShellWrapper.mOutputWindowController.OnFileHierarchyDetected; mCommandController.HasEncodingErrorEvent -= PowerShellWrapper.mOutputWindowController.OnEncodingErrorDetected; PowerShellWrapper.mOutputWindowController.HasEncodingErrorEvent -= mCommandController.OnEncodingErrorDetected; mCommandController.ClearErrorListEvent -= mErrorWindowController.OnClangCommandBegin; CompileCommand.Instance.HierarchyDetectedEvent -= mCommandController.OnFileHierarchyChanged; TidyCommand.Instance.HierarchyDetectedEvent -= mCommandController.OnFileHierarchyChanged; OptimizeIncludesCommand.Instance.HierarchyDetectedEvent -= mCommandController.OnFileHierarchyChanged; mCommandController.ErrorDetectedEvent -= PowerShellWrapper.mOutputWindowController.OnErrorDetected; PowerShellWrapper.mOutputWindowController.ErrorDetectedEvent -= mErrorWindowController.OnErrorDetected; PowerShellWrapper.mOutputWindowController.JsonCompilationDbFilePathEvent -= JsonCompilationDatabaseCommand.Instance.OpenInFileExplorer; RunController.CloseDataStreamingEvent -= mCommandController.OnAfterRunCommand; FormatCommand.Instance.FormatEvent -= mCommandController.OnAfterFormatCommand; CompileCommand.Instance.ActiveDocumentEvent -= mCommandController.OnActiveDocumentCheck; TidyCommand.Instance.ActiveDocumentEvent -= mCommandController.OnActiveDocumentCheck; OptimizeIncludesCommand.Instance.ActiveDocumentEvent -= mCommandController.OnActiveDocumentCheck; CompileCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; TidyCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; OptimizeIncludesCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; FormatCommand.Instance.IgnoredItemsEvent -= mCommandController.OnItemIgnore; PowerShellWrapper.DataHandler -= PowerShellWrapper.mOutputWindowController.OutputDataReceived; PowerShellWrapper.DataErrorHandler -= PowerShellWrapper.mOutputWindowController.OutputDataErrorReceived; PowerShellWrapper.ExitedHandler -= PowerShellWrapper.mOutputWindowController.ClosedDataConnection; PowerShellWrapper.ExitedHandler -= GenerateDocumentation.ClosedDataConnection; } private void DeleteTempSolution() { var solutionPath = Path.Combine(TidyConstants.TempsFolderPath, TidyConstants.SolutionTempGuid); if (Directory.Exists(solutionPath)) { Directory.Delete(solutionPath, true); } } /// /// Hide Find Tool Window and Tidy Tool Window /// /// private int HideToolWindow() { PowerShellWrapper.EndInteractiveMode(); var tidyToolWindow = mPackage.FindToolWindow(typeof(TidyToolWindow), 0, false); if (tidyToolWindow is null) return VSConstants.S_OK; var tidyWindow = tidyToolWindow.Frame as IVsWindowFrame; tidyWindow?.Hide(); var findToolWindow = mPackage.FindToolWindow(typeof(FindToolWindow), 0, false); if (findToolWindow is null) return VSConstants.S_OK; var findWindow = findToolWindow.Frame as IVsWindowFrame; findWindow?.Hide(); return VSConstants.S_OK; } private void DeleteCacheReporitory() { //Delete cache repository; if (Directory.Exists(PathConstants.CacheRepositoryPath)) { Directory.Delete(PathConstants.CacheRepositoryPath, true); } } private void DeleteFromFindToolWindowHistory() { FindToolWindowProvider.RemoveFromFullList(); FindToolWindowHandler findToolWindowHandler = new FindToolWindowHandler(); findToolWindowHandler.SaveMatchersHistoryData(); } private void CreateCacheRepository() { //Create cache repository if (Directory.Exists(PathConstants.CacheRepositoryPath)) { DeleteCacheReporitory(); } Directory.CreateDirectory(PathConstants.CacheRepositoryPath); } private void UnregisterFromVsEvents() { if (null != mBuildEvents) { mBuildEvents.OnBuildBegin -= mErrorWindowController.OnBuildBegin; mBuildEvents.OnBuildBegin -= mCommandController.OnMSVCBuildBegin; mBuildEvents.OnBuildDone -= mCommandController.OnMSVCBuildDone; } if (null != mCommandEvents) mCommandEvents.BeforeExecute -= mCommandController.CommandEventsBeforeExecute; if (null != mRunningDocTableEvents) mRunningDocTableEvents.BeforeSave -= mCommandController.OnBeforeSave; if (null != mDteEvents) mDteEvents.OnBeginShutdown -= UnregisterFromEvents; if (windowEvents != null) windowEvents.WindowActivated -= mCommandController.OnWindowActivated; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/ClangPowerToolsShared.projitems ================================================  $(MSBuildAllProjects);$(MSBuildThisFileFullPath) true a0cea277-f6a1-4f62-862c-357c8c5654aa ClangPowerToolsShared FindToolWindowView.xaml FolderExplorerView.xaml TidyToolWindowView.xaml AboutSettingsView.xaml CMakeBetaWarning.xaml CompilerSettingsView.xaml BuyNowFooter.xaml InputList.xaml MessageBanner.xaml ThreePieceButton.xaml ThreePieceComponent.xaml EncodingErrorView.xaml FeedbackView.xaml FormatEditorWarning.xaml FormatSettingsView.xaml InputDataView.xaml LicenseView.xaml LlvmSettingsView.xaml LoginView.xaml ReleaseNotesView.xaml SearchBoxView.xaml SettingsView.xaml TidyChecksView.xaml TidySettingsView.xaml TrialExpiredView.xaml MSBuild:Compile Designer Designer MSBuild:Compile Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/ClangPowerToolsShared.projitems.bak ================================================  $(MSBuildAllProjects);$(MSBuildThisFileFullPath) true a0cea277-f6a1-4f62-862c-357c8c5654aa ClangPowerToolsShared FolderExplorerView.xaml TidyToolWindowView.xaml AccountView.xaml CMakeBetaWarning.xaml CompilerSettingsView.xaml BuyNowFooter.xaml InputList.xaml MessageBanner.xaml ThreePieceButton.xaml ThreePieceComponent.xaml EncodingErrorView.xaml FeedbackView.xaml FormatEditorWarning.xaml FormatSettingsView.xaml InputDataView.xaml LicenseView.xaml LlvmSettingsView.xaml LoginView.xaml ReleaseNotesView.xaml SearchBoxView.xaml SettingsView.xaml TeamSettingsView.xaml TidyChecksView.xaml TidySettingsView.xaml TrialExpiredView.xaml Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/ClangPowerToolsShared.shproj ================================================ a0cea277-f6a1-4f62-862c-357c8c5654aa 14.0 ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/BackgroundTidy/BackgroundTidy.cs ================================================ using ClangPowerTools.CMake; using ClangPowerTools.Helpers; using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; namespace ClangPowerTools.Commands.BackgroundTidy { public class BackgroundTidy : IDisposable { #region Members private readonly DataProcessor dataProcessor = new DataProcessor(); private readonly PowerShellWrapperBackground powerShell = new PowerShellWrapperBackground(); private readonly Dictionary mVsVersions = new Dictionary { {"11.0", "2010"}, {"12.0", "2012"}, {"13.0", "2013"}, {"14.0", "2015"}, {"15.0", "2017"}, {"16.0", "2019"}, {"17.0", "2022"} }; #endregion #region Constructor public BackgroundTidy() { powerShell.DataHandler += dataProcessor.ReceiveData; powerShell.DataErrorHandler += dataProcessor.ReceiveData; powerShell.ExitedHandler += dataProcessor.ClosedDataConnection; } public void Dispose() { powerShell.DataHandler -= dataProcessor.ReceiveData; powerShell.DataErrorHandler -= dataProcessor.ReceiveData; powerShell.ExitedHandler -= dataProcessor.ClosedDataConnection; } #endregion public void Run(Document document, int commandId) { try { #region Create currnet project item if (document == null || document.ProjectItem == null) return; var projectName = document.ProjectItem.ContainingProject.FullName; if (string.IsNullOrWhiteSpace(projectName)) return; IItem item = new CurrentProjectItem(document.ProjectItem); #endregion #region Get VS edition and version var dte = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); var vsEdition = dte.Edition; mVsVersions.TryGetValue(dte.Version, out string vsVersion); #endregion #region Generate powershell script string runModeParameters = ScriptGenerator.GetRunModeParamaters(); string genericParameters = ScriptGenerator.GetGenericParamaters(commandId, vsEdition, vsVersion, false); CMakeBuilder cMakeBuilder = new CMakeBuilder(); if (SolutionInfo.IsOpenFolderModeActive()) { cMakeBuilder.Build(); } var vsSolution = SolutionInfo.IsOpenFolderModeActive() == false ? (IVsSolution)VsServiceProvider.GetService(typeof(SVsSolution)) : null; var itemRelatedParameters = ScriptGenerator.GetItemRelatedParameters(item); var psScript = JoinUtility.Join(" ", runModeParameters.Remove(runModeParameters.Length - 1), itemRelatedParameters, genericParameters, "'"); #endregion #region PowerShell Invocation powerShell.Invoke(psScript, new RunningProcesses(true)); #endregion if (SolutionInfo.IsOpenFolderModeActive()) { cMakeBuilder.ClearBuildCashe(); } } catch (Exception) { //MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/BackgroundTidy/DataProcessor.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Error; using ClangPowerTools.Output; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; namespace ClangPowerTools.Commands.BackgroundTidy { public class DataProcessor { #region Members private readonly ErrorDetector errorDetector = new ErrorDetector(); private readonly OutputContentModel outputContent = new OutputContentModel(); private readonly int kBufferSize = 5; #endregion #region Methods #region Public methods public void ReceiveData(object sender, DataReceivedEventArgs e) { if (null == e.Data) return; if (outputContent.HasEncodingError) return; Process(e.Data); } public void ClosedDataConnection(object sender, EventArgs e) { if (outputContent.Errors.Count <= 0) return; TaskErrorViewModel.FileErrorsPair = new Dictionary>(); foreach (var error in outputContent.Errors) { if (TaskErrorViewModel.FileErrorsPair.ContainsKey(error.Document)) { TaskErrorViewModel.FileErrorsPair[error.Document] .Add(error); } else { TaskErrorViewModel.FileErrorsPair .Add(error.Document, new List() { error }); } } } #endregion #region Private Methods private void Process(string message) { outputContent.Buffer.Add(message); var text = String.Join("\n", outputContent.Buffer.ToList()) + "\n"; if (errorDetector.Detect(text, ErrorParserConstants.kErrorMessageRegex, out _)) { GetErrors(text, null, out List aDetectedErrors); outputContent.Errors.UnionWith(aDetectedErrors); outputContent.Buffer.Clear(); } else if (kBufferSize <= outputContent.Buffer.Count) { outputContent.Buffer.RemoveAt(0); } } private void GetErrors(string text, IVsHierarchy hierarchy, out List detectedErrors) { detectedErrors = new List(); while (errorDetector.Detect(text, ErrorParserConstants.kErrorMessageRegex, out Match aMatchResult)) { detectedErrors.Add(GetDetectedError(hierarchy, aMatchResult)); GetOutput(ref text, detectedErrors.Last().FullMessage); } } private void GetOutput(ref string aText, string aSearchedSubstring) { var errorFormatter = new ErrorFormatter(); aText = errorFormatter.Format(aText, aSearchedSubstring); aText = aText.SubstringAfter(aSearchedSubstring); } private TaskErrorModel GetDetectedError(IVsHierarchy aHierarchy, Match aMarchResult) { IBuilder errorBuilder = new TaskErrorModelBuilder(aHierarchy, aMarchResult); errorBuilder.Build(); return errorBuilder.GetResult(); } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/BackgroundTidy/PowerShellWrapperBackground.cs ================================================ using System; using System.Diagnostics; using System.Linq; namespace ClangPowerTools.Commands.BackgroundTidy { public class PowerShellWrapperBackground { #region Properties public DataReceivedEventHandler DataErrorHandler { get; set; } public DataReceivedEventHandler DataHandler { get; set; } public EventHandler ExitedHandler { get; set; } #endregion #region Public Methods public void Invoke(string script, RunningProcesses runningProcesses) { Process process = new Process(); try { process.StartInfo = new ProcessStartInfo() { FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}", RedirectStandardError = true, RedirectStandardOutput = true, CreateNoWindow = true, UseShellExecute = false, Arguments = script, }; process.StartInfo.EnvironmentVariables["Path"] = CreatePathEnvironmentVariable(); process.EnableRaisingEvents = true; process.ErrorDataReceived += DataErrorHandler; process.OutputDataReceived += DataHandler; process.Exited += ExitedHandler; process.Disposed += ExitedHandler; runningProcesses.Add(process); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); } catch (Exception e) { process.EnableRaisingEvents = false; process.ErrorDataReceived -= DataErrorHandler; process.OutputDataReceived -= DataHandler; process.Exited -= ExitedHandler; process.Disposed -= ExitedHandler; process.Close(); throw e; } } #endregion #region Private Methods private string CreatePathEnvironmentVariable() { var path = Environment.GetEnvironmentVariable("Path"); var llvmModel = SettingsProvider.LlvmSettingsModel; if (string.IsNullOrEmpty(llvmModel.LlvmSelectedVersion)) return path; var paths = path.Split(';').ToList(); paths.RemoveAt(paths.Count - 1); paths.RemoveAll(ContainsLlvm); if (string.IsNullOrWhiteSpace(llvmModel.PreinstalledLlvmPath) == false && llvmModel.LlvmSelectedVersion == llvmModel.PreinstalledLlvmVersion) { paths.Add(llvmModel.PreinstalledLlvmPath); } else { paths.Add(GetUsedLlvmVersionPath(llvmModel.LlvmSelectedVersion)); } return String.Join(";", paths); } private static string GetUsedLlvmVersionPath(string llvmVersion) { var settingsPathBuilder = new SettingsPathBuilder(); return settingsPathBuilder.GetLlvmBinPath(llvmVersion); } private static bool ContainsLlvm(string input) { return input.ToLower().Contains("llvm"); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/BasicCommand.cs ================================================ using System; using Microsoft.VisualStudio.Shell; namespace ClangPowerTools { public abstract class BasicCommand { #region Properties protected int Id { get; set; } protected Guid CommandSet { get; set; } protected AsyncPackage AsyncPackage { get; set; } protected Package Package => AsyncPackage; protected IAsyncServiceProvider AsyncServiceProvider => AsyncPackage; protected IServiceProvider ServiceProvider => Package; #endregion #region Constructor protected BasicCommand(AsyncPackage aPackage, Guid aGuid, int aId) { AsyncPackage = aPackage ?? throw new ArgumentNullException("AsyncPackage"); CommandSet = aGuid; Id = aId; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/ClangCommand.cs ================================================ using ClangPowerTools.CMake; using ClangPowerTools.Commands; using ClangPowerTools.Events; using ClangPowerTools.Helpers; using ClangPowerTools.IgnoreActions; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.Commands.Models; using ClangPowerToolsShared.Helpers; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { public abstract class ClangCommand : BasicCommand { #region Members //public static RunningProcesses runningProcesses = new RunningProcesses(); private CacheProjectsItemsModel cacheProjectsItemsModel = new CacheProjectsItemsModel(); protected ItemsCollector mItemsCollector; protected FilePathCollector mFilePahtCollector; private readonly Dictionary mVsVersions = new Dictionary { {"11.0", "2010"}, {"12.0", "2012"}, {"13.0", "2013"}, {"14.0", "2015"}, {"15.0", "2017"}, {"16.0", "2019"}, {"17.0", "2022"}, {"18.0", "2026"} }; private IVsHierarchy mHierarchy; // private object public event EventHandler HierarchyDetectedEvent; public event EventHandler ActiveDocumentEvent; public event EventHandler IgnoredItemsEvent; protected static object mutex = new object(); #endregion #region Properties public string Script { get; private set; } protected string VsEdition { get; set; } protected string VsVersion { get; set; } protected string WorkingDirectoryPath { get; set; } public List DirectoryPaths { get; set; } = new List(); protected IVsHierarchy ItemHierarchy { get => mHierarchy; set { if (null == value) return; mHierarchy = value; OnFileHierarchyChanged(new VsHierarchyDetectedEventArgs(mHierarchy)); } } #endregion #region Constructor public ClangCommand(AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var dte2 = dte as DTE2; VsEdition = dte2.Edition; mVsVersions.TryGetValue(dte2.Version, out string version); VsVersion = version; } } #endregion #region Protected Methods protected void CacheProjectsFromItems() { cacheProjectsItemsModel.Projects.Clear(); cacheProjectsItemsModel.ProjectItems.Clear(); foreach (var item in mItemsCollector.Items) { if (item.GetObject() is Project) { var project = item.GetObject() as Project; cacheProjectsItemsModel.Projects.Add(project); } else if (item.GetObject() is ProjectItem) { var projectItem = item.GetObject() as ProjectItem; cacheProjectsItemsModel.ProjectItems.Add(projectItem); } } } protected void RunScript(int aCommandId, bool jsonCompilationDbActive, List paths = null) { string runModeParameters = ScriptGenerator.GetRunModeParamaters(); string genericParameters = ScriptGenerator.GetGenericParamaters(aCommandId, VsEdition, VsVersion, jsonCompilationDbActive); CMakeBuilder cMakeBuilder = new CMakeBuilder(); if (SolutionInfo.IsOpenFolderModeActive()) { cMakeBuilder.Build(); } if (jsonCompilationDbActive) ExportJsonCompilationDatabase(runModeParameters, genericParameters); else Compile(runModeParameters, genericParameters, aCommandId, paths); if (SolutionInfo.IsOpenFolderModeActive()) { cMakeBuilder.ClearBuildCashe(); } } //Collect files protected void CollectItemsDependingOnCommandLocation( CommandUILocation commandUILocation = CommandUILocation.ContextMenu, bool jsonCompilationDbActive = false) { mItemsCollector = new ItemsCollector(jsonCompilationDbActive); switch (commandUILocation) { case CommandUILocation.Toolbar: mItemsCollector.CollectActiveProjectItem(); SetActiveDocumentEvent(); break; case CommandUILocation.ContextMenu: mItemsCollector.CollectSelectedItems(); break; case CommandUILocation.ViewMenu: mItemsCollector.CollectProjectItems(); break; } } private void SetActiveDocumentEvent() { if (mItemsCollector.Items.Count == 0) { OnActiveFileCheck(new ActiveDocumentEventArgs(false)); } else { OnActiveFileCheck(new ActiveDocumentEventArgs(true)); } } protected async Task PrepareCommmandAsync(CommandUILocation commandUILocation, bool jsonCompilationDbActive = false) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); DocumentHandler.SaveActiveDocuments(); if (!VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) return; AutomationUtil.SaveDirtyProjects((dte as DTE2).Solution); CollectItemsDependingOnCommandLocation(commandUILocation, jsonCompilationDbActive); } protected void OnActiveFileCheck(ActiveDocumentEventArgs e) { ActiveDocumentEvent?.Invoke(this, e); } protected void OnFileHierarchyChanged(VsHierarchyDetectedEventArgs e) { HierarchyDetectedEvent?.Invoke(this, e); } protected void OnIgnoreItem(ClangCommandMessageEventArgs e) { IgnoredItemsEvent?.Invoke(this, e); } #endregion #region Private Methods protected void InvokeFindCommand(FindToolWindow findToolWindow) { if (findToolWindow != null) findToolWindow.RunQuery(); if (RunController.StopCommandActivated) { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(true)); RunController.StopCommandActivated = false; } else { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(false)); } } /// /// Use include-what-to-use tool to remove includes. /// Download all needed tools: iwyu.exe, iwyu_tool.py, fix_includes.py. /// Use iwyu_tool.py to generate output in iwyuUTF8.txt and apply fix with fix_includes.py /// protected void OptimizeIncludes() { if (string.IsNullOrEmpty(PathConstants.JsonCompilationDBPath)) { CommandControllerInstance.CommandController.DisplayMessage(false, "Cannot find compilation database"); return; } string jsonCompilationDatabasePath = Path.Combine(PathConstants.SolutionDirPath, "iwyu_compilation_db.json"); ManageEncoding.ChangeEncodingFromBomToUtf8(PathConstants.JsonCompilationDBPath, jsonCompilationDatabasePath); string iwyuUTF8BOMPath = Path.Combine(new FileInfo(jsonCompilationDatabasePath).Directory.FullName, "iwyuUTF8BOM.txt"); string iwyuUTF8Path = Path.Combine(new FileInfo(jsonCompilationDatabasePath).Directory.FullName, "iwyuUTF8.txt"); try { //downlaod tools string iwyuTool = Path.Combine(PowerShellWrapper.DownloadTool(ScriptConstants.kIwyuTool), ScriptConstants.kIwyuTool); var pythonPath = PowerShellWrapper.GetFilePathFromEnviromentVar("python.exe"); if (string.IsNullOrEmpty(pythonPath)) { CommandControllerInstance.CommandController.DisplayMessage(false, "To use optimize includes you must add in PATH python 3.x"); return; } string Script = $"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command \"& " + $"cmd.exe /c python.exe " + $" '{iwyuTool}' -v -p '{jsonCompilationDatabasePath}' " + $"--j {PowerShellWrapper.GetNumberOfProcessors()} > '{iwyuUTF8BOMPath}' \""; //generate iwyu output in iwyuOutput.txt PowerShellWrapper.StartProcess(Script); //change encoding from utf8 BOM to utf8 ManageEncoding.ChangeEncodingFromBomToUtf8(iwyuUTF8BOMPath ,iwyuUTF8Path); //apply fixes based on generated iwyuOutput.txt (encoding utf-8) file string iwyuFixIncludes = Path.Combine(PowerShellWrapper.DownloadTool(ScriptConstants.kIwyuFixIncludes), ScriptConstants.kIwyuFixIncludes); string includeFixScript = $"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command \"& " + $"cmd.exe /c python.exe '{iwyuFixIncludes}' " + $" '<' '{iwyuUTF8Path}' \""; PowerShellWrapper.StartProcess(includeFixScript); } catch (Exception e) { CommandControllerInstance.CommandController.DisplayMessage(false, e.Message); } finally { //Remove files FileSystem.DeleteFile(iwyuUTF8Path); FileSystem.DeleteFile(iwyuUTF8BOMPath); FileSystem.DeleteFile(jsonCompilationDatabasePath); } if (RunController.StopCommandActivated) { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(true)); RunController.StopCommandActivated = false; } else { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(false)); } } /// /// Create a process for running clang-doc.exe resulted /// format, depends on passed command /// /// /// /// /// protected void GenerateDocumentationForProject(int commandId, AsyncPackage package) { var jsonCompilationDatabasePath = PathConstants.JsonCompilationDBPath; string documentationOutoutePath = GenerateDocumentation.FindOutputFolderName( Path.Combine(new FileInfo(jsonCompilationDatabasePath).Directory.FullName, "Documentation\\")); string clangDocPath = PowerShellWrapper.DownloadTool(ScriptConstants.kClangDoc); clangDocPath = Path.Combine(clangDocPath, ScriptConstants.kClangDoc); if (File.Exists(jsonCompilationDatabasePath) && File.Exists(clangDocPath)) { string projectArguments = GetProjectName() == string.Empty ? string.Empty : $"--project-name='{GetProjectName()}'"; GenerateDocumentation.OutputDir = documentationOutoutePath; CommandControllerInstance.CommandController.DisplayMessage(false, "Please wait ..."); string Script = $"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command \"& " + $"'{clangDocPath}' --public {projectArguments} --format={GenerateDocumentation.Formats[commandId]} " + $"-output='{documentationOutoutePath}' '{jsonCompilationDatabasePath}' \""; PowerShellWrapper.Invoke(Script); //Replace a string in index_json.js if is generated with html format, to avoid a json error string indexJsonFileName = Path.Combine(documentationOutoutePath, "index_json.js"); if (File.Exists(indexJsonFileName) && commandId == CommandIds.kDocumentationHtmlId) { string indexJsonFileContent = File.ReadAllText(indexJsonFileName); indexJsonFileContent = indexJsonFileContent.Replace("var JsonIndex = `", "var JsonIndex = String.raw `"); File.WriteAllText(indexJsonFileName, indexJsonFileContent); } DeleteJsonCompilationDB(); if (RunController.StopCommandActivated) { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(true)); RunController.StopCommandActivated = false; } else { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(false)); } } } private void DeleteJsonCompilationDB() { var jsonCompilationDatabasePath = PathConstants.JsonCompilationDBPath; if (File.Exists(jsonCompilationDatabasePath)) File.Delete(jsonCompilationDatabasePath); } private void Compile(string runModeParameters, string genericParameters, int commandId, List paths) { var vsSolution = SolutionInfo.IsOpenFolderModeActive() == false ? (IVsSolution)VsServiceProvider.GetService(typeof(SVsSolution)) : null; try { var tempClangTidyFilePath = string.Empty; if (paths is not null) { var itemRelatedParameters = ScriptGenerator.GetItemRelatedParametersCustomPaths(paths, cacheProjectsItemsModel); Script = JoinUtility.Join(" ", runModeParameters, itemRelatedParameters, genericParameters, "\""); } else { var item = mItemsCollector.Items[0]; var ignoreItem = new IgnoreItem(); //TODO Display all ignored files //if (ignoreItem.Check(item)) //{ // OnIgnoreItem(new ClangCommandMessageEventArgs(ignoreItem.IgnoreCompileOrTidyMessage, false)); //} //TODO Handle CreateTemporaryFileForTidy if (commandId == CommandIds.kTidyId || commandId == CommandIds.kTidyFixId || CommandIds.kTidyToolWindowId == commandId || commandId == CommandIds.kTidyToolbarId || commandId == CommandIds.kTidyFixToolbarId) { tempClangTidyFilePath = CreateTemporaryFileForTidy(item); } var itemRelatedParameters = string.Empty; if (item is CurrentProject || item is Project || item is Solution) { itemRelatedParameters = ScriptGenerator.GetProjectRelatedParameters(cacheProjectsItemsModel); } else if (item is CurrentProjectItem || item is ProjectItem) { itemRelatedParameters = ScriptGenerator.GetItemRelatedParameters(mItemsCollector.Items); } // From the first parameter is removed the last character which is mandatory "'" // and added to the end of the string to close the script escaping command Script = JoinUtility.Join(" ", runModeParameters, itemRelatedParameters, genericParameters, "\""); ItemHierarchy = vsSolution != null ? AutomationUtil.GetItemHierarchy(vsSolution, item) : null; } PowerShellWrapper.Invoke(Script); if (RunController.StopCommandActivated) { RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(true)); RunController.StopCommandActivated = false; } else { if (File.Exists(tempClangTidyFilePath)) { File.Delete(tempClangTidyFilePath); } RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(false)); } } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private string CreateTemporaryFileForTidy(IItem item) { var directoryPath = Directory.GetParent(item.GetPath()).FullName; StopCommand.Instance.DirectoryPaths.Add(directoryPath); var clangTidyFilePath = Path.Combine(directoryPath, ScriptConstants.kTidyFile); if (File.Exists(clangTidyFilePath)) { var settingsPathBuilder = new SettingsPathBuilder(); var settingsPath = settingsPathBuilder.GetPath(""); var tempClangTidyFilePath = Path.Combine(settingsPath, ScriptConstants.kTidyFile); File.Copy(clangTidyFilePath, tempClangTidyFilePath, true); return tempClangTidyFilePath; } return string.Empty; } private void ExportJsonCompilationDatabase(string runModeParameters, string genericParameters) { if (mItemsCollector.IsEmpty) return; var item = mItemsCollector.Items[0]; if (item is CurrentSolution) Script = JoinUtility.Join(" ", runModeParameters, genericParameters, "\""); else if (item is CurrentProject) { var itemRelatedParameters = ScriptGenerator.GetItemRelatedParameters(item, true); Script = JoinUtility.Join(" ", runModeParameters, itemRelatedParameters, genericParameters, "\""); } else if (item is CurrentProjectItem) { var itemRelatedParameters = mItemsCollector.Items.Count == 1 ? ScriptGenerator.GetItemRelatedParameters(item, true) : ScriptGenerator.GetItemRelatedParameters(mItemsCollector.Items, true); Script = JoinUtility.Join(" ", runModeParameters, itemRelatedParameters, genericParameters, "\""); } PowerShellWrapper.Invoke(Script); } private string GetProjectName() { string projectName = string.Empty; try { if (cacheProjectsItemsModel.Projects.Count > 0) { projectName = cacheProjectsItemsModel.Projects[0].FullName; } else { projectName = cacheProjectsItemsModel.ProjectItems[0].ContainingProject.FullName; } } catch (NullReferenceException e) { } return projectName; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/CommandController.cs ================================================ using ClangPowerTools.CMake; using ClangPowerTools.Commands; using ClangPowerTools.Commands.BackgroundTidy; using ClangPowerTools.Error; using ClangPowerTools.Events; using ClangPowerTools.Handlers; using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Views; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.Helpers; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { /// /// Contains all the logic of disable and enable the clang custom commands /// public class CommandController { #region Members public bool running = false; public bool vsBuildRunning = false; public bool tokenExists = false; public bool clearOutputOnFormat = false; public bool keepJsonCompilationDb = false; public bool showOpenFolderWarning = true; public static readonly Guid mCommandSet = new Guid("498fdff5-5217-4da9-88d2-edad44ba3874"); public event EventHandler HierarchyDetectedEvent; public event EventHandler ClangCommandMessageEvent; public event EventHandler ClearErrorListEvent; public event EventHandler ClearOutputWindowEvent; public event EventHandler ErrorDetectedEvent; public event EventHandler HasEncodingErrorEvent; private bool mFormatted = false; private readonly Commands2 mCommand; private CommandUILocation commandUILocation; private int currentCommand = 0; private bool mSaveCommandWasGiven = false; private bool mFormatAfterTidyFlag = false; private string oldActiveDocumentName = null; private AsyncPackage package; private LaunchCompilationDbProgrammatically launchCompilationDbProgrammatically = new(); public AsyncPackage Package { get { return package; } } private readonly object mutex = new object(); private readonly string registryName = @"Software\Caphyon\Clang Power Tools"; private readonly string keyName = "CMakeBetaWarning"; #endregion #region Constructor public CommandController(AsyncPackage aAsyncPackage) { package = aAsyncPackage; if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var dte2 = (DTE2)dte; mCommand = (Commands2)dte2.Commands; } } #endregion #region Public Methods public async Task InitializeCommandsAsync(AsyncPackage aAsyncPackage) { if (CompileCommand.Instance == null) { await CompileCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kCompileId); await CompileCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kCompileToolbarId); } if (TidyCommand.Instance == null) { await TidyCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kTidyId); await TidyCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kTidyToolbarId); } if (FormatCommand.Instance == null) { await FormatCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kClangFormat); await FormatCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kClangFormatToolbarId); } if (FindCommand.Instance == null) { await FindCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kClangFind); } if (OptimizeIncludesCommand.Instance == null) { await OptimizeIncludesCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kOptimizeIncludesId); } if (IgnoreFormatCommand.Instance == null) { await IgnoreFormatCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kIgnoreFormatId); } if (IgnoreCompileCommand.Instance == null) { await IgnoreCompileCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kIgnoreCompileId); } if (StopCommand.Instance == null) { await StopCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kStopClang); } if (JsonCompilationDatabaseCommand.Instance == null) { await JsonCompilationDatabaseCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kJsonCompilationDatabase); } if (DocumentationYamlCommand.Instance == null) { await DocumentationYamlCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kDocumentationYamlId); } if (DocumentationHtmlCommand.Instance == null) { await DocumentationHtmlCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kDocumentationHtmlId); } if (DocumentationMdCommand.Instance == null) { await DocumentationMdCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kDocumentationMdId); } if (SettingsCommand.Instance == null) { await SettingsCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kSettingsId); } if (FindViewMenuCommand.Instance == null) { await FindViewMenuCommand.InitializeAsync(this, aAsyncPackage, mCommandSet, CommandIds.kFindViewMenuId); } } public async void Execute(object sender, EventArgs e) { var command = CreateCommand(sender); if (command == null) return; await LaunchCommandAsync(command.CommandID.ID, commandUILocation); } public int GetCurrentCommandId() { return currentCommand; } public async Task LaunchCommandAsync(int aCommandId, CommandUILocation aCommandUILocation, List paths = null, bool openCompilationDatabaseInExplorer = true) { // If ApplyTidy-Fix is enabled, switch command ChooseCommandIdDependingOnTidy(ref aCommandId); switch (aCommandId) { case CommandIds.kFindViewMenuId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kFindViewMenuId); await FindViewMenuCommand.Instance.FindAsync(aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kSettingsId: { await SettingsCommand.Instance.ShowSettingsAsync(); break; } case CommandIds.kStopClang: { await StopCommand.Instance.RunStopClangCommandAsync(false); break; } case CommandIds.kClangFormat: { clearOutputOnFormat = true; FormatCommand.Instance.RunClangFormat(aCommandUILocation); break; } case CommandIds.kClangFormatToolbarId: { clearOutputOnFormat = true; FormatCommand.Instance.RunClangFormat(aCommandUILocation); break; } case CommandIds.kClangFind: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kClangFind); await FindCommand.Instance.FindAsync(aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kClangFindRun: { await launchCompilationDbProgrammatically.FromFindToolWindowAsync(); OnBeforeClangCommand(CommandIds.kClangFindRun); await FindCommand.Instance.RunQueryAsync(); OnAfterClangCommand(); break; } case CommandIds.kOptimizeIncludesId: { //generate compilation database here, before setting the CommandId with OptimizeIncludesId await launchCompilationDbProgrammatically.FromOptimizeIncludesAsync(); await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kOptimizeIncludesId); await OptimizeIncludesCommand.Instance.RunOptimizeIncludes(aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kCompileId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kCompileId); await CompileCommand.Instance.RunClangCompileAsync(CommandIds.kCompileId, aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kCompileToolbarId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kCompileId); await CompileCommand.Instance.RunClangCompileAsync(CommandIds.kCompileId, aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kTidyId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kTidyId); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyId, aCommandUILocation); await TidyCommand.Instance.ShowTidyToolWindowEmptyAsync(); OnAfterClangCommand(); break; } case CommandIds.kTidyToolbarId: { await StopBackgroundRunnersAsync(); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyId, aCommandUILocation); await TidyCommand.Instance.ShowTidyToolWindowEmptyAsync(); break; } case CommandIds.kTidyToolWindowId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kTidyToolWindowId); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyToolWindowId, aCommandUILocation, paths); OnAfterClangCommand(); break; } case CommandIds.kTidyToolWindowFilesId: { OnAfterClangCommand(); await StopBackgroundRunnersAsync(); await TidyCommand.Instance.ShowTidyToolWindowAsync(paths); OnAfterClangCommand(); break; } case CommandIds.kTidyFixId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kTidyFixId); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyFixId, aCommandUILocation, paths); OnAfterClangCommand(); break; } case CommandIds.kTidyFixToolbarId: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kTidyFixId); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyFixId, aCommandUILocation); OnAfterClangCommand(); break; } case CommandIds.kIgnoreFormatId: { IgnoreFormatCommand.Instance.RunIgnoreFormatCommand(); break; } case CommandIds.kIgnoreCompileId: { IgnoreCompileCommand.Instance.RunIgnoreCompileCommand(); break; } case CommandIds.kDocumentationYamlId: { await launchCompilationDbProgrammatically.FromGenerateDocumentationAsync(); await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kDocumentationYamlId); await DocumentationYamlCommand.Instance.GenerateDocumentationAsync( CommandIds.kDocumentationYamlId); OnAfterClangCommand(); break; } case CommandIds.kDocumentationMdId: { await launchCompilationDbProgrammatically.FromGenerateDocumentationAsync(); await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kDocumentationMdId); await DocumentationMdCommand.Instance.GenerateDocumentationAsync( CommandIds.kDocumentationMdId); OnAfterClangCommand(); break; } case CommandIds.kDocumentationHtmlId: { await launchCompilationDbProgrammatically.FromGenerateDocumentationAsync(); await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kDocumentationHtmlId); await DocumentationHtmlCommand.Instance.GenerateDocumentationAsync( CommandIds.kDocumentationHtmlId); OnAfterClangCommand(); break; } case CommandIds.kJsonCompilationDatabase: { await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kJsonCompilationDatabase); await JsonCompilationDatabaseCommand.Instance.ExportAsync( aCommandUILocation, openCompilationDatabaseInExplorer); OnAfterClangCommand(); break; } default: break; } } #endregion #region Private Methods /// /// Return commandId depending on tidy settings /// /// /// private void ChooseCommandIdDependingOnTidy(ref int aCommandId) { var tidySettings = SettingsProvider.TidySettingsModel; if (aCommandId == CommandIds.kTidyToolbarId && tidySettings.ApplyTidyFix) { aCommandId = CommandIds.kTidyFixToolbarId; } if (aCommandId == CommandIds.kTidyId && tidySettings.ApplyTidyFix) { aCommandId = CommandIds.kTidyFixId; } } private OleMenuCommand CreateCommand(object sender) { if ((sender is OleMenuCommand) == false) return null; OleMenuCommand command = sender as OleMenuCommand; if (running && command.CommandID.ID != CommandIds.kStopClang) return null; if (command.CommandID.ID != CommandIds.kStopClang) currentCommand = command.CommandID.ID; SetCommandLocation(); return command; } private void SetCommandLocation() { switch (currentCommand) { case CommandIds.kClangFormatToolbarId: case CommandIds.kCompileToolbarId: case CommandIds.kTidyToolbarId: case CommandIds.kTidyFixToolbarId: commandUILocation = CommandUILocation.Toolbar; break; case CommandIds.kFindViewMenuId: commandUILocation = CommandUILocation.ViewMenu; break; default: commandUILocation = CommandUILocation.ContextMenu; break; } } private async Task StopBackgroundRunnersAsync() { await StopCommand.Instance.RunStopClangCommandAsync(true); } private void StopBackgroundRunners() { StopCommand.Instance.StopClangCommand(true); } private void OnBeforeClangCommand(int aCommandId) { currentCommand = aCommandId; running = true; OnClangCommandBegin(new ClearEventArgs()); if (OutputWindowConstants.commandName.ContainsKey(aCommandId)) DisplayStartedMessage(aCommandId, true); } private void OnClangCommandBegin(ClearEventArgs e) { ClearErrorListEvent?.Invoke(this, e); } private void OnAfterClangCommand() { running = false; var cMakeBuilder = new CMakeBuilder(); cMakeBuilder.ClearBuildCashe(); } public void OnAfterFormatCommand(object sender, FormatCommandEventArgs e) { if (e.FormatConfigFound == false) { DisplayMessage( e.Clear, $"\n--- ERROR ---\nFormat config file not found.\nCreate the config file and place it in the solution folder or select one of the predefined format styles from Clang Power Tools settings -> Format -> Style."); } else if (e.Clear) { ClearOutputWindowEvent?.Invoke(this, new ClearEventArgs()); } } public void OnAfterRunCommand(object sender, CloseDataStreamingEventArgs e) { if (e.IsStopped) { DisplayStoppedMessage(false); running = false; return; } DisplayFinishedMessage(false); if (currentCommand != CommandIds.kJsonCompilationDatabase) OnErrorDetected(new EventArgs()); } protected void OnErrorDetected(EventArgs e) { ErrorDetectedEvent?.Invoke(this, e); HasEncodingErrorEvent?.Invoke(this, new EventArgs()); } public void OnEncodingErrorDetected(object sender, HasEncodingErrorEventArgs e) { if (!e.Model.HasEncodingError) { return; } DisplayErrorWindow(); } private void DisplayErrorWindow() { try { UIUpdater .InvokeAsync(new Action(() => { var itemsCollector = new ItemsCollector(); var window = new EncodingErrorView(itemsCollector.GetDocumentsToEncode()); window.ShowDialog(); })) .SafeFireAndForget(); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } public void OnActiveDocumentCheck(object sender, ActiveDocumentEventArgs e) { if (e.IsActiveDocument == false) { DisplayNoActiveDocumentMessage(true); } } private void OnClangCommandMessageTransfer(ClangCommandMessageEventArgs e) { ClangCommandMessageEvent?.Invoke(this, e); } public void OnFileHierarchyChanged(object sender, VsHierarchyDetectedEventArgs e) { HierarchyDetectedEvent?.Invoke(this, e); } private void DisplayStartedMessage(int aCommandId, bool clearOutput) { OnClangCommandMessageTransfer(new ClangCommandMessageEventArgs( $"\n--- {OutputWindowConstants.commandName[aCommandId].ToUpper()} STARTED ---\n", clearOutput)); StatusBarHandler.Status(OutputWindowConstants.commandName[aCommandId] + " started...", 1, vsStatusAnimation.vsStatusAnimationBuild, 1); } private void DisplayNoActiveDocumentMessage(bool clearOutput) { OnClangCommandMessageTransfer(new ClangCommandMessageEventArgs( $"\nToolbar Clang commands can only run on open files. Open a file or use the context menu commands by right-clicking in the Solution Explorer.\n", clearOutput)); StatusBarHandler.Status("Ready", 0, vsStatusAnimation.vsStatusAnimationBuild, 0); } private void DisplayFinishedMessage(bool clearOutput) { OnClangCommandMessageTransfer(new ClangCommandMessageEventArgs( $"\n--- {OutputWindowConstants.commandName[currentCommand].ToUpper()} FINISHED ---\n", clearOutput)); StatusBarHandler.Status(OutputWindowConstants.commandName[currentCommand] + " finished", 0, vsStatusAnimation.vsStatusAnimationBuild, 0); } private void DisplayStoppedMessage(bool clearOutput) { OnClangCommandMessageTransfer(new ClangCommandMessageEventArgs( $"\n--- {OutputWindowConstants.commandName[currentCommand].ToUpper()} STOPPED ---", clearOutput)); StatusBarHandler.Status("Command stopped", 0, vsStatusAnimation.vsStatusAnimationBuild, 0); } public void DisplayMessage(bool clearOutput = false, string message = "") { OnClangCommandMessageTransfer(new ClangCommandMessageEventArgs(message, clearOutput)); StatusBarHandler.Status("Command stopped", 0, vsStatusAnimation.vsStatusAnimationBuild, 0); } private string GetCommandName(string aGuid, int aId) { try { if (null == aGuid) return string.Empty; if (null == mCommand) return string.Empty; Command cmd = mCommand.Item(aGuid, aId); if (null == cmd) return string.Empty; return cmd.Name; } catch (Exception) { // MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return string.Empty; } #endregion #region Events internal void OnItemIgnore(object sender, ClangCommandMessageEventArgs e) { ClangCommandMessageEvent?.Invoke(this, e); } public void VisibilityOnBeforeCommand(object sender, EventArgs e) { if (sender is OleMenuCommand == false) return; var command = (OleMenuCommand)sender; var itemsCollector = new ItemsCollector(); itemsCollector.CollectSelectedProjectItems(); if (itemsCollector.Items != null && itemsCollector.Items.Count == 1 && (command.CommandID.ID == CommandIds.kIgnoreCompileId) && ScriptConstants.kAcceptedFileExtensionsWithoutHeaders.Contains( Path.GetExtension(itemsCollector.Items[0].GetName())) == false) { command.Visible = command.Enabled = false; } else { command.Enabled = !itemsCollector.IsEmpty; } } /// /// It is called before every command. Update the running state. /// /// /// public void OnBeforeClangCommand(object sender, EventArgs e) { if (!(sender is OleMenuCommand command)) return; var itemsCollector = new ItemsCollector(); itemsCollector.CollectSelectedProjectItems(); var tidySettings = SettingsProvider.TidySettingsModel; // Change button name for tidy depending on settings property if (tidySettings.ApplyTidyFix && (command.CommandID.ID == CommandIds.kTidyId || command.CommandID.ID == CommandIds.kTidyToolbarId)) { command.Text = "Tidy-Fix"; } else if (command.CommandID.ID == CommandIds.kTidyId || command.CommandID.ID == CommandIds.kTidyToolbarId) { command.Text = "Tidy"; } if (IsAToolbarCommand(command)) { if (SolutionInfo.AreToolbarCommandsEnabled() == false) { command.Enabled = command.CommandID.ID == CommandIds.kClangFormatToolbarId && SolutionInfo.ActiveDocumentValidation(); return; } } else if (SolutionInfo.AreContextMenuCommandsEnabled() == false) { command.Enabled = false; return; } if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte) && !(dte as DTE2).Solution.IsOpen) { command.Visible = command.Enabled = false; } else if (itemsCollector.Items != null && itemsCollector.Items.Count == 1 && (command.CommandID.ID == CommandIds.kCompileId || command.CommandID.ID == CommandIds.kTidyId || command.CommandID.ID == CommandIds.kOptimizeIncludesId || command.CommandID.ID == CommandIds.kJsonCompilationDatabase || command.CommandID.ID == CommandIds.kClangFindRun || command.CommandID.ID == CommandIds.kIgnoreCompileId || command.CommandID.ID == CommandIds.kDocumentationMdId || command.CommandID.ID == CommandIds.kDocumentationHtmlId || command.CommandID.ID == CommandIds.kDocumentationYamlId || command.CommandID.ID == CommandIds.kClangFind) && ScriptConstants.kAcceptedFileExtensionsWithoutHeaders.Contains( Path.GetExtension(itemsCollector.Items[0].GetName())) == false) { command.Visible = command.Enabled = false; return; } else if (vsBuildRunning && command.CommandID.ID != CommandIds.kSettingsId) { command.Visible = command.Enabled = false; } else { command.Visible = command.Enabled = command.CommandID.ID != CommandIds.kStopClang ? !running : running; } } /// /// Set the VS running build flag to true when the VS build begin. /// /// /// public void OnMSVCBuildBegin(vsBuildScope Scope, vsBuildAction Action) { vsBuildRunning = true; } /// /// Set the VS running build flag to false when the VS build finished. /// /// /// public void OnMSVCBuildDone(vsBuildScope Scope, vsBuildAction Action) { vsBuildRunning = false; OnMSVCBuildSucceededAsync().SafeFireAndForget(); } private async Task OnMSVCBuildSucceededAsync() { if (SettingsProvider.CompilerSettingsModel.ClangAfterMSVC == false || SolutionInfo.ContainsCppProject() == false) return; var exitCode = int.MaxValue; if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) exitCode = (dte as DTE2).Solution.SolutionBuild.LastBuildInfo; // VS compile detected errors and there is not necessary to run clang compile if (exitCode != 0) { return; } // Run clang compile after the VS compile succeeded OnBeforeClangCommand(CommandIds.kCompileId); await CompileCommand.Instance.RunClangCompileAsync(CommandIds.kCompileId, CommandUILocation.ContextMenu); OnAfterClangCommand(); } private int HideFindToolWindow() { var findToolWindow = package.FindToolWindow(typeof(FindToolWindow), 0, false); if (findToolWindow is null) return VSConstants.S_OK; var findWindow = findToolWindow.Frame as IVsWindowFrame; findWindow?.Hide(); return VSConstants.S_OK; } private int HideTidyToolWindow() { var tidyToolWindow = package.FindToolWindow(typeof(TidyToolWindow), 0, false); if (tidyToolWindow is null) return VSConstants.S_OK; var tidyWindow = tidyToolWindow.Frame as IVsWindowFrame; tidyWindow?.Hide(); return VSConstants.S_OK; } public void OnBeforeSave(object sender, Document aDocument) { StopBackgroundRunners(); BeforeSaveClangTidyAsync(aDocument).SafeFireAndForget(); BeforeSaveClangFormat(aDocument); } private async Task BeforeSaveClangTidyAsync(Document document) { // OnBeforeActiveDocumentChange(new object(), document); // The save event was not triggered by Save File or SaveAll commands if (false == mSaveCommandWasGiven) return; var tidySettings = SettingsProvider.TidySettingsModel; // The clang-tidy on save option is disable if (false == tidySettings.TidyOnSave) return; // Clang compile/tidy command is running if (true == running) return; await StopBackgroundRunnersAsync(); OnBeforeClangCommand(CommandIds.kTidyFixId); await TidyCommand.Instance.RunClangTidyAsync(CommandIds.kTidyFixId, CommandUILocation.ContextMenu); OnAfterClangCommand(); mSaveCommandWasGiven = false; } private void BeforeSaveClangFormat(Document aDocument) { var formatSettings = SettingsProvider.FormatSettingsModel; var tidySettings = SettingsProvider.TidySettingsModel; if (currentCommand == CommandIds.kTidyFixId && running && tidySettings.FormatAfterTidy && formatSettings.FormatOnSave) { mFormatAfterTidyFlag = true; return; } if (false == formatSettings.FormatOnSave) return; if (currentCommand == CommandIds.kTidyFixId && false == Vsix.IsDocumentDirty(aDocument) && false == mFormatAfterTidyFlag) return; FormatCommand.Instance.FormatOnSave(aDocument); } public void CommandEventsBeforeExecute(string aGuid, int aId, object aCustomIn, object aCustomOut, ref bool aCancelDefault) { BeforeExecuteClangCompile(aGuid, aId); BeforeExecuteClangTidy(aGuid, aId); } private void BeforeExecuteClangCompile(string aGuid, int aId) { var compilerSettings = SettingsProvider.CompilerSettingsModel; if (compilerSettings.ClangAfterMSVC == false) return; string commandName = GetCommandName(aGuid, aId); if (0 != string.Compare(VsCommands.Compile, commandName)) return; } private void BeforeExecuteClangTidy(string aGuid, int aId) { string commandName = GetCommandName(aGuid, aId); if (VsCommands.SaveCommands.Contains(commandName)) mSaveCommandWasGiven = true; } public void OnWindowActivated(Window GotFocus, Window LostFocus) { VsWindowController.SetPreviousActiveWindow(LostFocus); if (ReleaseNotesView.WasShown == false) { var releaseNotesView = new ReleaseNotesView(true); releaseNotesView.Show(); } if (showOpenFolderWarning) { var registryUtility = new RegistryUtility(registryName); string showCMakeBetaWarning = registryUtility.ReadCurrentUserKey(keyName); if (showCMakeBetaWarning == null && SolutionInfo.IsOpenFolderModeActive()) { showOpenFolderWarning = false; CMakeBetaWarning cMakeBetaWarning = new CMakeBetaWarning(); cMakeBetaWarning.Show(); } } if (SettingsProvider.CompilerSettingsModel.ShowSquiggles == false) return; if (running || vsBuildRunning) return; Document document = GotFocus.Document; if (document == null) return; if (!string.IsNullOrEmpty(oldActiveDocumentName) && oldActiveDocumentName == document.FullName) return; oldActiveDocumentName = document.FullName; if (!ScriptConstants.kAcceptedFileExtensions.Contains(Path.GetExtension(document.FullName))) return; _ = Task.Run(() => { lock (mutex) { try { TaskErrorViewModel.FileErrorsPair.Clear(); using BackgroundTidy backgroundTidyCommand = new BackgroundTidy(); backgroundTidyCommand.Run(document, CommandIds.kTidyId); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } }); } private bool IsAToolbarCommand(OleMenuCommand command) { return command.CommandID.ID == CommandIds.kCompileToolbarId || command.CommandID.ID == CommandIds.kClangFormatToolbarId || command.CommandID.ID == CommandIds.kTidyToolbarId || command.CommandID.ID == CommandIds.kTidyFixToolbarId; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/CommandControllerInstance.cs ================================================ namespace ClangPowerTools { public class CommandControllerInstance { public static CommandControllerInstance Instance { get { return instance; } } public static CommandController CommandController { get; set; } public static readonly CommandControllerInstance instance = new(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/CommandIds.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public class CommandIds { #region Constants public static readonly HashSet idsHexa = new HashSet() { 0x1A20, 0x0102, 0x1100, 0x010A, 0x010B, 0x0101, 0x1101, 0x0109, 0x1102, 0x0115, 0x0117, 0x01A7, 0x0105, 0x1103, 0x0104, 0x0103, 0x0107, 0x0108, 0x1032, 0x1033, 0X0106, 0x0216, 0X0116, 0x0126, }; public static readonly HashSet idsNumeric = new HashSet() { 6688, 258, 4352, 266, 267, 257, 4353, 277, 279, 423, 265, 4354, 261, 4355, 260, 259, 263, 264, 4146, 4147, 262, 534, 278, 294 }; public const int kFindViewMenuId = 0x1A20; public const int kCompileId = 0x0102; public const int kCompileToolbarId = 0x1100; public const int kTidyToolWindowId = 0x010A; public const int kTidyToolWindowFilesId = 0x010B; public const int kTidyId = 0x0101; public const int kTidyToolbarId = 0x1101; public const int kTidyFixId = 0x0109; public const int kTidyFixToolbarId = 0x1102; public const int kClangFind = 0x0115; public const int kClangFindRun = 0x0117; public const int kOptimizeIncludesId = 0x01A7; public const int kClangFormat = 0x0105; public const int kClangFormatToolbarId = 0x1103; public const int kStopClang = 0x0104; public const int kSettingsId = 0x0103; public const int kIgnoreFormatId = 0x0107; public const int kIgnoreCompileId = 0x0108; public const int kITidyExportConfigId = 0x1032; public const int kLogoutId = 0x1033; public const int kJsonCompilationDatabase = 0x0106; public const int kDocumentationYamlId = 0x0216; public const int kDocumentationHtmlId = 0x0116; public const int kDocumentationMdId = 0x0126; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/CommandUILocation.cs ================================================ namespace ClangPowerTools.Commands { public enum CommandUILocation { Toolbar, ContextMenu, ViewMenu }; } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/CompileCommand.cs ================================================ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.ComponentModel.Design; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public class CompileCommand : ClangCommand { #region Properties /// /// Gets the instance of the command. /// public static CompileCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. protected CompileCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in CompileCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new CompileCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task RunClangCompileAsync(int aCommandId, CommandUILocation commandUILocation, bool jsonCompilationDbActive = false) { await PrepareCommmandAsync(commandUILocation, jsonCompilationDbActive); CacheProjectsFromItems(); await Task.Run(() => { lock (mutex) { try { RunScript(aCommandId, jsonCompilationDbActive); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/DocumentationHtmlCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerTools.Events; using ClangPowerToolsShared.Helpers; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Commands { public sealed class DocumentationHtmlCommand : ClangCommand { private AsyncPackage package; public static DocumentationHtmlCommand Instance { get; private set; } protected DocumentationHtmlCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { package = aPackage; if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to DocumentationCommand in TidyCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new DocumentationHtmlCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task GenerateDocumentationAsync(int commandId) { await PrepareCommmandAsync(CommandUILocation.ContextMenu, false); CacheProjectsFromItems(); await Task.Run(() => { lock (mutex) { try { GenerateDocumentationForProject(commandId, package); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/DocumentationMdCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerTools.Events; using ClangPowerToolsShared.Helpers; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.Linq; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Commands { public sealed class DocumentationMdCommand : ClangCommand { private AsyncPackage package; public static DocumentationMdCommand Instance { get; private set; } private DocumentationMdCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { package = aPackage; if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to DocumentationCommand in TidyCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new DocumentationMdCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task GenerateDocumentationAsync(int commandId) { await PrepareCommmandAsync(CommandUILocation.ContextMenu, false); CacheProjectsFromItems(); await Task.Run(() => { lock (mutex) { try { GenerateDocumentationForProject(commandId, package); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/DocumentationYamlCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerTools.Events; using ClangPowerToolsShared.Helpers; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Commands { public sealed class DocumentationYamlCommand : ClangCommand { //public event EventHandler CloseDataStreamingEvent; //protected void OnDataStreamClose(CloseDataStreamingEventArgs e) //{ // CloseDataStreamingEvent?.Invoke(this, e); //} private AsyncPackage package; public static DocumentationYamlCommand Instance { get; private set; } private DocumentationYamlCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { package = aPackage; if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to DocumentationCommand in TidyCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new DocumentationYamlCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task GenerateDocumentationAsync(int commandId) { await PrepareCommmandAsync(CommandUILocation.ContextMenu, false); CacheProjectsFromItems(); await Task.Run(() => { lock (mutex) { try { GenerateDocumentationForProject(commandId, package); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/FindCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.Linq; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Commands { public class FindCommand : ClangCommand { #region Properties private readonly AsyncPackage package; public static FindCommand Instance { get; private set; } #endregion #region Constructor protected FindCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { package = aPackage; var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in CompileCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new FindCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task FindAsync(CommandUILocation commandUILocation) { await PrepareCommmandAsync(commandUILocation); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await package.ShowToolWindowAsync( typeof(FindToolWindow), 0, create: true, cancellationToken: package.DisposalToken); var findToolWindow = (FindToolWindow)window; ItemsCollector itemsCollector = new ItemsCollector(); itemsCollector.CollectSelectedProjectItems(); FilePathCollector fileCollector = new FilePathCollector(); var paths = fileCollector.Collect(itemsCollector.Items).ToList(); if (findToolWindow != null) findToolWindow.OpenFindToolWindow(paths); } public async Task RunQueryAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await package.ShowToolWindowAsync( typeof(FindToolWindow), 0, create: true, cancellationToken: package.DisposalToken); var findToolWindow = (FindToolWindow)window; await Task.Run(() => { lock (mutex) { try { InvokeFindCommand(findToolWindow); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/FindCommandIds.cs ================================================ using System.Collections.Generic; using System.Linq; namespace ClangPowerToolsShared.Commands { public static class FindCommandIds { public const int kDefaultArgsId = 1; public const int kCustomMatchesId = 2; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/FindViewMenuCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using Microsoft.VisualStudio.Shell; using System; using System.ComponentModel.Design; using System.Linq; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Commands { public class FindViewMenuCommand : ClangCommand { private readonly AsyncPackage package; public static FindViewMenuCommand Instance { get; private set; } protected FindViewMenuCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { package = aPackage; var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in CompileCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new FindViewMenuCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task FindAsync(CommandUILocation commandUILocation) { await PrepareCommmandAsync(commandUILocation); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await package.ShowToolWindowAsync( typeof(FindToolWindow), 0, create: true, cancellationToken: package.DisposalToken); var findToolWindow = (FindToolWindow)window; ItemsCollector itemsCollector = new ItemsCollector(); itemsCollector.CollectSelectedProjectItems(); FilePathCollector fileCollector = new FilePathCollector(); var paths = fileCollector.Collect(itemsCollector.Items).ToList(); if (findToolWindow != null) findToolWindow.OpenFindToolWindow(paths); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/FormatCommand.cs ================================================ using ClangPowerTools.Events; using ClangPowerTools.Helpers; using ClangPowerTools.IgnoreActions; using EnvDTE; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.Linq; using System.Windows.Forms; using System.Xml.Linq; using Process = System.Diagnostics.Process; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class FormatCommand : ClangCommand { #region Members public event EventHandler FormatEvent; private bool clearOutput = false; private Document mDocument = null; #endregion #region Properties /// /// Gets the instance of the command. /// public static FormatCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. private FormatCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion #region Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in ClangFormatCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new FormatCommand(commandService, aCommandController, aPackage, aGuid, aId); } public void RunClangFormat(CommandUILocation commandUILocation) { if (clearOutput == false) OnFormatFile(new FormatCommandEventArgs() { CanFormat = true, Clear = clearOutput }); clearOutput = true; if (CommandUILocation.ContextMenu == commandUILocation) { FormatAllSelectedDocuments(); } else { FormatActiveDocument(); } } private void FormatActiveDocument() { mDocument = DocumentHandler.GetActiveDocument(); ExecuteFormatCommand(); } public void FormatOnSave(Document document) { clearOutput = true; mDocument = document; ExecuteFormatCommand(); } public string RunFormatProcess(string dirPath, string filePath, string text, int startPosition, int length) { var process = CreateProcess(text, startPosition, length, dirPath, filePath); try { process.Start(); } catch (Exception exception) { throw new Exception( $"Cannot execute {process.StartInfo.FileName}.\n{exception.Message}."); } process.StandardInput.Write(text); process.StandardInput.Close(); var output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (0 != process.ExitCode) throw new Exception(process.StandardError.ReadToEnd()); return output; } private void ExecuteFormatCommand() { try { if (ValidExecution(out IWpfTextView view) == false) return; var dirPath = string.Empty; var filePath = Vsix.GetDocumentPath(view); var text = view.TextBuffer.CurrentSnapshot.GetText(); var startPosition = 0; var length = text.Length; if (false == view.Selection.StreamSelectionSpan.IsEmpty) { // get the necessary elements for format selection FindStartPositionAndLengthOfSelectedText(view, text, out startPosition, out length); dirPath = Vsix.GetDocumentParent(view); } else { // format the end of the file for format document text = FormatEndOfFile(view, filePath, out dirPath); } string output = RunFormatProcess(dirPath, filePath, text, startPosition, length); ApplyClangFormat(output, view); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error while running clang-format", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } #region Validation private bool ValidExecution(out IWpfTextView view) { var formatSettings = SettingsProvider.FormatSettingsModel; view = Vsix.GetDocumentView(mDocument); if (view == null) return false; if (IsFileStyleSelected(formatSettings)) { var fileToFormatPath = Vsix.GetDocumentParent(view); if (!FileSystem.SearchAllTopDirectories(fileToFormatPath, FileSystem.ConfigClangFormatFileTypes)) { OnFormatFile(new FormatCommandEventArgs() { Clear = clearOutput, FormatConfigFound = false }); if (clearOutput) clearOutput = false; return false; } } if (FileHasExtension(mDocument.FullName, formatSettings.FileExtensions) == false) { OnFormatFile(new FormatCommandEventArgs() { IgnoreExtension = true, FileName = mDocument.Name, Clear = clearOutput }); if (clearOutput) clearOutput = false; return false; } var ignoreItem = new IgnoreItem(); if (ignoreItem.Check(mDocument)) { OnFormatFile(new FormatCommandEventArgs() { IgnoreFile = true, FileName = mDocument.Name, Clear = clearOutput }); if (clearOutput) clearOutput = false; OnIgnoreItem(new ClangCommandMessageEventArgs(ignoreItem.IgnoreFormatMessage, false)); return false; } if (ScriptConstants.kCMakeConfigFile == mDocument.Name.ToLower()) return false; OnFormatFile(new FormatCommandEventArgs() { Clear = true }); return true; } private void OnFormatFile(FormatCommandEventArgs e) { FormatEvent?.Invoke(this, e); } private bool IsFileStyleSelected(FormatSettingsModel formatSettings) { return formatSettings.Style == ClangFormatStyle.file && formatSettings.FallbackStyle == ClangFormatFallbackStyle.none; } private bool FileHasExtension(string filePath, string fileExtensions) { var extensions = fileExtensions.ToLower().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); return extensions.Contains(Path.GetExtension(filePath).ToLower()); } #endregion private void FormatAllSelectedDocuments() { ItemsCollector itemsCollector = new ItemsCollector(); itemsCollector.CollectSelectedProjectItems(); List activeDocs = DocumentHandler.GetListOfActiveDocuments(); Document activeDocument = DocumentHandler.GetActiveDocument(); foreach (var item in itemsCollector.Items) { try { var projectItem = item.GetObject() as ProjectItem; mDocument = projectItem.Open().Document; ExecuteFormatCommand(); if (DocumentHandler.IsOpen(mDocument, activeDocs)) { mDocument.Save(); } else { mDocument.Close(vsSaveChanges.vsSaveChangesYes); } } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { mDocument = null; } } if (activeDocument != null) { activeDocument.Activate(); } } private string FormatEndOfFile(IWpfTextView aView, string aFilePath, out string aDirPath) { aDirPath = Path.GetDirectoryName(aFilePath); var text = aView.TextBuffer.CurrentSnapshot.GetText(); var newline = text.Contains(Environment.NewLine) ? Environment.NewLine : "\n"; if (!text.EndsWith(newline)) { aView.TextBuffer.Insert(aView.TextBuffer.CurrentSnapshot.Length, newline); text += newline; } return text; } private void FindStartPositionAndLengthOfSelectedText(IWpfTextView aView, string aText, out int aStartPosition, out int aLength) { aStartPosition = aView.Selection.Start.Position.GetContainingLine().Start.Position; int end = aView.Selection.End.Position.GetContainingLine().End.Position; aLength = end - aStartPosition; // formatting a range that starts at the end of the file is not supported. if (aStartPosition >= aText.Length && aText.Length > 0) aStartPosition = aText.Length - 1; } private Process CreateProcess(string aText, int aOffset, int aLength, string aPath, string aFilePath) { var formatSettings = SettingsProvider.FormatSettingsModel; string vsixPath = Path.GetDirectoryName( GetType().Assembly.Location); Process process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.FileName = true == (string.IsNullOrWhiteSpace(formatSettings.CustomExecutable) == false) ? formatSettings.CustomExecutable : Path.Combine(vsixPath, ScriptConstants.kClangFormat); process.StartInfo.Arguments = " -offset " + aOffset + " -length " + aLength + " -output-replacements-xml " + $" {ScriptConstants.kStyle} \"{formatSettings.Style}\"" + $" {ScriptConstants.kFallbackStyle} \"{formatSettings.FallbackStyle}\""; var assumeFilename = formatSettings.AssumeFilename; if (string.IsNullOrEmpty(assumeFilename)) assumeFilename = aFilePath; if (!string.IsNullOrEmpty(assumeFilename)) process.StartInfo.Arguments += $" -assume-filename \"{assumeFilename}\""; if (null != aPath) process.StartInfo.WorkingDirectory = aPath; return process; } private void ApplyClangFormat(string replacements, IWpfTextView view) { if (string.IsNullOrWhiteSpace(replacements)) return; var root = XElement.Parse(replacements); var edit = view.TextBuffer.CreateEdit(); foreach (XElement replacement in root.Descendants("replacement")) { var span = new Span( int.Parse(replacement.Attribute("offset").Value), int.Parse(replacement.Attribute("length").Value)); edit.Replace(span, replacement.Value); } edit.Apply(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/IgnoreCommand.cs ================================================ using ClangPowerTools.Helpers; using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools.Commands { public class IgnoreCommand : BasicCommand { #region Constructor public IgnoreCommand(AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { } #endregion #region Public Methods /// /// the method will add to ignored files the items meant to be ignored /// /// template /// list of items to ignore /// settings from SettingsProvider /// name of property meant to be get and set using reflection public void AddItemsToIgnore(List itemsToIgnore, T settings, string PropertyName) { if (itemsToIgnore.Any() == false) { return; } string filesToIgnore = (string)PropertyHandler.Get(settings, PropertyName); if (filesToIgnore.Length > 0) { filesToIgnore += ";"; } filesToIgnore += string.Join(";", RemoveDuplicateDocuments(itemsToIgnore, filesToIgnore)); PropertyHandler.Set(settings, PropertyName, filesToIgnore); } #endregion #region Private Methods private List RemoveDuplicateDocuments(List documentsToIgnore, string filesToIgnore) { List trimmedDocumentToIgnore = new List(); foreach (var item in documentsToIgnore) { if (filesToIgnore.Contains(item) == false) { trimmedDocumentToIgnore.Add(item); } } return trimmedDocumentToIgnore; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/IgnoreCompileCommand.cs ================================================ using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Linq; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class IgnoreCompileCommand : IgnoreCommand { #region Properties /// /// Gets the instance of the command. /// public static IgnoreCompileCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. /// Command service to add command to, not null. private IgnoreCompileCommand(CommandController aCommandController, OleMenuCommandService aCommandService, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuItem = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuItem.BeforeQueryStatus += aCommandController.VisibilityOnBeforeCommand; aCommandService.AddCommand(menuItem); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in IgnoreCompileCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new IgnoreCompileCommand(aCommandController, commandService, aPackage, aGuid, aId); } /// /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// /// Event sender. /// Event args. public void RunIgnoreCompileCommand() { _ = Task.Run(() => { var settingsHandler = new SettingsHandler(); var itemsCollector = new ItemsCollector(); List projectsToIgnore = itemsCollector.GetProjectsToIgnore(); var settingsModel = SettingsProvider.CompilerSettingsModel; AddItemsToIgnore(projectsToIgnore, settingsModel, "ProjectsToIgnore"); if (projectsToIgnore.Any() == false) { List filesToIgnore = itemsCollector.GetFilesToIgnore(); AddItemsToIgnore(filesToIgnore, settingsModel, "FilesToIgnore"); } settingsHandler.SaveSettings(); }); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/IgnoreFormatCommand.cs ================================================ using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.ComponentModel.Design; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class IgnoreFormatCommand : IgnoreCommand { #region Properties /// /// Gets the instance of the command. /// public static IgnoreFormatCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. /// Command service to add command to, not null. private IgnoreFormatCommand(CommandController aCommandController, OleMenuCommandService aCommandService, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuItem = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuItem.BeforeQueryStatus += aCommandController.VisibilityOnBeforeCommand; aCommandService.AddCommand(menuItem); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in IgnoreFormatCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new IgnoreFormatCommand(aCommandController, commandService, aPackage, aGuid, aId); } /// /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// /// Event sender. /// Event args. public void RunIgnoreFormatCommand() { _ = Task.Run(() => { var itemsCollector = new ItemsCollector(); var settingsHandler = new SettingsHandler(); var settings = SettingsProvider.FormatSettingsModel; List documentsToIgnore = itemsCollector.GetFilesToIgnore(); AddItemsToIgnore(documentsToIgnore, settings, "FilesToIgnore"); settingsHandler.SaveSettings(); }); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/JsonCompilationDatabaseCommand.cs ================================================ using ClangPowerTools.Events; using Microsoft.VisualStudio.Shell; using System; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// internal sealed class JsonCompilationDatabaseCommand : CompileCommand { #region Properties /// /// Gets the instance of the command. /// public static new JsonCompilationDatabaseCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. /// Command service to add command to, not null. private JsonCompilationDatabaseCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aCommandService, aCommandController, aPackage, aGuid, aId) { } #endregion #region Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static new async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in ClangFormatCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new JsonCompilationDatabaseCommand(commandService, aCommandController, aPackage, aGuid, aId); } private bool OpenInExplorer { get; set; } /// /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// /// Event sender. /// Event args. public async Task ExportAsync(CommandUILocation aCommandUILocation, bool openInExplorer = true) { OpenInExplorer = openInExplorer; await RunClangCompileAsync(CommandIds.kCompileId, aCommandUILocation, true); } internal void OpenInFileExplorer(object sender, JsonFilePathArgs e) { if (OpenInExplorer) { if (!File.Exists(e.FilePath)) return; // combine the arguments together // it doesn't matter if there is a space after ',' string argument = "/select, \"" + e.FilePath + "\""; // open the file in File Explorer and select it Process.Start("explorer.exe", argument); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/LookInMenu.cs ================================================ namespace ClangPowerToolsShared.Commands { public enum LookInMenu { EntireSolution, CurrentProject, CurrentActiveDocument, } public class MenuItem { public MenuItem() { } public MenuItem(string name, LookInMenu lookInMenu) { Name = name; LookInMenu = lookInMenu; } public string Name { get; set; } public LookInMenu LookInMenu { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/Models/CacheProjectsItemsModel.cs ================================================ using ClangPowerTools; using EnvDTE; using System.Collections.Generic; using System.Linq; namespace ClangPowerToolsShared.Commands.Models { /// /// Cache projects and Items, configuration, platform - used in script generating /// public class CacheProjectsItemsModel { public List Projects { get; set; } = new List(); public List ProjectItems { get; set; } = new List(); public List ProjectsStringList { get { if (ProjectItems.Count > 0) { return ProjectItems.Select(p => p.ContainingProject.FullName).ToList().Distinct().ToList(); } else if (Projects.Count > 0) { return Projects.Select(e => e.FullName).ToList(); } return new(); } } public string Configuration { get { if (ProjectItems.Count > 0) { return ProjectConfigurationHandler.GetConfiguration(ProjectItems[0].ContainingProject); } else if (Projects.Count > 0) { return ProjectConfigurationHandler.GetConfiguration(Projects[0]); } return string.Empty; } } public string Platform { get { if (ProjectItems.Count > 0) { return ProjectConfigurationHandler.GetPlatform(ProjectItems[0].ContainingProject); } else if (Projects.Count > 0) { return ProjectConfigurationHandler.GetPlatform(Projects[0]); } return string.Empty; } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/OptimizeIncludesCommand.cs ================================================ using Microsoft.VisualStudio.Shell; using System.ComponentModel.Design; using System; using Task = System.Threading.Tasks.Task; using Microsoft.VisualStudio.Shell.Interop; using System.Windows.Forms; using System.IO; using ClangPowerToolsShared.MVVM.Constants; using Microsoft.VisualStudio.TextTemplating.VSHost; namespace ClangPowerTools.Commands { public class OptimizeIncludesCommand : ClangCommand { /// /// Gets the instance of the command. /// public static OptimizeIncludesCommand Instance { get; private set; } #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. protected OptimizeIncludesCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in CompileCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new OptimizeIncludesCommand(commandService, aCommandController, aPackage, aGuid, aId); } public async Task RunOptimizeIncludes(CommandUILocation commandUILocation) { //apply include what you use await Task.Run(() => { lock (mutex) { try { OptimizeIncludes(); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/RunController.cs ================================================ using ClangPowerTools; using ClangPowerTools.Events; using System; using System.Collections.Generic; using System.Text; namespace ClangPowerToolsShared.Commands { public static class RunController { public static bool StopCommandActivated { get; set; } = false; public static RunningProcesses runningProcesses = new RunningProcesses(); public static event EventHandler CloseDataStreamingEvent; public static void OnDataStreamClose(CloseDataStreamingEventArgs e) { CloseDataStreamingEvent?.Invoke(null, e); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/SettingsCommand.cs ================================================ using ClangPowerTools.Commands.BackgroundTidy; using ClangPowerTools.MVVM.LicenseValidation; using ClangPowerTools.Views; using Microsoft.VisualStudio.Shell; using System; using EnvDTE; using System.ComponentModel.Design; using Task = System.Threading.Tasks.Task; using System.Windows.Interop; using Microsoft.Internal.VisualStudio.PlatformUI; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class SettingsCommand : BasicCommand { #region Properties /// /// Gets the instance of the command. /// public static SettingsCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. private SettingsCommand(CommandController aCommandController, OleMenuCommandService aCommandService, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuItem = new OleMenuCommand(aCommandController.Execute, menuCommandID); aCommandService.AddCommand(menuItem); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in SettingsCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new SettingsCommand(aCommandController, commandService, aPackage, aGuid, aId); } public async Task ShowSettingsAsync() { bool activeLicense = await new PersonalLicenseValidator().ValidateAsync(); SettingsView settingsView = new SettingsView(activeLicense); DTE dte = (DTE)ServiceProvider.GetService(typeof(DTE)); WindowHelper.ShowModal(settingsView, (IntPtr) dte.MainWindow.HWnd); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/StopCommand.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell; using System; using System.ComponentModel.Design; using System.Threading; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class StopCommand : ClangCommand { #region Members private PCHCleaner mPCHCleaner = new PCHCleaner(); #endregion #region Properties /// /// Gets the instance of the command. /// public static StopCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. private StopCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in StopClang's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new StopCommand(commandService, aCommandController, aPackage, aGuid, aId); } public Task RunStopClangCommandAsync(bool backgroundRunners) { return Task.Run(() => { StopClangCommand(backgroundRunners); }); } private Mutex mutex = new Mutex(); public void StopClangCommand(bool backgroundRunners) { try { if (backgroundRunners == false) RunController.StopCommandActivated = true; if (RunController.runningProcesses.Exists(backgroundRunners) == false) return; mutex.WaitOne(); RunController.runningProcesses.Kill(backgroundRunners); mutex.ReleaseMutex(); if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { string solutionPath = (dte as DTE2).Solution.FullName; if (string.IsNullOrWhiteSpace(solutionPath)) return; string solutionFolder = solutionPath.Substring(0, solutionPath.LastIndexOf('\\')); mPCHCleaner.Remove(solutionFolder); } if (DirectoryPaths.Count > 0) { var tidyFileCleaner = new ClangTidyCleaner(); tidyFileCleaner.Remove(DirectoryPaths); DirectoryPaths.Clear(); } } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/TidyCommand.cs ================================================ using ClangPowerTools.Events; using ClangPowerTools.Helpers; using ClangPowerTools.Services; using ClangPowerTools.SilentFile; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Views.ToolWindows; using EnvDTE80; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Linq; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Commands { /// /// Command handler /// public sealed class TidyCommand : ClangCommand { #region Properties private readonly AsyncPackage package; /// /// Gets the instance of the command. /// /// public static TidyCommand Instance { get; private set; } #endregion #region Constructor /// /// Initializes a new instance of the class. /// Adds our command handlers for menu (commands must exist in the command table file) /// /// Owner package, not null. private TidyCommand(OleMenuCommandService aCommandService, CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) : base(aPackage, aGuid, aId) { if (null != aCommandService) { package = aPackage; var menuCommandID = new CommandID(CommandSet, Id); var menuCommand = new OleMenuCommand(aCommandController.Execute, menuCommandID); menuCommand.BeforeQueryStatus += aCommandController.OnBeforeClangCommand; menuCommand.Enabled = true; aCommandService.AddCommand(menuCommand); } } #endregion #region Public Methods /// /// Initializes the singleton instance of the command. /// /// Owner package, not null. public static async Task InitializeAsync(CommandController aCommandController, AsyncPackage aPackage, Guid aGuid, int aId) { // Switch to the main thread - the call to AddCommand in TidyCommand's constructor requires // the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(aPackage.DisposalToken); OleMenuCommandService commandService = await aPackage.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService; Instance = new TidyCommand(commandService, aCommandController, aPackage, aGuid, aId); } //display tidy tool window - progress bar, run tidy again public async Task ShowTidyToolWindowEmptyAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await package.ShowToolWindowAsync( typeof(TidyToolWindow), 0, create: true, cancellationToken: package.DisposalToken); var tidyToolWindow = (TidyToolWindow)window; FilePathCollector fileCollector = new FilePathCollector(); var paths = fileCollector.Collect(mItemsCollector.Items).ToList(); if (tidyToolWindow != null) tidyToolWindow.OpenTidyToolWindow(paths); RunController.OnDataStreamClose(new CloseDataStreamingEventArgs(false)); } public async Task ShowTidyToolWindowAsync(List paths = null) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); ToolWindowPane window = await package.ShowToolWindowAsync( typeof(TidyToolWindow), 0, create: true, cancellationToken: package.DisposalToken); var tidyToolWindow = (TidyToolWindow)window; if (tidyToolWindow != null && paths != null) tidyToolWindow.UpdateToolWindow(paths); } public async Task RunClangTidyAsync(int aCommandId, CommandUILocation commandUILocation, List paths = null) { if (CommandIds.kTidyToolWindowId != aCommandId && CommandIds.kTidyFixId != aCommandId) { await PrepareCommmandAsync(commandUILocation); CacheProjectsFromItems(); }else if (CommandIds.kTidyFixId == aCommandId || CommandIds.kTidyFixToolbarId == aCommandId) { await PrepareCommmandAsync(commandUILocation); CacheProjectsFromItems(); } if (CommandIds.kTidyToolWindowId == aCommandId || CommandIds.kTidyFixId == aCommandId) { await Task.Run(() => { lock (mutex) { try { using var silentFileController = new SilentFileChangerController(); using var fileChangerWatcher = new FileChangerWatcher(); var tidySettings = SettingsProvider.TidySettingsModel; if (CommandIds.kTidyFixId == aCommandId || tidySettings.TidyOnSave) { fileChangerWatcher.OnChanged += FileOpener.Open; var dte2 = VsServiceProvider.GetService(typeof(DTE2)) as DTE2; string solutionFolderPath = SolutionInfo.IsOpenFolderModeActive() ? dte2.Solution.FullName : dte2.Solution.FullName .Substring(0, dte2.Solution.FullName.LastIndexOf('\\')); fileChangerWatcher.Run(solutionFolderPath); //FilePathCollector fileCollector = new FilePathCollector(); //var filesPath = fileCollector.Collect(mItemsCollector.Items).ToList(); //silentFileController.SilentFiles(filesPath); //silentFileController.SilentFiles(dte2.Documents); } if (tidySettings.DetectClangTidyFile && !mItemsCollector.IsEmpty) { tidySettings.UseChecksFrom = ClangTidyUseChecksFrom.TidyFile; var settingsHandlder = new SettingsHandler(); settingsHandlder.SaveSettings(); } if (CommandIds.kTidyToolWindowId == aCommandId) RunScript(CommandIds.kTidyId, false, paths); else RunScript(aCommandId, false, paths); } catch (Exception exception) { VsShellUtilities.ShowMessageBox(AsyncPackage, exception.Message, "Error", OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Commands/VsCommands.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.Commands { public static class VsCommands { public static List SaveCommands { get; } = new List() { "File.SaveAll", "File.SaveSelectedItems", "File.Save" }; public static string Compile { get; } = "Build.Compile"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/BooleanToGridLengthConverter.cs ================================================ using System; using System.Globalization; using System.Windows; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class BooleanToGridLengthConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is bool valueAsBool && valueAsBool) { return new GridLength(1, GridUnitType.Auto); } return new GridLength(0); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/BooleanToVisibilityConverter.cs ================================================ using System; using System.Globalization; using System.Windows; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class BooleanToVisibilityConverter : IValueConverter { private object GetVisibility(object value) { if (!(value is bool)) return Visibility.Hidden; bool objValue = (bool)value; if (objValue) return Visibility.Visible; return Visibility.Hidden; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return GetVisibility(value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/ClangFormatFallbackStyleConverter.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class ClangFormatFallbackStyleConverter : IValueConverter { private static Dictionary fallbackStyleDisplay = new Dictionary() { { ClangFormatFallbackStyle.none, "none" }, { ClangFormatFallbackStyle.Chromium, "Chromium" }, { ClangFormatFallbackStyle.Google, "Google" }, { ClangFormatFallbackStyle.LLVM, "LLVM" }, { ClangFormatFallbackStyle.Mozilla, "Mozilla" }, { ClangFormatFallbackStyle.WebKit, "WebKit" }, }; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ClangFormatFallbackStyle fallbackStyle = (ClangFormatFallbackStyle)value; return fallbackStyleDisplay[fallbackStyle]; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/ClangFormatStyleConverter.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class ClangFormatStyleConverter : IValueConverter { public static Dictionary styleDisplay = new Dictionary() { { ClangFormatStyle.file, "file" }, { ClangFormatStyle.Chromium, "Chromium" }, { ClangFormatStyle.Google, "Google" }, { ClangFormatStyle.LLVM, "LLVM" }, { ClangFormatStyle.Mozilla, "Mozilla" }, { ClangFormatStyle.WebKit, "WebKit" }, }; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ClangFormatStyle style = (ClangFormatStyle)value; return styleDisplay[style]; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/ClangGeneralAdditionalIncludesConvertor.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class ClangGeneralAdditionalIncludesConvertor : IValueConverter { #region Members private static readonly Dictionary mAdditionalIncludesEnumToString = new Dictionary { {ClangGeneralAdditionalIncludes.IncludeDirectories, ComboBoxConstants.kIncludeDirectories}, {ClangGeneralAdditionalIncludes.SystemIncludeDirectories, ComboBoxConstants.kSystemIncludeDirectories } }; private static readonly Dictionary mAdditionalIncludesStringToEnum = new Dictionary { { ComboBoxConstants.kIncludeDirectories, ClangGeneralAdditionalIncludes.IncludeDirectories }, { ComboBoxConstants.kSystemIncludeDirectories, ClangGeneralAdditionalIncludes.SystemIncludeDirectories } }; #endregion #region Public Methods public static string ToString(ClangGeneralAdditionalIncludes? aAdditionalIncludes) => mAdditionalIncludesEnumToString[aAdditionalIncludes]; public static ClangGeneralAdditionalIncludes? FromString(string aAdditionalIncludes) => mAdditionalIncludesStringToEnum[aAdditionalIncludes]; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ClangGeneralAdditionalIncludes additionalIncludes = (ClangGeneralAdditionalIncludes)value; return mAdditionalIncludesEnumToString[additionalIncludes]; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/ClangTidyHeaderFiltersConvertor.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class ClangTidyHeaderFiltersConvertor : IValueConverter { #region Members private static Dictionary mCorrespondingHeaderScriptEncode = new Dictionary() { {ComboBoxConstants.kDefaultHeaderFilter, ComboBoxConstants.kDefaultHeaderFilter }, {ComboBoxConstants.kCorrespondingHeaderName, ComboBoxConstants.kCorrespondingHeaderValue } }; private static Dictionary mCorrespondingHeaderScriptDecode = new Dictionary() { {ComboBoxConstants.kDefaultHeaderFilter, ComboBoxConstants.kDefaultHeaderFilter }, {ComboBoxConstants.kCorrespondingHeaderValue, ComboBoxConstants.kCorrespondingHeaderName } }; #endregion #region Public Methods public static string ScriptEncode(string aHeaderFilters) { if (false == mCorrespondingHeaderScriptEncode.ContainsKey(aHeaderFilters)) return string.Empty; return mCorrespondingHeaderScriptEncode[aHeaderFilters]; } public static string ScriptDecode(string aHeaderFilters) { if (false == mCorrespondingHeaderScriptDecode.ContainsKey(aHeaderFilters)) return string.Empty; return mCorrespondingHeaderScriptDecode[aHeaderFilters]; } #region IValueConverter Implementation public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return ((HeaderFiltersValue)value).HeaderFilters; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return new HeaderFiltersValue(value.ToString()); } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Convertors/ClangTidyUseChecksFromConvertor.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Windows.Data; namespace ClangPowerTools.Convertors { public class ClangTidyUseChecksFromConvertor : IValueConverter { #region Members private static readonly Dictionary mClangTidyUseChecksFromEnumToString = new Dictionary { {ClangTidyUseChecksFrom.PredefinedChecks, ComboBoxConstants.kPredefinedChecks }, {ClangTidyUseChecksFrom.CustomChecks, ComboBoxConstants.kCustomChecks }, {ClangTidyUseChecksFrom.TidyFile, ComboBoxConstants.kTidyFile } }; private static readonly Dictionary mClangTidyUseChecksFromStringToEnum = new Dictionary { {ComboBoxConstants.kPredefinedChecks, ClangTidyUseChecksFrom.PredefinedChecks}, {ComboBoxConstants.kCustomChecks , ClangTidyUseChecksFrom.CustomChecks}, {ComboBoxConstants.kTidyFile, ClangTidyUseChecksFrom.TidyFile } }; #endregion #region Public Methods public static string ToString(ClangTidyUseChecksFrom? aChecksFrom) => mClangTidyUseChecksFromEnumToString[aChecksFrom]; public static ClangTidyUseChecksFrom? FromString(string aChecksFrom) => mClangTidyUseChecksFromStringToEnum[aChecksFrom]; #endregion #region IValueConverter Implementation public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ClangTidyUseChecksFrom checksFrom = (ClangTidyUseChecksFrom)value; return ToString(checksFrom); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/ErrorDetector.cs ================================================ using ClangPowerTools.MVVM.Constants; using ClangPowerTools.Properties; using ClangPowerTools.TextOperationsInterfaces; using System.Text.RegularExpressions; namespace ClangPowerTools { public class ErrorDetector : IDetector { #region IDetector Implementation public bool Detect(string text, string pattern, out Match matchResult) { Regex regex = new Regex(pattern); matchResult = regex.Match(text); return matchResult.Success; } #endregion #region Public Methods public bool HasEncodingError(string message) { return message.Contains(ResourceConstants.EncodingError); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/ErrorFormatter.cs ================================================ using ClangPowerTools.TextOperationsInterfaces; using System.Text.RegularExpressions; namespace ClangPowerTools.Error { class ErrorFormatter : ITextFormatter { #region ITextFormater Implementation public string Format(string aText, string aReplacement) { Regex regex = new Regex(ErrorParserConstants.kErrorMessageRegex); return regex.Replace(aText, aReplacement, 1); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/ErrorParserConstants.cs ================================================ namespace ClangPowerTools { public class ErrorParserConstants { #region Constants public const string kClangTag = "Clang Power Tools : "; public const string kCptMatcher = "🔎 Match : "; public const string kCompileClangMissingFromPath = "'clang++.exe' is not recognized"; public const string kTidyClangMissingFromPath = "'clang-tidy.exe' is not recognized"; public const string kErrorTag = "error"; public const string kWarningTag = "warning"; public const string kMessageTag = "message"; public const string kErrorMessageRegex = @"(.\:(\\|\/)[ \S+\\\/.]*[c|C|h|H|cpp|CPP|cc|CC|cxx|CXX|c++|C++|cp|CP])(\r\n|\r|\n| |:)*(\d+)(\r\n|\r|\n| |:)*(\d+)(\r\n|\r|\n| |:)*(error|note|warning)[^s](\r\n|\r|\n| |:)*(.*)"; public const string kMatchMessageRegex = @"<([A-Z]:.+?\.(cpp|cu|cc|cp|tlh|c|cxx|tli|h|hh|hpp|hxx)):(\d+):(\d+),\s(?:col:\d+|line:\d+:\d+)>"; public const string kMatchTidyFileRegex = @"^(?!.*and children =).*([A-Z]:\\.[^""]+?\.(cpp|cu|cc|cp|tlh|c|cxx|tli|h|hh|hpp|hxx))(\W|$)"; public const string kNumberMatchesRegex = @"(\d+)\s(matches|match)\."; public const string kJsonCompilationDbFilePathRegex = @"Exported JSON Compilation Database to (.+\.json)"; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/ErrorWindowController.cs ================================================ using ClangPowerTools.Error; using ClangPowerTools.Events; using ClangPowerTools.Handlers; using ClangPowerToolsShared.Commands; using EnvDTE; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Linq; using System.Threading; namespace ClangPowerTools { public class ErrorWindowController : ErrorListProvider { #region Constructor /// /// Instance Constructor /// /// public ErrorWindowController(IServiceProvider aIServiceProvider) : base(aIServiceProvider) { } #endregion #region Public Methods public void OnErrorDetected(object sender, ErrorDetectedEventArgs e) { UIUpdater.InvokeAsync(() => { SuspendRefresh(); foreach (TaskErrorModel error in e.ErrorList.ToList()) { error.Navigate += ErrorTaskNavigate; Tasks.Add(error); } ResumeRefresh(); if (SettingsProvider.CompilerSettingsModel.ShowErrorList) { BringToFront(); DocumentHandler.FocusActiveDocument(); } }).SafeFireAndForget(); } public void RemoveErrors(IVsHierarchy aHierarchy) { UIUpdater.InvokeAsync(() => { SuspendRefresh(); for (int i = Tasks.Count - 1; i >= 0; --i) { var errorTask = Tasks[i] as ErrorTask; aHierarchy.GetCanonicalName(Microsoft.VisualStudio.VSConstants.VSITEMID_ROOT, out string nameInHierarchy); if (null == errorTask.HierarchyItem) return; errorTask.HierarchyItem.GetCanonicalName(Microsoft.VisualStudio.VSConstants.VSITEMID_ROOT, out string nameErrorTaskHierarchy); if (nameInHierarchy == nameErrorTaskHierarchy) { errorTask.Navigate -= ErrorTaskNavigate; Tasks.Remove(errorTask); } } ResumeRefresh(); }).SafeFireAndForget(); } public void Clear() { UIUpdater.InvokeAsync(() => { Tasks.Clear(); }).SafeFireAndForget(); } public void OnClangCommandBegin(object sender, ClearEventArgs e) { Clear(); TaskErrorViewModel.Errors.Clear(); TaskErrorViewModel.FileErrorsPair.Clear(); } public void OnBuildBegin(vsBuildScope Scope, vsBuildAction Action) { Clear(); } #endregion #region Private Methods private void ErrorTaskNavigate(object sender, EventArgs e) { ErrorTask objErrorTask = (ErrorTask)sender; objErrorTask.Line += 1; objErrorTask.Column += 1; bool bResult = Navigate(objErrorTask, new Guid(EnvDTE.Constants.vsViewKindCode)); objErrorTask.Line -= 1; objErrorTask.Column -= 1; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/TaskErrorModel.cs ================================================ using Microsoft.VisualStudio.Shell; namespace ClangPowerTools { public class TaskErrorModel : ErrorTask { #region Properties public string FullMessage { get; set; } #endregion #region Public Methods public override bool Equals(object obj) { var otherObj = obj as TaskErrorModel; if (null == otherObj) return false; return FullMessage.Replace('/', '\\') == otherObj.FullMessage.Replace('/', '\\'); } public override int GetHashCode() { return FullMessage.Replace('/', '\\').GetHashCode(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/TaskErrorModelBuilder.cs ================================================ using ClangPowerTools.Builder; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System.IO; using System.Text.RegularExpressions; namespace ClangPowerTools.Error { public class TaskErrorModelBuilder : IBuilder { #region Members private TaskErrorModel mError = null; private Match mMatchResult = null; private IVsHierarchy mHierarchy; #endregion #region Consstructor public TaskErrorModelBuilder(IVsHierarchy aHierarchy, Match aMatchResult) { mMatchResult = aMatchResult; mHierarchy = aHierarchy; } #endregion #region IBuilder implementation public TaskErrorModel GetResult() => mError; public void Build() { if (CommandControllerInstance.CommandController.GetCurrentCommandId() == CommandIds.kClangFindRun) { BuildMatch(); } else { var groups = mMatchResult.Groups; string messageDescription = groups[10].Value; if (string.IsNullOrWhiteSpace(messageDescription)) return; string path = groups[1].Value.Replace('/', '\\'); int.TryParse(groups[4].Value, out int line); int.TryParse(groups[6].Value, out int column); string categoryAsString = groups[8].Value; TaskErrorCategory category = FindErrorCategory(ref categoryAsString); string fullMessage = CreateFullErrorMessage(path, line, categoryAsString, messageDescription); // Add clang prefix for error list messageDescription = messageDescription.Insert(0, ErrorParserConstants.kClangTag); mError = new TaskErrorModel() { Document = path, Line = line - 1, Column = column - 1, ErrorCategory = category, Text = messageDescription, FullMessage = fullMessage, HierarchyItem = mHierarchy, Category = TaskCategory.BuildCompile, Priority = TaskPriority.High }; } } private void BuildMatch() { var groups = mMatchResult.Groups; if (string.IsNullOrWhiteSpace(groups[0].Value)) return; string path = groups[1].Value.Replace('/', '\\'); int.TryParse(groups[3].Value, out int line); int.TryParse(groups[4].Value, out int column); string messageDescription = File.ReadAllLines(path)?[line - 1].Remove(0, column - 1); string categoryAsString = ErrorParserConstants.kMessageTag; TaskErrorCategory category = FindErrorCategory(ref categoryAsString); string fullMessage = CreateFullErrorMessage(path, line, categoryAsString, messageDescription); // Add clang prefix for error list messageDescription = messageDescription.Insert(0, ErrorParserConstants.kCptMatcher); mError = new TaskErrorModel() { Document = path, Line = line - 1, Column = column - 1, ErrorCategory = category, Text = messageDescription, FullMessage=fullMessage, HierarchyItem = mHierarchy, Category = TaskCategory.CodeSense, Priority = TaskPriority.High }; } #endregion #region Private Methods private TaskErrorCategory FindErrorCategory(ref string aCategoryAsString) { TaskErrorCategory category; switch (aCategoryAsString) { case ErrorParserConstants.kErrorTag: category = TaskErrorCategory.Error; aCategoryAsString = ErrorParserConstants.kErrorTag; break; case ErrorParserConstants.kWarningTag: category = TaskErrorCategory.Warning; aCategoryAsString = ErrorParserConstants.kWarningTag; break; default: category = TaskErrorCategory.Message; aCategoryAsString = ErrorParserConstants.kMessageTag; break; } return category; } private string CreateFullErrorMessage(string aPath, int aLine, string aCategory, string aDescription) { return $"{aPath}({aLine}): {aCategory}: {aDescription}"; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Error/TaskErrorViewModel.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.Error { public static class TaskErrorViewModel { public static List Errors { get; set; } = new List(); public static Dictionary> FileErrorsPair { get; set; } = new Dictionary>(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/ActiveDocumentEventArgs.cs ================================================ namespace ClangPowerTools.Events { public class ActiveDocumentEventArgs { public bool IsActiveDocument { get; set; } public ActiveDocumentEventArgs(bool isActiveDocument) { IsActiveDocument = isActiveDocument; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/BoolEventArgs.cs ================================================ using System; namespace ClangPowerTools.Events { public class BoolEventArgs : EventArgs { public bool Value { get; set; } public BoolEventArgs(bool value) => Value = value; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/ClangCommandEventArgs.cs ================================================ using System; namespace ClangPowerTools.Events { public class ClangCommandMessageEventArgs : EventArgs { public string Message { get; private set; } public bool ClearFlag { get; set; } public ClangCommandMessageEventArgs(string aMessage, bool aClear) { Message = aMessage; ClearFlag = aClear; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/CleanErrorListEventArgs.cs ================================================ using System; namespace ClangPowerTools.Events { public class ClearEventArgs : EventArgs { public ClearEventArgs() { } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/CloseDataConnectionEventArgs.cs ================================================ namespace ClangPowerTools.Events { public class CloseDataConnectionEventArgs { public CloseDataConnectionEventArgs() { } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/CloseDataStreamingEventArgs.cs ================================================ namespace ClangPowerTools.Events { public class CloseDataStreamingEventArgs { public bool IsStopped { get; set; } public CloseDataStreamingEventArgs(bool isStopped) { IsStopped = isStopped; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/ErrorDetectedEventArgs.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.Events { public class ErrorDetectedEventArgs { public IEnumerable ErrorList { get; set; } public ErrorDetectedEventArgs(IEnumerable aErrorList) { ErrorList = aErrorList; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/FormatCommandEventArgs.cs ================================================ using System; namespace ClangPowerTools.Events { public class FormatCommandEventArgs : EventArgs { public bool CanFormat { get; set; } = false; public bool IgnoreFile { get; set; } = false; public bool IgnoreExtension { get; set; } = false; public bool Clear{ get; set; } = false; public bool FormatConfigFound { get; set; } = true; public string FileName { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/HasEncodingErrorEventArgs.cs ================================================ using ClangPowerTools.Output; namespace ClangPowerTools.Events { public class HasEncodingErrorEventArgs { public OutputContentModel Model { get; set; } public HasEncodingErrorEventArgs(OutputContentModel model) { Model = model; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/JsonFilePathArgs.cs ================================================ namespace ClangPowerTools.Events { public class JsonFilePathArgs { public string FilePath { get; set; } public JsonFilePathArgs(string path) { FilePath = path; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Events/VsHierarchyDetectedEventArgs.cs ================================================ using Microsoft.VisualStudio.Shell.Interop; namespace ClangPowerTools.Events { public class VsHierarchyDetectedEventArgs { public IVsHierarchy Hierarchy { get; set; } public VsHierarchyDetectedEventArgs(IVsHierarchy aHierarchy) { Hierarchy = aHierarchy; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Export Config/TidyConfigFile.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ClangPowerTools { public class TidyConfigFile { #region Members // Create StringBuilder to be written in the .clang-tidy file private readonly StringBuilder tidyConfigOutput = new StringBuilder(); private readonly CompilerSettingsModel compilerSettingsModel; private readonly TidySettingsModel tidySettingsModel; private readonly FormatSettingsModel formatSettingsModel; public TidyConfigFile() { compilerSettingsModel = SettingsProvider.CompilerSettingsModel; tidySettingsModel = SettingsProvider.TidySettingsModel; formatSettingsModel = SettingsProvider.FormatSettingsModel; } // Readonly list for paramaters names private static readonly List parameterNames = new List() { "Checks:", "WarningsAsErrors:", "WarningsAsErrors:", "HeaderFilterRegex:", "FormatStyle:", "User:" }; // Max length used to add space padding for the paramater name in a line private int maxNameLength = 0; private readonly string NO_CHECKS_ACTIVE = "-*"; #endregion #region Public Methods public StringBuilder CreateOutput() { maxNameLength = parameterNames.OrderByDescending(s => s.Length).First().Length; tidyConfigOutput.AppendLine("---"); //Checks line CreateChecksOutputLine(parameterNames.ElementAt(0)); //Treat warnings as errors line string treatWarningsAsErrors = ScriptConstants.kTreatWarningsAsErrors; CreateWarningAsErrorsOutputLine(parameterNames.ElementAt(1), treatWarningsAsErrors, true); //Header filter line string headerFilter = tidySettingsModel.HeaderFilter; CreateHeaderFilterOutputLine(parameterNames.ElementAt(3), headerFilter, true); //Format style line string formatStyle = formatSettingsModel.Style.ToString(); CreateOutputLine(parameterNames.ElementAt(4), formatStyle, true); //User line CreateOutputLine(parameterNames.ElementAt(5), Environment.UserName, false); return tidyConfigOutput; } #endregion #region Private Methods private void CreateChecksOutputLine(string paramaterName) { var tidySettings = SettingsProvider.TidySettingsModel; ClangTidyUseChecksFrom clangTidyUseChecksFrom = tidySettings.UseChecksFrom; switch (clangTidyUseChecksFrom) { case ClangTidyUseChecksFrom.PredefinedChecks: var predefinedChecks = tidySettings.PredefinedChecks.Replace(';', ',').TrimEnd(','); CreateChecksOutputLine(paramaterName, predefinedChecks, true); break; case ClangTidyUseChecksFrom.CustomChecks: case ClangTidyUseChecksFrom.TidyFile: var customChecks = tidySettings.CustomChecks.Replace(';', ',').TrimEnd(','); CreateChecksOutputLine(paramaterName, customChecks, true); break; default: CreateOutputLine(paramaterName, "", true); break; } } private string CreateLine(string propertyName, int nameLength, T value, bool hasQuotationMark) { if (hasQuotationMark) { return $"{propertyName.PadRight(maxNameLength - nameLength + nameLength, ' ')} '{value}'"; } return $"{propertyName.PadRight(maxNameLength - nameLength + nameLength, ' ')} {value.ToString().ToLower()}"; } private void CreateOutputLine(string paramaterName, T formatStyle, bool hasQuotationMark) { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, formatStyle, hasQuotationMark)); } private void CreateWarningAsErrorsOutputLine(string paramaterName, string warningsAsErrors, bool hasQuotationMark) { if (compilerSettingsModel.WarningsAsErrors) { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, warningsAsErrors, hasQuotationMark)); } else { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, string.Empty, hasQuotationMark)); } } private void CreateChecksOutputLine(string paramaterName, string customChecks, bool hasQuotationMark) { if (customChecks.Length < 1) { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, NO_CHECKS_ACTIVE, hasQuotationMark)); } else { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, $"{NO_CHECKS_ACTIVE},{customChecks}", hasQuotationMark)); } } private void CreateHeaderFilterOutputLine(string paramaterName, string headerFilter, bool hasQuotationMark) { if (headerFilter.Length < 1) { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, ComboBoxConstants.kNone, false)); } else if (headerFilter == ComboBoxConstants.kCorrespondingHeaderName) { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, ComboBoxConstants.kCorrespondingHeaderValue, hasQuotationMark)); } else { tidyConfigOutput.AppendLine(CreateLine(paramaterName, paramaterName.Length, headerFilter, hasQuotationMark)); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Extensions/IntExtension.cs ================================================ namespace ClangPowerTools { public static class IntExtension { public static int ForceInRange(this int number, int min, int max) { if (number < min) number = min; if (number > max) number = max; return number; } public static int RoundUp(this int number) { return 10 * ((number + 9) / 10); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Extensions/ObjectExtension.cs ================================================ using Newtonsoft.Json; namespace ClangPowerTools.Extensions { public static class ObjectExtension { public static T Clone(this T obj) { return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj)); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Extensions/StringExtension.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; namespace ClangPowerTools { public static class StringExtension { #region Public Methods public static string SubstringAfter(this string aText, string aSearchedSubstring) { if (string.IsNullOrEmpty(aSearchedSubstring)) return aText; CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo; int index = compareInfo.IndexOf(aText, aSearchedSubstring, CompareOptions.Ordinal); if (index < 0) return string.Empty; //No such substring return aText.Substring(index + aSearchedSubstring.Length); } public static string SubstringBefore(this string aText, string aSearchedSubstring) { if (string.IsNullOrEmpty(aSearchedSubstring)) return aSearchedSubstring; CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo; int index = compareInfo.IndexOf(aText, aSearchedSubstring, CompareOptions.Ordinal); if (index < 0) return string.Empty; //No such substring return aText.Substring(0, index); } /// /// String comparison using IndexOf /// /// /// /// /// public static bool Contains(this string paragrah, string word, StringComparison comp) { return paragrah?.IndexOf(word, comp) >= 0; } /// /// Get all indexes of a value /// /// /// /// public static IEnumerable AllIndexesOf(this string str, string value) { if (String.IsNullOrEmpty(value)) throw new ArgumentException("the string to find may not be empty", "value"); for (int index = 0; ; index += value.Length) { index = str.IndexOf(value, index); if (index == -1) break; yield return index; } } public static string Reverse(this string input) { char[] chars = input.ToCharArray(); Array.Reverse(chars); return new String(chars); } public static string TrimEnd(this string input, string substring) { if (input.EndsWith(substring)) input = input.Substring(0, input.LastIndexOf(substring)); return input; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Extensions/TaskExtensions.cs ================================================ using System; using System.Threading.Tasks; namespace ClangPowerTools { /// /// Extension methods for System.Threading.Tasks.Task /// public static class TaskExtensions { #region Public Methods /// /// Safely execute the Task without waiting for it to complete before moving to the next line of code; commonly known as "Fire And Forget". /// /// Task. /// If set to true continue on captured context; this will ensure that the Synchronization Context returns to the calling thread. If set to false continue on a different context; this will allow the Synchronization Context to continue on a different thread /// If an exception is thrown in the Task, onException will execute. If onException is null, the exception will be re-thrown #pragma warning disable VSTHRD100 // Asynchronous methods should return a Task instead of void public static async void SafeFireAndForget(this Task task, bool continueOnCapturedContext = true, Action onException = null) #pragma warning restore VSTHRD100 // Asynchronous methods should return a Task instead of void { try { #pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks await task.ConfigureAwait(continueOnCapturedContext); #pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks } catch (Exception ex) when (onException != null) { onException(ex); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Files Operations/FileChangerWatcher.cs ================================================ using System; using System.Collections.Generic; using System.IO; namespace ClangPowerTools { public class FileChangerWatcher : IDisposable { #region Members private List mWatchers = new List(); #endregion #region Properties public FileSystemEventHandler OnChanged { get; set; } #endregion #region Public methods public void Run(string aDirectoryPath) { if (null == aDirectoryPath || string.IsNullOrWhiteSpace(aDirectoryPath)) return; foreach (var extension in ScriptConstants.kAcceptedFileExtensions) mWatchers.Add(CreateFileWatcher(aDirectoryPath, extension)); } #region IDisposable implementation public void Dispose() { OnChanged = null; mWatchers = null; } #endregion #endregion #region Private Methods private FileSystemWatcher CreateFileWatcher(string aDirectoryPath, string aExtension) { FileSystemWatcher fileWatcher = new FileSystemWatcher(); // Set the path property of FileSystemWatcher fileWatcher.Path = aDirectoryPath; // Watch for changes in LastWrite time fileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; // Watch files with specific file extension fileWatcher.Filter = $"*{aExtension}"; //Subdirectories will be also watched. fileWatcher.IncludeSubdirectories = true; // Watch every file in the directory for changes fileWatcher.Changed += OnChanged; fileWatcher.Deleted += OnChanged; // Begin watching. fileWatcher.EnableRaisingEvents = true; return fileWatcher; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Files Operations/FileOpener.cs ================================================ using System.IO; namespace ClangPowerTools { public class FileOpener { #region Members //private static readonly string kOpenCommand = "File.OpenFile"; #endregion #region Public methods // Open the changed files in the editor public static void Open(object source, FileSystemEventArgs e) { //if (VsServiceProvider.TryGetService(typeof(DTE), out object dte)) // (dte as DTE2).ExecuteCommand(kOpenCommand, e.FullPath); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Files Operations/FilePathCollector.cs ================================================ using EnvDTE; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools { public class FilePathCollector { #region Public Methods public IEnumerable Collect(IEnumerable aItems) => aItems.Select(item => item.GetPath()); public IEnumerable Collect(Documents aDocuments) => aDocuments.Cast().Select(doc => doc.FullName); public string Collect(Document aDocument) => aDocument.FullName; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ActiveWindowProperties.cs ================================================ using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; namespace ClangPowerTools { public static class ActiveWindowProperties { #region Public Methods public static ProjectItem GetProjectItemOfActiveWindow() { if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { var activeWindow = (dte as DTE2).ActiveWindow; activeWindow.Activate(); return activeWindow.ProjectItem; } return null; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ApiUtility.cs ================================================ using System.Net.Http; using System.Net.Http.Headers; namespace ClangPowerTools { public static class ApiUtility { public static HttpClient ApiClient { get; set; } public static void InitializeApiClient() { if (ApiClient != null) return; ApiClient = new HttpClient(); ApiClient.DefaultRequestHeaders.Accept.Clear(); ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/AutomationUtil.cs ================================================ using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using System.Collections.Generic; namespace ClangPowerTools { public class AutomationUtil { #region Public Methods public static List GetAllProjects(Solution aSolution) { List list = new List(); Projects projects = aSolution.Projects; for (int index = 1; index <= projects.Count; ++index) { Project project = projects.Item(index); if (null == project) continue; if (project.Kind == EnvDTE.Constants.vsProjectKindSolutionItems) list.AddRange(GetSolutionFolderProjects(project)); else if (project.Kind != EnvDTE.Constants.vsProjectKindMisc) list.Add(new CurrentProject(project)); } return list; } public static IVsHierarchy GetProjectHierarchy(IVsSolution aSolution, Project aProject) { return VSConstants.S_OK == aSolution.GetProjectOfUniqueName(aProject.UniqueName, out IVsHierarchy hierarchy) ? hierarchy : null; } public static IVsHierarchy GetItemHierarchy(IVsSolution aSolution, IItem aItem ) { Project project = null; if( aItem is CurrentProjectItem ) { var projectItem = aItem.GetObject() as ProjectItem; project = projectItem.ContainingProject; } else if( aItem is CurrentProject ) { project = aItem.GetObject() as Project; } if( project != null ) { return GetProjectHierarchy(aSolution, project ); } return null; } public static void SaveDirtyProjects(Solution aSolution) { var projects = GetAllProjects(aSolution); if (null == projects) return; foreach (var proj in projects) { var project = proj.GetObject() as Project; if (null == project) continue; if (true == project.IsDirty) project.Save(); } } public static bool ContainLoadedItems(IEnumerable aItems) { foreach( var item in aItems ) { var projItem = item.GetObject() as ProjectItem; if (null == projItem) return true; var project = projItem.ContainingProject; if (null == project) return true; if (true == IsLoadedProject(project)) return true; } return false; } #endregion #region Private Methods private static List GetSolutionFolderProjects(Project aSolutionFolderItem) { List list = new List(); foreach (ProjectItem projectItem in aSolutionFolderItem.ProjectItems) { Project subProject = projectItem.SubProject; if (null == subProject) continue; if (subProject.Kind == EnvDTE.Constants.vsProjectKindSolutionItems) list.AddRange(GetSolutionFolderProjects(subProject)); else if (subProject.Kind != EnvDTE.Constants.vsProjectKindMisc) list.Add(new CurrentProject(subProject)); } return list; } private static bool IsLoadedProject(Project aProject) { return 0 != string.Compare(EnvDTE.Constants.vsProjectKindMisc, aProject.Kind, System.StringComparison.OrdinalIgnoreCase) && 0 != string.Compare(EnvDTE.Constants.vsProjectKindUnmodeled, aProject.Kind, System.StringComparison.OrdinalIgnoreCase); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ClangTidyCleaner.cs ================================================ using System.Collections.Generic; using System.IO; namespace ClangPowerTools.Helpers { public class ClangTidyCleaner { #region Members private const string CLANG_TIDY_FILE = ".clang-tidy"; private const string CLANG_TIDY_BACKUP_FILE = ".clang-tidy.cpt_backup"; #endregion #region Methods public void Remove(string directoryPath) { var clangTidyFilePath = Path.Combine(directoryPath, CLANG_TIDY_FILE); var clangTidyBackupFilePath = Path.Combine(directoryPath, CLANG_TIDY_BACKUP_FILE); var settingsPathBuilder = new SettingsPathBuilder(); var settingsPath = settingsPathBuilder.GetPath(""); var tempClangTidyFilePath = Path.Combine(settingsPath, CLANG_TIDY_FILE); // if in the same directory already exists a .clang-tidy file if (File.Exists(tempClangTidyFilePath)) { // if the backup file from script still exists if (File.Exists(clangTidyBackupFilePath)) { File.Copy(clangTidyBackupFilePath, clangTidyFilePath, true); File.Delete(clangTidyBackupFilePath); } else // backup file from script was deleted but we still have the backup file from %appdata% { File.Copy(tempClangTidyFilePath, clangTidyFilePath, true); } File.Delete(tempClangTidyFilePath); return; } // the .clang-tidy file was created by the script // if it wasn't deteled by the script then delete it now if (File.Exists(clangTidyFilePath) && File.Exists(tempClangTidyFilePath)) File.Delete(clangTidyFilePath); } public void Remove(List mDirectoriesPath) { foreach (var directoryPath in mDirectoriesPath) Remove(directoryPath); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/DocumentHandler.cs ================================================ using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace ClangPowerTools { public class DocumentHandler { #region Public Methods /// /// Get active documents /// /// Active documents public static Documents GetActiveDocuments() { return VsServiceProvider.TryGetService(typeof(DTE2), out object dte) ? (dte as DTE2).Documents : null; } /// /// Get a list of active documents /// /// public static List GetListOfActiveDocuments() { List documents = new List(); foreach (var item in GetActiveDocuments()) { documents.Add(item as Document); } return documents; } /// /// Get the active document /// /// Active document public static Document GetActiveDocument() { return VsServiceProvider.TryGetService(typeof(DTE2), out object dte) ? (dte as DTE2).ActiveDocument : null; } /// /// Get the elected items /// /// public static SelectedItems GetSelectedItems() { var vsServiceProvider = VsServiceProvider.TryGetService(typeof(DTE2), out object dte) ? (dte as DTE2) : null; return vsServiceProvider.SelectedItems; } /// /// Save all the active documents /// public static void SaveActiveDocuments() { try { GetActiveDocuments().SaveAll(); } catch (System.Exception) { CommandControllerInstance.CommandController.DisplayMessage(false, "Cannot get all active documents, close all tabs and try again"); } } /// /// Check if a document is open /// /// /// True if the document is open, false otherwise public static bool IsOpen(Document aSearchedDocument, List aDocuments) { Document doc = aDocuments.FirstOrDefault(currentDoc => currentDoc.FullName == aSearchedDocument.FullName); return doc != null; } public static void FocusActiveDocument() { var document = GetActiveDocument(); if (document == null) return; document.Activate(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/FileSystem.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Windows.Forms; namespace ClangPowerTools.Helpers { public static class FileSystem { #region Properties public static List ConfigClangFormatFileTypes = new List { ".clang-format", "_clang-format" }; public static string ConfigClangTidyFileName { get; } = ".clang-tidy"; #endregion #region Methods public static bool SearchAllTopDirectories(string filePath, IEnumerable searchedFiles) { while (string.IsNullOrEmpty(filePath) == false) { foreach (var file in searchedFiles) { if (DoesFileExist(filePath, file)) return true; } var index = filePath.LastIndexOf("\\"); if (index > 0) filePath = filePath.Remove(index); else return false; } return false; } public static void CreateDirectory(string path) { if (Directory.Exists(path) == false) Directory.CreateDirectory(path); } public static void DeleteDirectory(string path) { if (Directory.Exists(path)) { try { Directory.Delete(path, true); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } public static void DeleteFile(string path) { if (File.Exists(path)) { try { File.Delete(path); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } public static bool DoesFileExist(string path, string fileName) { var filePath = string.Concat(path, "\\", fileName); return File.Exists(filePath); } public static void WriteContentToFile(string path, string content) { using FileStream fs = new FileStream(path, FileMode.Create); using StreamWriter sw = new StreamWriter(fs); sw.Write(content); } public static string ReadContentFromFile(string path) { if (File.Exists(path)) { return File.ReadAllText(path); } return string.Empty; } public static string ReadContentFromFile(string path, string wantedLineEnding) { if (File.Exists(path)) { var sb = new StringBuilder(); using var sr = new StreamReader(path); while (sr.Peek() >= 0) { string line = sr.ReadLine(); sb.Append(line).Append(wantedLineEnding); } return sb.ToString(); } return string.Empty; } public static List ReadContentFromMultipleFiles(List filePaths, string wantedLineEnding) { var filesContent = new List(); foreach (var path in filePaths) { var content = ReadContentFromFile(path, wantedLineEnding); if (string.IsNullOrWhiteSpace(content)) { continue; } filesContent.Add(content); } return filesContent; } public static string CreateFullFileName(string path, string fileName) { return string.Concat(path, "\\", fileName); } public static void MoveFile(string sourceFileName, string destFileName) { if (File.Exists(destFileName)) { File.Delete(destFileName); } File.Move(sourceFileName, destFileName); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/FormatEditorUtility.cs ================================================ using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Windows; namespace ClangPowerTools.Helpers { public static class FormatEditorUtility { #region Methods public static void OpenBrowser() { try { Process.Start(FormatEditorConstants.FrameworkdUrlDownload); } catch (Exception e) { MessageBox.Show(e.Message, "Clang-Format Error", MessageBoxButton.OK, MessageBoxImage.Error); } } public static bool FrameworkInstalled() { if (Directory.Exists(FormatEditorConstants.FrameworkPath)) { var directories = Directory.GetDirectories(FormatEditorConstants.FrameworkPath) .Select(Path.GetFileName) .ToArray(); foreach (var directory in directories) { if (directory.StartsWith("5.")) return true; } } return false; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/GenerateDocumentation.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Text.RegularExpressions; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.Helpers { public static class GenerateDocumentation { public static string OutputDir { get; set; } = string.Empty; public static EventHandler ExitedHandler { get; set; } public static Dictionary Formats = new Dictionary() { {534, "yaml" }, {278, "html" }, {294, "md" } }; /// /// Find a name for output documentation folder /// public static string FindOutputFolderName(string outputPath) { while (Directory.Exists(outputPath)) { //Get number from folder path FileInfo fileInfo = new FileInfo(outputPath); var resultString = Regex.Match(fileInfo.Directory.Name, @"\d+").Value; if (resultString != string.Empty) { var resultNumber = Int32.Parse(resultString); //Increment number and replace in foder path ++resultNumber; var resultFolderName = fileInfo.Directory.Name.Replace(resultString, resultNumber.ToString()); outputPath = outputPath.Replace(fileInfo.Directory.Name, resultFolderName); } else { //Start folder count from 1, by adding 1 to final var resultFolderName = fileInfo.Directory.Name + " (1)"; outputPath = outputPath.Replace(fileInfo.Directory.Name, resultFolderName); } } //Delete last two charachers (\\) from end return outputPath.Remove(outputPath.Length - 1, 1); } public static void DisplayInfoMessage(string outputPath) { CommandControllerInstance.CommandController.DisplayMessage(false, $"Generated Documentation at path: {outputPath}"); } public static void ClosedDataConnection(object sender, EventArgs e) { int id = CommandControllerInstance.CommandController.GetCurrentCommandId(); if (Formats.ContainsKey(id)) { OpenInFileExplorer(OutputDir); DisplayInfoMessage(OutputDir); } } public static void OpenInFileExplorer(string path) { if (!Directory.Exists(path)) return; // combine the arguments together // it doesn't matter if there is a space after ',' string argument = " \"" + path + "\""; // open the file in File Explorer and select it Process.Start("explorer.exe", argument); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/JoinUtility.cs ================================================ using ClangPowerToolsShared.MVVM.Models.ToolWindowModels; using EnvDTE; namespace ClangPowerTools.Helpers { public static class JoinUtility { public static string Join(string separator, params string[] text) { return string.Join(separator, text); } //Add matcher keyword if is needed public static string AddMatcherKeyword(string matcher) { if ((matcher.Length > 0 && matcher[0] == 'm')) { return matcher; } else { return "m " + matcher; } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/LaunchCompilationDbProgrammatically.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Constants; using System.IO; using System.Threading.Tasks; using MenuItem = ClangPowerToolsShared.Commands.MenuItem; namespace ClangPowerToolsShared.Helpers { internal class LaunchCompilationDbProgrammatically { private string lastHash = string.Empty; private MenuItem lastSelectedMenuOption = new(); private string mActiveDocumentName = string.Empty; /// /// Before launching compilation database programmatically, you need to check selected option from menu /// /// public async Task FromFindToolWindowAsync() { string currentHash = string.Empty; if(File.Exists(PathConstants.VcxprojPath)) { currentHash = (File.ReadAllText(PathConstants.VcxprojPath)).GetHashCode().ToString(); } var selectedItem = LookInMenuController.GetSelectedMenuItem(); bool sameActiveDocument = true; if (DocumentHandler.GetActiveDocument()?.FullName != mActiveDocumentName && selectedItem.LookInMenu == LookInMenu.CurrentActiveDocument) { sameActiveDocument = false; mActiveDocumentName = DocumentHandler.GetActiveDocument()?.FullName; } //Generate again compilation database on project, document, or files modifications if ((lastSelectedMenuOption == selectedItem && lastHash == currentHash && selectedItem.LookInMenu == LookInMenu.EntireSolution) || (selectedItem.LookInMenu == LookInMenu.CurrentActiveDocument && sameActiveDocument)) { return; } else if (lastHash != currentHash || string.IsNullOrEmpty(lastHash) || lastSelectedMenuOption != LookInMenuController.GetSelectedMenuItem()) { lastHash = currentHash; lastSelectedMenuOption = LookInMenuController.GetSelectedMenuItem(); } await CommandControllerInstance.CommandController.LaunchCommandAsync(CommandIds.kJsonCompilationDatabase, CommandUILocation.ViewMenu, null, false); } public async Task FromGenerateDocumentationAsync() { await CommandControllerInstance.CommandController.LaunchCommandAsync(CommandIds.kJsonCompilationDatabase, CommandUILocation.ContextMenu, null, false); } public async Task FromOptimizeIncludesAsync() { ///generate compilation database here, before setting the CommandId with OptimizeIncludesId await CommandControllerInstance.CommandController.LaunchCommandAsync(aCommandId: CommandIds.kJsonCompilationDatabase, aCommandUILocation: CommandUILocation.ContextMenu, openCompilationDatabaseInExplorer: false); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ManageEncoding.cs ================================================ using System.IO; using System.Text; namespace ClangPowerToolsShared.Helpers { public class ManageEncoding { //change encoding from utf8 BOM to utf8 public static void ChangeEncodingFromBomToUtf8(string inputFile, string outputFile) { using (StreamReader reader = new StreamReader(inputFile, Encoding.UTF8, true)) { string content = reader.ReadToEnd(); using (StreamWriter writer = new StreamWriter(outputFile, false, new UTF8Encoding(false))) { writer.Write(content); } } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/NetworkUtility.cs ================================================ using System; using System.Net.Http; using System.Threading.Tasks; namespace ClangPowerTools.Helpers { public class NetworkUtility { public static async Task CheckInternetConnectionAsync() { ApiUtility.InitializeApiClient(); try { using HttpResponseMessage result = await ApiUtility.ApiClient.GetAsync("https://www.google.com"); return result != null; } catch (Exception) { return false; } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/PCHCleaner.cs ================================================ using System.IO; namespace ClangPowerTools { public class PCHCleaner { #region Members private const string kPchExtension = ".clang.pch"; #endregion #region Public Methods /// /// Delete all PCH files with ".clang.pch" extension found in folder "aPath" from the disk /// /// Folder path from where the PCH fils will be deleted public void Remove(string aFolderPath) { if (!Directory.Exists(aFolderPath)) return; var pchPaths = Directory.GetFiles(aFolderPath, $"*{kPchExtension}"); foreach (var path in pchPaths) File.Delete(path); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/PackageUtility.cs ================================================ using System.IO; using System.Linq; using System.Reflection; using System.Xml; namespace ClangPowerTools.Helpers { public class PackageUtility { public static string GetVersion() { var assemblyPath = Assembly.GetExecutingAssembly().Location; assemblyPath = assemblyPath.Substring(0, assemblyPath.LastIndexOf('\\')); var manifestPath = Path.Combine(assemblyPath, "extension.vsixmanifest"); if (!File.Exists(manifestPath)) return string.Empty; var doc = new XmlDocument(); doc.Load(manifestPath); var metaData = doc.DocumentElement.ChildNodes.Cast().First(x => x.Name == "Metadata"); var identity = metaData.ChildNodes.Cast().First(x => x.Name == "Identity"); return identity.GetAttribute("Version"); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ProjectConfigurationHandler.cs ================================================ using EnvDTE; namespace ClangPowerTools { public class ProjectConfigurationHandler { #region Public Methods public static string GetPlatform(Project aProject) { var succes = GetActiveConfiguration(aProject, out Configuration configuration); if (false == succes) return string.Empty; return configuration.PlatformName; } public static string GetConfiguration(Project aProject) { var succes = GetActiveConfiguration(aProject, out Configuration configuration); if (false == succes) return string.Empty; return configuration.ConfigurationName; } #endregion #region Private Methods private static bool GetActiveConfiguration(Project aProject, out Configuration aConfiguration) { aConfiguration = null; var configurationManager = aProject.ConfigurationManager; if (null == configurationManager) return false; aConfiguration = configurationManager.ActiveConfiguration; if (null == aConfiguration) return false; return true; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/PropertyHandler.cs ================================================ using System; using System.Reflection; namespace ClangPowerTools.Helpers { public static class PropertyHandler { /// /// Method get values of specified property of an object /// and the property names are available through PropertyInfo.Name property /// /// template /// the object that contains the property you want to get /// the name of the property you are trying to get /// public static object Get(object obj, string propertyName) => typeof(T).GetProperty(propertyName)?.GetValue(obj); /// /// Method set values of specified property of an object /// /// the object that contains the property you want to set /// /// the name of the property you are trying to set public static void Set(object obj, string propertyName, object value) { PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName); propertyInfo?.SetValue(obj, Convert.ChangeType(value, propertyInfo.PropertyType), null); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/RegistryUtility.cs ================================================ using System; namespace ClangPowerTools.Helpers { public class RegistryUtility { #region MyRegion private readonly string registryName; #endregion #region Constructor public RegistryUtility(string registryName) => this.registryName = registryName; #endregion #region Public Methods public string ReadLocalMachineKey(string keyName) { try { using var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(registryName); if (key == null) return null; var keyValue = key.GetValue(keyName).ToString(); return keyValue; } catch (Exception) { return null; } } public string ReadCurrentUserKey(string keyName) { try { using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(registryName); if (key == null) return null; var keyValue = key.GetValue(keyName)?.ToString(); return keyValue; } catch (Exception) { return null; } } public bool WriteCurrentUserKey(string keyName, string keyValue) { try { using var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(registryName); key.SetValue(keyName, keyValue); return true; } catch (Exception) { return false; } } public bool Exists() => Microsoft.Win32.Registry.CurrentUser.OpenSubKey(registryName) != null; public bool DeleteCurrentUserKey(string keyName) { try { using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(registryName, true); if (key == null) return false; key.DeleteValue(keyName); return true; } catch (Exception) { return false; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/RunningDocTableEvents.cs ================================================ using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.IO; using System.Linq; using System.Windows.Forms; namespace ClangPowerTools { public class RunningDocTableEvents : IVsRunningDocTableEvents3 { #region Members private RunningDocumentTable mRunningDocumentTable; public delegate void OnBeforeSaveHandler(object sender, Document document); public delegate void OnBeforeActiveDocumentChange(object sender, Document document); public event OnBeforeSaveHandler BeforeSave; public event OnBeforeActiveDocumentChange BeforeActiveDocumentChange; #endregion #region Constructor public RunningDocTableEvents(Package aPackage) { try { mRunningDocumentTable = new RunningDocumentTable(aPackage); mRunningDocumentTable.Advise(this); } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } #endregion #region IVsRunningDocTableEvents3 implementation public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) { return VSConstants.S_OK; } public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew) { return VSConstants.S_OK; } public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) { return VSConstants.S_OK; } public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) { return VSConstants.S_OK; } public int OnAfterSave(uint docCookie) { return VSConstants.S_OK; } public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) { if (fFirstShow == 0) return VSConstants.S_OK; if (null == BeforeActiveDocumentChange) return VSConstants.S_OK; var document = FindDocument(docCookie); if (null == document) return VSConstants.S_OK; BeforeActiveDocumentChange(this, document); return VSConstants.S_OK; } public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) { return VSConstants.S_OK; } public int OnBeforeSave(uint docCookie) { try { if (null == BeforeSave) return VSConstants.S_OK; var document = FindDocument(docCookie); if (null == document) return VSConstants.S_OK; bool acceptedExtension = ScriptConstants.kExtendedAcceptedFileExtensions.Contains(Path.GetExtension(document.Name)); if (acceptedExtension == false) return VSConstants.S_OK; BeforeSave(this, document); } catch (Exception e) { MessageBox.Show("Error while running clang command on save. " + e.Message, "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Error); } return VSConstants.S_OK; } #endregion #region Private Methods private Document FindDocument(uint docCookie) { Document document = null; try { document = DocumentHandler.GetActiveDocument(); } catch (Exception) { CommandControllerInstance.CommandController.DisplayMessage(false, "Cannot find active document, close all tabs and try again"); } return document; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/ScriptGenerator.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Script; using ClangPowerToolsShared.Commands.Models; using System.Collections.Generic; using System.IO; using System.Text; namespace ClangPowerTools.Helpers { public static class ScriptGenerator { #region Methods public static string GetRunModeParamaters() { IBuilder runModeScriptBuilder = new RunModeScriptBuilder(); runModeScriptBuilder.Build(); var runModeParameters = runModeScriptBuilder.GetResult(); return runModeParameters; } public static string GetGenericParamaters(int aCommandId, string vsEdition, string vsVersion, bool jsonCompilationDbActive) { IBuilder genericScriptBuilder = new GenericScriptBuilder(vsEdition, vsVersion, aCommandId, jsonCompilationDbActive); genericScriptBuilder.Build(); var genericParameters = genericScriptBuilder.GetResult(); return genericParameters; } public static string GetItemRelatedParametersCustomPaths(List filePaths, CacheProjectsItemsModel cacheProjectsItemsModel) { if (filePaths.Count > 0 && ScriptConstants.kProjectFileExtension == (Path.GetExtension(filePaths[0]))) { return GetProjectRelatedParameters(cacheProjectsItemsModel); } var tokens = new List(); if (cacheProjectsItemsModel.ProjectsStringList != null && cacheProjectsItemsModel.ProjectsStringList.Count > 0) tokens.Add($"{ScriptConstants.kProject} {JoinPathsToStringScript(cacheProjectsItemsModel.ProjectsStringList)}"); tokens.Add($"{ScriptConstants.kFile} {JoinPathsToStringScript(filePaths)}"); if(!string.IsNullOrEmpty(cacheProjectsItemsModel.Configuration) && !string.IsNullOrEmpty(cacheProjectsItemsModel.Platform)) tokens.Add($"{ScriptConstants.kActiveConfiguration} '{cacheProjectsItemsModel.Configuration}|{cacheProjectsItemsModel.Platform}'"); return string.Join(" ", tokens); } public static string GetProjectRelatedParameters(CacheProjectsItemsModel cacheProjectsItemsModel) { var tokens = new List(); if (cacheProjectsItemsModel.ProjectsStringList != null && cacheProjectsItemsModel.ProjectsStringList.Count > 0) tokens.Add($"{ScriptConstants.kProject} {JoinPathsToStringScript(cacheProjectsItemsModel.ProjectsStringList)}"); if (!string.IsNullOrEmpty(cacheProjectsItemsModel.Configuration) && !string.IsNullOrEmpty(cacheProjectsItemsModel.Platform)) tokens.Add($"{ScriptConstants.kActiveConfiguration} '{cacheProjectsItemsModel.Configuration}|{cacheProjectsItemsModel.Platform}'"); return string.Join(" ", tokens); } public static string JoinPathsToStringScript(List paths) { StringBuilder stringBuilder = new StringBuilder("('"); foreach (string path in paths) { stringBuilder.Append(path).Append("','"); } stringBuilder.Remove(stringBuilder.Length - 2, 2); return stringBuilder.Append(")").ToString(); } public static string GetItemRelatedParameters(IItem item, bool jsonCompilationDbActive = false) { IBuilder itemRelatedScriptBuilder = new ItemRelatedScriptBuilder(item, jsonCompilationDbActive); itemRelatedScriptBuilder.Build(); var itemRelatedParameters = itemRelatedScriptBuilder.GetResult(); return itemRelatedParameters; } public static string GetItemRelatedParameters(List items, bool jsonCompilationDbActive = false) { IBuilder itemRelatedScriptBuilder = new ItemRelatedScriptBuilder(items, jsonCompilationDbActive); itemRelatedScriptBuilder.Build(); var itemRelatedParameters = itemRelatedScriptBuilder.GetResult(); return itemRelatedParameters; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/SettingsApi.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.LicenseValidation; using ClangPowerTools.MVVM.WebApi; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; namespace ClangPowerTools { public class SettingsApi { #region Constructor public SettingsApi() { ApiUtility.InitializeApiClient(); } #endregion #region Public Methods public async Task UploadSettingsAsync() { if (await NetworkUtility.CheckInternetConnectionAsync() == false) return; var settingsHandler = new SettingsHandler(); string json = settingsHandler.GetSettingsAsJson(); await PostSettingsAsync(json); } public async Task DownloadSettingsAsync() { if (await NetworkUtility.CheckInternetConnectionAsync() == false) return; HttpResponseMessage httpResponseMessage = await GetSettingsAsync(); if (httpResponseMessage.IsSuccessStatusCode) { var settingsHandler = new SettingsHandler(); string json = await httpResponseMessage.Content.ReadAsStringAsync(); settingsHandler.LoadCloudSettings(json); } } public async Task CloudSaveExistsAsync() { if (await NetworkUtility.CheckInternetConnectionAsync() == false) return false; HttpResponseMessage httpResponseMessage = await GetSettingsAsync(); if (httpResponseMessage.IsSuccessStatusCode) { return true; } return false; } public async Task GetUserProfileJsonAsync() { HttpResponseMessage httpResponseMessage = await GetUserProfileDetailsAsync(); if (!httpResponseMessage.IsSuccessStatusCode) return null; return await httpResponseMessage.Content.ReadAsStringAsync(); } public async Task GetLicenseDetailsJsonAsync() { HttpResponseMessage httpResponseMessage = await GetLicenseDetailsAsync(); if (!httpResponseMessage.IsSuccessStatusCode) return null; return await httpResponseMessage.Content.ReadAsStringAsync(); } #endregion #region Private Methods private async Task PostSettingsAsync(string settingsJson) { SetAuthenticationHeader(); using StringContent content = new StringContent(settingsJson, Encoding.UTF8, "application/json"); return await ApiUtility.ApiClient.PostAsync(WebApiUrl.settingsConfig, content); } private async Task GetSettingsAsync() { SetAuthenticationHeader(); return await ApiUtility.ApiClient.GetAsync(WebApiUrl.settingsConfig); } private async Task GetUserProfileDetailsAsync() { SetAuthenticationHeader(); return await ApiUtility.ApiClient.GetAsync(WebApiUrl.userProfile); } private async Task GetLicenseDetailsAsync() { SetAuthenticationHeader(); return await ApiUtility.ApiClient.GetAsync(WebApiUrl.licenseUrl); } private static void SetAuthenticationHeader() { var token = new Token(); token.GetToken(out string jwt); ApiUtility.ApiClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/SettingsPathBuilder.cs ================================================ using System; using System.IO; namespace ClangPowerTools { public class SettingsPathBuilder { #region Constants private const string folderName = "ClangPowerTools"; private const string llvm = "LLVM"; private const string binFolder = "bin"; private const string fileExtension = ".exe"; #endregion #region Methods Public public string GetPath(string aFileName) => Path.Combine(GetFolderPath(), aFileName); public string GetLlvmPath(string version) { var appdDataPath = GetPath(""); var folderName = string.Concat(llvm, version); return Path.Combine(appdDataPath, llvm, folderName); } public string GetLlvmBinPath(string version) { var path = GetLlvmPath(version); return Path.Combine(path, binFolder); } public string GetCurrentExecutableLlvmPath() { var llvmSetPath = SettingsProvider.LlvmSettingsModel.PreinstalledLlvmPath; if (llvmSetPath == "") { return GetLlvmExecutablePath(SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion, "bin\\clang-tidy"); } else { return Path.Combine(llvmSetPath, "clang-tidy.exe"); } } public string GetLlvmExecutablePath(string version, string executableName) { var path = GetLlvmPath(version); var executable = string.Concat(executableName, fileExtension); return Path.Combine(path, executable); } public string GetAssemblyLocalPath() { return System.Reflection.Assembly.GetExecutingAssembly().Location; } #endregion #region Private Methods private string GetFolderPath() { string folderPath = Path.Combine (Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), folderName); if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath); return folderPath; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/SolutionInfo.cs ================================================ using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Shell.Interop; using System.Collections.Generic; using System.IO; namespace ClangPowerTools.Helpers { public static class SolutionInfo { #region Properties public static bool SolutionOpen { get; set; } public static bool OpenFolderModeActive { get; set; } #endregion #region Public Methods /// /// Returns the required solution file information. /// /// Pointer to the solution directory /// Pointer to the solution file name /// Pointer to the solutions options file name /// If the method succeeds, it returns Microsoft.VisualStudio.VSConstants.S_OK. If it fails, it returns an error code. public static int GetSolutionInfo(out string dir, out string file, out string optionFile) { var solution = (IVsSolution)VsServiceProvider.GetService(typeof(SVsSolution)); return solution.GetSolutionInfo(out dir, out file, out optionFile); } /// /// Check if any VS Solution is open /// /// True if any VS Solution is open. False otherwise. public static bool IsSolutionOpen() { var solution = (IVsSolution)VsServiceProvider.GetService(typeof(SVsSolution)); solution.GetProperty((int)__VSPROPID.VSPROPID_IsSolutionOpen, out object open); SolutionOpen = (bool)open; return SolutionOpen; } /// /// Check if VS runs in Open Folder Mode /// /// True if VS runs in Open Folder Mode. False otherwise. public static bool IsOpenFolderModeActive() { var solution = (IVsSolution)VsServiceProvider.GetService(typeof(SVsSolution)); solution.GetProperty((int)__VSPROPID7.VSPROPID_IsInOpenFolderMode, out object folderMode); OpenFolderModeActive = folderMode == null ? false : (bool)folderMode; return OpenFolderModeActive; } public static bool ContainsCppProject() { DTE2 dte = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); Solution solution = dte.Solution; if (solution == null) { return false; } return AnyCppProject(solution); } public static bool AnyCppProject(Solution solution) { foreach (var project in solution) { if (IsCppProject((Project)project)) { return true; } } return false; } public static bool IsCppProject(Project project) { return project.Kind.Equals(ScriptConstants.kCppProjectGuid); } public static bool AreContextMenuCommandsEnabled() { if (IsOpenFolderModeActive()) { return true; } ItemsCollector itemCollector = new ItemsCollector(); itemCollector.CollectSelectedItems(); List selectedItems = new List(); if (itemCollector.IsEmpty) return false; itemCollector.Items.ForEach(e => selectedItems.Add(e.GetName())); if (selectedItems.Count == 0) { return false; } foreach (var item in selectedItems) { var fileExtension = Path.GetExtension(item).ToLower(); if (ScriptConstants.kAcceptedFileExtensions.Contains(fileExtension)) { return true; } } return false; } public static bool AreToolbarCommandsEnabled() { if (IsOpenFolderModeActive()) return true; ItemsCollector itemCollector = new ItemsCollector(); itemCollector.CollectActiveProjectItem(); if (itemCollector.IsEmpty) return false; string activeItem = itemCollector.Items[0]?.GetName().ToLower(); var fileExtension = Path.GetExtension(activeItem); return ScriptConstants.kAcceptedFileExtensionsWithoutHeaders.Contains(fileExtension); } public static bool ActiveDocumentValidation() { var document = DocumentHandler.GetActiveDocument(); if (document == null || string.IsNullOrWhiteSpace(document.FullName)) return false; var extensionDocument = Path.GetExtension(document.FullName); return ScriptConstants.kExtendedAcceptedFileExtensions.Contains(extensionDocument); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/StatusBarHandler.cs ================================================ using ClangPowerTools.Handlers; using ClangPowerTools.Services; using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; namespace ClangPowerTools { public class StatusBarHandler { #region Public Methods public static void Text(string aText, int aFreezeStatusBar) { if (!VsServiceProvider.TryGetService(typeof(SVsStatusbar), out object statusBarService) || null == statusBarService as IVsStatusbar) return; var statusBar = statusBarService as IVsStatusbar; // Make sure the status bar is not frozen if (VSConstants.S_OK != statusBar.IsFrozen(out int frozen)) return; UIUpdater.InvokeAsync(() => { if (0 != frozen) statusBar.FreezeOutput(0); // Set the status bar text statusBar.SetText(aText); // Freeze the status bar. statusBar.FreezeOutput(aFreezeStatusBar); // Clear the status bar text. if (0 == aFreezeStatusBar) statusBar.Clear(); }).SafeFireAndForget(); } public static void Animation(vsStatusAnimation aAnimation, int aEnableAnimation) { if (!VsServiceProvider.TryGetService(typeof(SVsStatusbar), out object statusBarService) || null == statusBarService as IVsStatusbar) return; var statusBar = statusBarService as IVsStatusbar; // Use the standard Visual Studio icon for building. object icon = (short)Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Build; UIUpdater.InvokeAsync(() => { // Display the icon in the Animation region. statusBar.Animation(aEnableAnimation, ref icon); }).SafeFireAndForget(); } public static void Status(string aText, int aFreezeStatusBar, vsStatusAnimation aAnimation, int aEnableAnimation) { Text(aText, aFreezeStatusBar); Animation(aAnimation, aEnableAnimation); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/UIUpdater.cs ================================================ using Microsoft.VisualStudio.Shell; using System; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Handlers { public class UIUpdater { #region Public Methods public static void BeginInvoke(Action aAction) { aAction.BeginInvoke(aAction.EndInvoke, null); } public async static Task InvokeAsync(Action aAction) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); aAction.Invoke(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/VsWindowController.cs ================================================ using EnvDTE; namespace ClangPowerTools.Helpers { /// /// Contains the logic of managing Visual Studio window objects type /// public static class VsWindowController { #region Members /// /// Get the previouse focused window from Visual Studio /// public static Window PreviousWindow { get; private set; } #endregion #region Methods /// /// Set the previouse focused window from Visual Studio /// /// public static void SetPreviousActiveWindow(Window previousWindow) => PreviousWindow = previousWindow; /// /// Moves the focus to the current item /// /// The window which will be focused public static void Activate(Window window) { if (PreviousWindow == null) return; window.Activate(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Helpers/Vsix.cs ================================================ using EnvDTE; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; using System; using System.IO; namespace ClangPowerTools { public class Vsix { /// /// Returns the currently active view if it is a IWpfTextView. /// public static IWpfTextView GetCurrentView() { // The SVsTextManager is a service through which we can get the active view. var textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager)); IVsTextView textView; textManager.GetActiveView(1, null, out textView); // Now we have the active view as IVsTextView, but the text interfaces we need // are in the IWpfTextView. return VsToWpfTextView(textView); } public static bool IsDocumentDirty(Document document) { var textView = GetDocumentView(document); var textDocument = GetTextDocument(textView); return textDocument?.IsDirty == true; } public static IWpfTextView GetDocumentView(Document document) { var textView = GetVsTextViewFrompPath(document.FullName); return VsToWpfTextView(textView); } public static IWpfTextView VsToWpfTextView(IVsTextView textView) { var userData = (IVsUserData)textView; if (userData == null) return null; Guid guidWpfViewHost = DefGuidList.guidIWpfTextViewHost; object host; userData.GetData(ref guidWpfViewHost, out host); return ((IWpfTextViewHost)host).TextView; } public static IVsTextView GetVsTextViewFrompPath(string filePath) { var dte2 = (EnvDTE80.DTE2)Package.GetGlobalService(typeof(SDTE)); var sp = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte2; var serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(sp); IVsUIHierarchy uiHierarchy; uint itemID; IVsWindowFrame windowFrame; if (VsShellUtilities.IsDocumentOpen(serviceProvider, filePath, Guid.Empty, out uiHierarchy, out itemID, out windowFrame)) { // Get the IVsTextView from the windowFrame. return VsShellUtilities.GetTextView(windowFrame); } return null; } public static ITextDocument GetTextDocument(IWpfTextView view) { ITextDocument document = null; if (view != null && view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document)) return document; return null; } public static string GetDocumentParent(IWpfTextView view) { ITextDocument document = GetTextDocument(view); if (document != null) { return Directory.GetParent(document.FilePath).ToString(); } return null; } public static string GetDocumentPath(IWpfTextView view) { return GetTextDocument(view)?.FilePath; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/IgnoreActions/IgnoreItem.cs ================================================ using EnvDTE; using System; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools.IgnoreActions { /// /// Logic for all the ignore actions types on any abject /// public class IgnoreItem { #region Members /// /// Message to display if the checked file /// is on the ignore list after a clang compile/tidy command /// private string ignoreCompileOrTidyMessage; /// /// Message to display if the checked file /// is on the ignore list after a clang-format command /// private string ignoreFormatMessage; #endregion #region Properties /// /// Message for the ignored files for clang compile/tidy /// The value is null if the proper check wasn't executed before. /// public string IgnoreCompileOrTidyMessage { get { return ignoreCompileOrTidyMessage; } private set { ignoreCompileOrTidyMessage = $"Cannot use clang compile/tidy on ignored files.\nTo enable clang compile/tidy remove the {value} from Clang Power Tools Settings -> Compiler -> Files/Projects to ignore."; } } /// /// Message for the ignored files for clang-format /// The value is null if the proper check wasn't executed before. /// public string IgnoreFormatMessage { get { return ignoreFormatMessage; } private set { ignoreFormatMessage = $"\nCannot use clang-format on ignored files.\nTo enable clang-format remove the \"{value}\" file from Clang Power Tools Settings -> Format -> Files to ignore."; } } #endregion #region Methods /// /// Check if the given parameter /// is on the clang compile/tidy ignore list /// /// Object to be checked /// True if the given parameter is on the clang compile/tidy ignore list. False otherwise public bool Check(IItem checkedItem, List paths = null) { if (checkedItem is CurrentProjectItem) { ProjectItem projectItem = checkedItem.GetObject() as ProjectItem; IgnoreCompileOrTidyMessage = $"\"{projectItem.Name}\" file"; return SettingsProvider.CompilerSettingsModel.FilesToIgnore.Contains(projectItem.Name); } else if (checkedItem is CurrentProject) { Project project = checkedItem.GetObject() as Project; IgnoreCompileOrTidyMessage = $"\"{project.Name}\" project"; return SettingsProvider.CompilerSettingsModel.ProjectsToIgnore.Contains(project.Name); } return false; } /// /// Check if the given parameter /// is on the clang compile/tidy ignore list /// /// Object to be checked /// True if the given parameter is on the clang-format ignore list. False otherwise public bool Check(Document checkedItem) { var skipFilesList = SettingsProvider.FormatSettingsModel.FilesToIgnore .ToLower() .Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); IgnoreFormatMessage = checkedItem.Name; return skipFilesList .Contains(checkedItem.Name.ToLower()); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/CurrentDocument.cs ================================================ using EnvDTE; namespace ClangPowerTools.Items { public class CurrentDocument : IItem { #region Members private Document mDocument; #endregion #region Constructor public CurrentDocument(Document aDocument) => mDocument = aDocument; #endregion #region IItem implementation public string GetName() => mDocument.Name; public object GetObject() => mDocument.Object(); public string GetPath() => mDocument.FullName; public void Save() => mDocument.Save(); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/CurrentProject.cs ================================================ using EnvDTE; namespace ClangPowerTools { public class CurrentProject : IItem { #region Members private Project mProject; #endregion #region Constructor public CurrentProject(Project aProject) => mProject = aProject; #endregion #region IItem implementation public string GetName() => mProject.FullName.Substring(mProject.FullName.LastIndexOf('\\') + 1); public string GetPath() => mProject.FullName; public object GetObject() => mProject; public void Save() => mProject.Save(mProject.FullName); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/CurrentProjectItem.cs ================================================ using EnvDTE; namespace ClangPowerTools { public class CurrentProjectItem : IItem { #region Members private ProjectItem mProjectItem; #endregion #region Constructor public CurrentProjectItem(ProjectItem aProjectItem) => mProjectItem = aProjectItem; #endregion #region IItem implementation public string GetName() => mProjectItem.Name; public string GetPath() => mProjectItem.Properties.Item("FullPath").Value.ToString(); public object GetObject() => mProjectItem; public void Save() => mProjectItem.Save(""); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/CurrentSolution.cs ================================================ using EnvDTE; namespace ClangPowerTools { class CurrentSolution : IItem { #region Members private readonly Solution solution; private readonly string saveAsPath = string.Empty; #endregion #region Constructor public CurrentSolution(Solution solution) => this.solution = solution; public CurrentSolution(Solution solution, string savePath) { this.solution = solution; saveAsPath = savePath; } #endregion public string GetName() => solution.FileName; public object GetObject() => solution; public string GetPath() => solution.FullName; public void Save() => solution.SaveAs(saveAsPath); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/IItem.cs ================================================ namespace ClangPowerTools { public interface IItem { string GetName(); string GetPath(); object GetObject(); void Save(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Items/ItemsCollector.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.Items; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using EnvDTE; using EnvDTE80; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; namespace ClangPowerTools { public class ItemsCollector { #region Members private readonly Array selectedItems; private readonly DTE2 dte2; private readonly bool jsonCompilationDbActive; #endregion #region Constructor public ItemsCollector(bool jsonCompilationActive = false) { dte2 = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); selectedItems = dte2.ToolWindows.SolutionExplorer.SelectedItems as Array; jsonCompilationDbActive = jsonCompilationActive; } #endregion #region Properties public List Items { get; set; } = new List(); public bool IsEmpty => Items.Count == 0; #endregion #region Public Methods public void SetItem(Document document) { if (document == null) return; var projectName = document.ProjectItem.ContainingProject.FullName; if (string.IsNullOrWhiteSpace(projectName)) return; IItem item = new CurrentProjectItem(document.ProjectItem); Items.Add(item); } public List CollectActiveProjectItem(bool saveInItems = true) { try { List items = new List(); var dte = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); if (dte == null) return items; Document activeDocument = null; try { activeDocument = dte.ActiveDocument; } catch (Exception) { return items; } if (activeDocument == null || activeDocument.ProjectItem == null) return items; IItem item = null; var projectName = activeDocument.ProjectItem.ContainingProject.FullName; if (SolutionInfo.IsOpenFolderModeActive()) { item = new CurrentDocument(activeDocument); } else if (string.IsNullOrWhiteSpace(projectName) == false) { item = new CurrentProjectItem(activeDocument.ProjectItem); } if (saveInItems) Items.Add(item); items.Add(item); return items; } catch (Exception e) { MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception(e.Message); } } /// /// Get the name of the active document /// public List GetFilesToIgnore() { CollectSelectedProjectItems(); List documentsToIgnore = new List(); Items.ForEach(e => documentsToIgnore.Add(e.GetName())); return documentsToIgnore; } public List GetProjectsToIgnore() { List projectsToIgnore = new List(); Array selectedItems = dte2.ToolWindows.SolutionExplorer.SelectedItems as Array; foreach (UIHierarchyItem item in selectedItems) { if (item.Object is Project) { var project = item.Object as Project; projectsToIgnore.Add(project?.Name); } } return projectsToIgnore; } /// /// Get selected files to encode /// public List GetDocumentsToEncode() { CollectCurrentProjectItems(); HashSet selectedFiles = new HashSet(); Items.ForEach(i => selectedFiles.Add(i.GetPath())); return selectedFiles.ToList(); } public bool SolutionOrProjectIsSelected() { if (selectedItems == null || selectedItems.Length == 0) return false; foreach (UIHierarchyItem item in selectedItems) { if (item.Object is Solution) { return true; } else if (item.Object is Project) { return true; } } return false; } /// /// Collect all selected items in the Solution explorer for commands /// /// public void CollectCustomItemsByPath(List customPath) { foreach (var path in customPath) { var item = dte2.ToolWindows.SolutionExplorer.GetItem(path); AddProjectItem(item.Object as ProjectItem); } } /// /// Collect project items based on look in menu from find tool window /// public void CollectProjectItems() { var dte2 = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); var selectedMenuItem = LookInMenuController.GetSelectedMenuItem(); try { switch (selectedMenuItem.LookInMenu) { case LookInMenu.EntireSolution: Items.Add(new CurrentSolution(dte2.Solution)); break; case LookInMenu.CurrentProject: List items = CollectActiveProjectItem(false); var projItem = items.First().GetObject() as ProjectItem; Items.Add(new CurrentProject(projItem.ContainingProject)); break; case LookInMenu.CurrentActiveDocument: CollectActiveProjectItem(); break; } } catch (Exception exception) { CommandControllerInstance.CommandController.DisplayMessage(false, "CPT Error: Can't collect ProjectItems from based on look in menu"); } } public void CollectSelectedItems() { if (selectedItems == null || selectedItems.Length == 0) return; foreach (UIHierarchyItem item in selectedItems) { if (item.Object is Solution) { var solution = item.Object as Solution; if (jsonCompilationDbActive) Items.Add(new CurrentSolution(solution)); else GetProjectsFromSolution(solution); } else if (item.Object is Project) { var project = item.Object as Project; AddProject(project); } else if (item.Object is ProjectItem) { GetProjectItem(item.Object as ProjectItem); } } } /// /// Collect all selected ProjectItems /// public void CollectSelectedProjectItems() { if (selectedItems == null || selectedItems.Length == 0) return; foreach (UIHierarchyItem item in selectedItems) { if (item.Object is Solution) { var solution = item.Object as Solution; GetProjectItem(solution); } else if (item.Object is Project) { var project = item.Object as Project; GetProjectItem(project); } else if (item.Object is ProjectItem) { GetProjectItem(item.Object as ProjectItem); } } } public void CollectCurrentProjectItems() { if (selectedItems == null || selectedItems.Length == 0) return; foreach (UIHierarchyItem item in selectedItems) { if (item.Object is Solution) { var solution = item.Object as Solution; GetProjectItem(solution); } else if (item.Object is Project) { var project = item.Object as Project; GetProjectItem(project); } else if (item.Object is ProjectItem) { Project project = (item.Object as ProjectItem).ContainingProject; GetProjectItem(project); return; } } } public void AddProjectItem(ProjectItem aItem) { if (aItem == null) return; var fileExtension = Path.GetExtension(aItem.Name).ToLower(); if (null != ScriptConstants.kAcceptedFileExtensions && false == ScriptConstants.kAcceptedFileExtensions.Contains(fileExtension)) return; Items.Add(new CurrentProjectItem(aItem)); } #endregion #region Private Methods private void GetProjectsFromSolution(Solution aSolution) { Items = AutomationUtil.GetAllProjects(aSolution); } private List GetResultProjectsFromSolution(Solution aSolution) { return AutomationUtil.GetAllProjects(aSolution); } private void AddProject(Project aProject) => Items.Add(new CurrentProject(aProject)); private void GetProjectItem(ProjectItem aProjectItem) { // Items that contains projects if (aProjectItem.ProjectItems == null) { if (aProjectItem.SubProject != null) AddProject(aProjectItem.SubProject); return; } // Folders or filters else if (aProjectItem.ProjectItems.Count != 0) { foreach (ProjectItem projItem in aProjectItem.ProjectItems) GetProjectItem(projItem); } // Files else { AddProjectItem(aProjectItem); } } private void GetProjectItem(Project aProject) { foreach (var item in aProject.ProjectItems) { var projectItem = item as ProjectItem; if (projectItem == null) continue; GetProjectItem(projectItem); } } private void GetProjectItem(Solution aSolution) { foreach (var item in AutomationUtil.GetAllProjects(aSolution)) { var project = (item as CurrentProject).GetObject() as Project; if (project == null) continue; GetProjectItem(project); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/.clang-format ================================================ # Format Style Options - Created with Clang Power Tools --- BasedOnStyle: WebKit AccessModifierOffset: -1 BreakBeforeBraces: Attach ColumnLimit: 140 IndentWidth: 2 NamespaceIndentation: All SpaceBeforeParens: Never ... ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/AutoCompleteHistory/ASTMatchers.cs ================================================ using ClangPowerToolsShared.MVVM.ViewModels; using System; using System.Collections.Generic; namespace ClangPowerToolsShared.MVVM.AutoCompleteHistory { public static class ASTMatchers { public static List AutoCompleteMatchers { get; } = new List { "attr()", "cxxBaseSpecifier()", "cxxCtorInitializer()", "accessSpecDecl()", "bindingDecl()", "blockDecl()", "classTemplateDecl()", "classTemplatePartialSpecializationDecl()", "classTemplateSpecializationDecl()", "cxxConstructorDecl()", "cxxConversionDecl()", "cxxDeductionGuideDecl()", "cxxDestructorDecl()", "cxxMethodDecl()", "cxxRecordDecl()", "decl()", "declaratorDecl()", "decompositionDecl()", "enumConstantDecl()", "enumDecl()", "fieldDecl()", "friendDecl()", "functionDecl()", "functionTemplateDecl()", "indirectFieldDecl()", "labelDecl()", "linkageSpecDecl()", "namedDecl()", "namespaceAliasDecl()", "namespaceDecl()", "nonTypeTemplateParmDecl()", "objcCategoryDecl()", "objcCategoryImplDecl()", "objcImplementationDecl()", "objcInterfaceDecl()", "objcIvarDecl()", "objcMethodDecl()", "objcPropertyDecl()", "objcProtocolDecl()", "parmVarDecl()", "recordDecl()", "staticAssertDecl()", "tagDecl()", "templateTemplateParmDecl()", "templateTypeParmDecl()", "translationUnitDecl()", "typeAliasDecl()", "typeAliasTemplateDecl()", "typedefDecl()", "typedefNameDecl()", "unresolvedUsingTypenameDecl()", "unresolvedUsingValueDecl()", "usingDecl()", "usingDirectiveDecl()", "usingEnumDecl()", "valueDecl()", "varDecl()", "lambdaCapture()", "nestedNameSpecifierLoc()", "nestedNameSpecifier()", "ompDefaultClause()", "qualType()", "addrLabelExpr()", "arraySubscriptExpr()", "asmStmt()", "atomicExpr()", "autoreleasePoolStmt()", "binaryConditionalOperator()", "binaryOperator()", "blockExpr()", "breakStmt()", "cStyleCastExpr()", "callExpr()", "caseStmt()", "castExpr()", "characterLiteral()", "chooseExpr()", "coawaitExpr()", "compoundLiteralExpr()", "compoundStmt()", "conditionalOperator()", "constantExpr()", "continueStmt()", "coreturnStmt()", "coyieldExpr()", "cudaKernelCallExpr()", "cxxBindTemporaryExpr()", "cxxBoolLiteral()", "cxxCatchStmt()", "cxxConstCastExpr()", "cxxConstructExpr()", "cxxDefaultArgExpr()", "cxxDeleteExpr()", "cxxDependentScopeMemberExpr()", "cxxDynamicCastExpr()", "cxxForRangeStmt()", "cxxFunctionalCastExpr()", "cxxMemberCallExpr()", "cxxNewExpr()", "cxxNoexceptExpr()", "cxxNullPtrLiteralExpr()", "cxxOperatorCallExpr()", "cxxReinterpretCastExpr()", "cxxRewrittenBinaryOperator()", "cxxStaticCastExpr()", "cxxStdInitializerListExpr()", "cxxTemporaryObjectExpr()", "cxxThisExpr()", "cxxThrowExpr()", "cxxTryStmt()", "cxxUnresolvedConstructExpr()", "declRefExpr()", "declStmt()", "defaultStmt()", "dependentCoawaitExpr()", "designatedInitExpr()", "doStmt()", "explicitCastExpr()", "expr()", "exprWithCleanups()", "fixedPointLiteral()", "floatLiteral()", "forStmt()", "genericSelectionExpr()", "gnuNullExpr()", "gotoStmt()", "ifStmt()", "imaginaryLiteral()", "implicitCastExpr()", "implicitValueInitExpr()", "initListExpr()", "integerLiteral()", "labelStmt()", "lambdaExpr()", "materializeTemporaryExpr()", "memberExpr()", "nullStmt()", "objcCatchStmt()", "objcFinallyStmt()", "objcIvarRefExpr()", "objcMessageExpr()", "objcStringLiteral()", "objcThrowStmt()", "objcTryStmt()", "ompExecutableDirective()", "opaqueValueExpr()", "parenExpr()", "parenListExpr()", "predefinedExpr()", "returnStmt()", "stmt()", "stmtExpr()", "stringLiteral()", "substNonTypeTemplateParmExpr()", "switchCase()", "switchStmt()", "unaryExprOrTypeTraitExpr()", "unaryOperator()", "unresolvedLookupExpr()", "unresolvedMemberExpr()", "userDefinedLiteral()", "whileStmt()", "templateArgumentLoc()", "templateArgument()", "templateName()", "elaboratedTypeLoc()", "pointerTypeLoc()", "qualifiedTypeLoc()", "referenceTypeLoc()", "templateSpecializationTypeLoc()", "typeLoc()", "arrayType()", "atomicType()", "autoType()", "blockPointerType()", "builtinType()", "complexType()", "constantArrayType()", "decayedType()", "decltypeType()", "deducedTemplateSpecializationType()", "dependentSizedArrayType()", "elaboratedType()", "enumType()", "functionProtoType()", "functionType()", "incompleteArrayType()", "injectedClassNameType()", "lValueReferenceType()", "memberPointerType()", "objcObjectPointerType()", "parenType()", "pointerType()", "rValueReferenceType()", "recordType()", "referenceType()", "substTemplateTypeParmType()", "tagType()", "templateSpecializationType()", "templateTypeParmType()", "type()", "typedefType()", "unaryTransformType()", "usingType()", "variableArrayType()", "allOf()", "anyOf()", "anything()", "unless()", "isImplicit()", "hasAnyOperatorName()", "hasOperatorName()", "isAssignmentOperator()", "isComparisonOperator()", "isPrivate()", "isProtected()", "isPublic()", "isVirtual()", "equals()", "equals()", "equals()", "equals()", "isCatchAll()", "argumentCountIs()", "isListInitialization()", "requiresZeroInitialization()", "isCopyConstructor()", "isDefaultConstructor()", "isDelegatingConstructor()", "isExplicit()", "isInheritingConstructor()", "isMoveConstructor()", "isExplicit()", "isBaseInitializer()", "isMemberInitializer()", "isWritten()", "isExplicit()", "hasMemberName()", "isArrow()", "memberHasSameNameAsBoundNode()", "isConst()", "isCopyAssignmentOperator()", "isFinal()", "isMoveAssignmentOperator()", "isOverride()", "isPure()", "isUserProvided()", "isVirtual()", "isVirtualAsWritten()", "isArray()", "hasAnyOperatorName()", "hasAnyOverloadedOperatorName()", "hasOperatorName()", "hasOverloadedOperatorName()", "isAssignmentOperator()", "isComparisonOperator()", "hasDefinition()", "isDerivedFrom()", "isDirectlyDerivedFrom()", "isExplicitTemplateSpecialization()", "isFinal()", "isLambda()", "isSameOrDerivedFrom()", "isTemplateInstantiation()", "hasAnyOperatorName()", "hasOperatorName()", "isAssignmentOperator()", "isComparisonOperator()", "argumentCountIs()", "argumentCountIs()", "usesADL()", "hasCastKind()", "equals()", "equals()", "equals()", "equals()", "templateArgumentCountIs()", "statementCountIs()", "hasSize()", "declCountIs()", "equalsBoundNode()", "equalsNode()", "hasAttr()", "isExpandedFromMacro()", "isExpansionInFileMatching()", "isExpansionInMainFile()", "isExpansionInSystemHeader()", "isImplicit()", "isInStdNamespace()", "isInstantiated()", "isPrivate()", "isProtected()", "isPublic()", "designatorCountIs()", "isScoped()", "isInstantiationDependent()", "isTypeDependent()", "isValueDependent()", "nullPointerConstant()", "hasBitWidth()", "isBitField()", "equals()", "equals()", "hasAnyOverloadedOperatorName()", "hasDynamicExceptionSpec()", "hasOverloadedOperatorName()", "hasTrailingReturn()", "isConsteval()", "isConstexpr()", "isDefaulted()", "isDefinition()", "isDeleted()", "isExplicitTemplateSpecialization()", "isExternC()", "isInline()", "isMain()", "isNoReturn()", "isNoThrow()", "isStaticStorageClass()", "isTemplateInstantiation()", "isVariadic()", "isWeak()", "parameterCountIs()", "hasDynamicExceptionSpec()", "isNoThrow()", "parameterCountIs()", "isConsteval()", "isConstexpr()", "equals()", "equals()", "equals()", "equals()", "capturesThis()", "isImplicit()", "isArrow()", "hasAnyName()", "hasExternalFormalLinkage()", "hasName()", "matchesName()", "isAnonymous()", "isInline()", "isFirstPrivateKind()", "isNoneKind()", "isPrivateKind()", "isSharedKind()", "isAllowedToContainClauseKind()", "isStandaloneDirective()", "isDerivedFrom()", "isDirectlyDerivedFrom()", "isSameOrDerivedFrom()", "argumentCountIs()", "hasAnySelector()", "hasKeywordSelector()", "hasNullSelector()", "hasSelector()", "hasUnarySelector()", "isClassMessage()", "isInstanceMessage()", "matchesSelector()", "numSelectorArgs()", "isClassMethod()", "isDefinition()", "isInstanceMethod()", "hasDefaultArgument()", "isAtPosition()", "asString()", "equalsBoundNode()", "hasLocalQualifiers()", "isAnyCharacter()", "isAnyPointer()", "isConstQualified()", "isInteger()", "isSignedInteger()", "isUnsignedInteger()", "isVolatileQualified()", "equalsBoundNode()", "equalsNode()", "isExpandedFromMacro()", "isExpansionInFileMatching()", "isExpansionInMainFile()", "isExpansionInSystemHeader()", "isInTemplateInstantiation()", "hasSize()", "isClass()", "isDefinition()", "isEnum()", "isStruct()", "isUnion()", "equalsIntegralValue()", "isIntegral()", "templateArgumentCountIs()", "isExpandedFromMacro()", "isExpansionInFileMatching()", "isExpansionInMainFile()", "isExpansionInSystemHeader()", "booleanType()", "equalsBoundNode()", "equalsNode()", "realFloatingPointType()", "voidType()", "ofKind()", "hasAnyOperatorName()", "hasOperatorName()", "isArrow()", "hasAutomaticStorageDuration()", "hasGlobalStorage()", "hasLocalStorage()", "hasStaticStorageDuration()", "hasThreadStorageDuration()", "isConstexpr()", "isConstinit()", "isDefinition()", "isExceptionVariable()", "isExplicitTemplateSpecialization()", "isExternC()", "isInitCapture()", "isInline()", "isStaticLocal()", "isStaticStorageClass()", "isTemplateInstantiation()", "binaryOperation()", "eachOf()", "findAll()", "forEachDescendant()", "forEach()", "hasAncestor()", "hasDescendant()", "has()", "hasParent()", "invocation()", "optionally()", "traverse()", "hasCondition()", "hasFalseExpression()", "hasTrueExpression()", "hasDeclaration()", "hasBase()", "hasIndex()", "hasLHS()", "hasRHS()", "hasElementType()", "hasValueType()", "hasDeducedType()", "hasAnyUsingShadowDecl()", "hasEitherOperand()", "hasLHS()", "hasOperands()", "hasRHS()", "forDecomposition()", "hasAnyParameter()", "hasParameter()", "hasTypeLoc()", "pointee()", "hasTypeLoc()", "hasType()", "hasType()", "forEachArgumentWithParam()", "forEachArgumentWithParamType()", "hasAnyArgument()", "hasArgument()", "hasDeclaration()", "forEachConstructorInitializer()", "hasAnyConstructorInitializer()", "forField()", "hasTypeLoc()", "withInitializer()", "hasObjectExpression()", "hasBody()", "hasInitStatement()", "hasLoopVariable()", "hasRangeInit()", "hasTypeLoc()", "onImplicitObjectArgument()", "on()", "thisPointerType()", "thisPointerType()", "forEachOverridden()", "ofClass()", "hasAnyPlacementArg()", "hasArraySize()", "hasDeclaration()", "hasPlacementArg()", "hasTypeLoc()", "hasEitherOperand()", "hasLHS()", "hasOperands()", "hasRHS()", "hasUnaryOperand()", "hasAnyBase()", "hasDirectBase()", "hasMethod()", "isDerivedFrom()", "isDirectlyDerivedFrom()", "isSameOrDerivedFrom()", "hasEitherOperand()", "hasLHS()", "hasOperands()", "hasRHS()", "hasTypeLoc()", "hasAnyArgument()", "hasArgument()", "hasTypeLoc()", "callee()", "callee()", "forEachArgumentWithParam()", "forEachArgumentWithParamType()", "hasAnyArgument()", "hasArgument()", "hasDeclaration()", "hasCaseConstant()", "hasSourceExpression()", "forEachTemplateArgument()", "hasAnyTemplateArgument()", "hasSpecializedTemplate()", "hasTemplateArgument()", "hasTypeLoc()", "hasElementType()", "hasTypeLoc()", "hasAnySubstatement()", "hasDecayedType()", "hasDeclaration()", "hasTemplateArgumentLoc()", "throughUsingDecl()", "to()", "containsDeclaration()", "hasSingleDecl()", "hasTypeLoc()", "hasDeclContext()", "hasUnderlyingType()", "hasAnyBinding()", "hasBinding()", "hasBody()", "hasCondition()", "hasNamedTypeLoc()", "hasQualifier()", "namesType()", "hasDeclaration()", "hasDestinationType()", "hasTypeLoc()", "hasType()", "hasType()", "ignoringElidableConstructorCall()", "ignoringImpCasts()", "ignoringImplicit()", "ignoringParenCasts()", "ignoringParenImpCasts()", "ignoringParens()", "hasInClassInitializer()", "hasBody()", "hasCondition()", "hasIncrement()", "hasLoopInit()", "hasType()", "hasType()", "forEachTemplateArgument()", "hasAnyBody()", "hasAnyParameter()", "hasAnyTemplateArgument()", "hasBody()", "hasExplicitSpecifier()", "hasParameter()", "hasReturnTypeLoc()", "hasTemplateArgument()", "returns()", "hasCondition()", "hasConditionVariableStatement()", "hasElse()", "hasInitStatement()", "hasThen()", "hasImplicitDestinationType()", "hasInit()", "hasSyntacticForm()", "hasDeclaration()", "hasDeclaration()", "capturesVar()", "forEachLambdaCapture()", "hasAnyCapture()", "hasDeclaration()", "hasObjectExpression()", "member()", "pointee()", "hasUnderlyingDecl()", "hasPrefix()", "loc()", "specifiesTypeLoc()", "hasPrefix()", "specifiesNamespace()", "specifiesType()", "hasAnyClause()", "hasStructuredBlock()", "isDerivedFrom()", "isDirectlyDerivedFrom()", "isSameOrDerivedFrom()", "callee()", "hasAnyArgument()", "hasArgument()", "hasReceiver()", "hasReceiverType()", "hasAnyParameter()", "hasParameter()", "hasTypeLoc()", "hasSourceExpression()", "hasAnyDeclaration()", "innerType()", "hasPointeeLoc()", "pointee()", "hasCanonicalType()", "hasDeclaration()", "ignoringParens()", "pointsTo()", "pointsTo()", "references()", "references()", "hasUnqualifiedLoc()", "hasDeclaration()", "hasReferentLoc()", "pointee()", "hasReturnValue()", "hasAnySubstatement()", "alignOfExpr()", "forCallable()", "forFunction()", "sizeOfExpr()", "hasReplacementType()", "forEachSwitchCase()", "hasCondition()", "hasInitStatement()", "hasDeclaration()", "hasTypeLoc()", "isExpr()", "refersToDeclaration()", "refersToIntegralType()", "refersToTemplate()", "refersToType()", "hasAnyTemplateArgumentLoc()", "hasTemplateArgumentLoc()", "forEachTemplateArgument()", "hasAnyTemplateArgument()", "hasDeclaration()", "hasTemplateArgument()", "hasDeclaration()", "loc()", "hasTypeLoc()", "hasType()", "hasDeclaration()", "hasUnqualifiedDesugaredType()", "hasArgumentOfType()", "hasUnaryOperand()", "hasObjectExpression()", "hasDeclaration()", "hasTargetDecl()", "hasUnderlyingType()", "throughUsingDecl()", "hasType()", "hasType()", "hasInitializer()", "hasSizeExpr()", "hasBody()", "hasCondition()", }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/AutoCompleteHistory/AutoCompleteBehavior.cs ================================================ using ClangPowerToolsShared.MVVM.Models.ToolWindowModels; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace ClangPowerToolsShared.MVVM.AutoCompleteHistory { public static class AutoCompleteBehavior { public static TextChangedEventHandler OnListUpdate = delegate { }; public static TextChangedEventHandler onTextChanged = new TextChangedEventHandler(OnTextChanged); public static KeyEventHandler onKeyDown = new KeyEventHandler(OnPreviewKeyDown); public static List AutocompleteResult = new(); public static string MatchText { get; set; } /// /// The collection to search for matches from. /// public static readonly DependencyProperty AutoCompleteItemsSource = DependencyProperty.RegisterAttached ( "AutoCompleteItemsSource", typeof(IEnumerable), typeof(AutoCompleteBehavior), new UIPropertyMetadata(null, OnAutoCompleteItemsSource) ); /// /// Whether or not to ignore case when searching for matches. /// public static readonly DependencyProperty AutoCompleteStringComparison = DependencyProperty.RegisterAttached ( "AutoCompleteStringComparison", typeof(StringComparison), typeof(AutoCompleteBehavior), new UIPropertyMetadata(StringComparison.Ordinal) ); /// /// What string should indicate that we should start giving auto-completion suggestions. For example: @ /// If this is null or empty, auto-completion suggestions will begin at the beginning of the textbox's text. /// public static readonly DependencyProperty AutoCompleteIndicator = DependencyProperty.RegisterAttached ( "AutoCompleteIndicator", typeof(String), typeof(AutoCompleteBehavior), new UIPropertyMetadata(String.Empty) ); #region Items Source public static IEnumerable GetAutoCompleteItemsSource(DependencyObject obj) { object objRtn = obj.GetValue(AutoCompleteItemsSource); if (objRtn is IEnumerable) return (objRtn as IEnumerable); return null; } public static void SetAutoCompleteItemsSource(DependencyObject obj, IEnumerable value) { obj.SetValue(AutoCompleteItemsSource, value); } private static void OnAutoCompleteItemsSource(object sender, DependencyPropertyChangedEventArgs e) { TextBox tb = sender as TextBox; if (sender == null) return; //If we're being removed, remove the callbacks //Remove our old handler, regardless of if we have a new one. tb.TextChanged -= onTextChanged; tb.PreviewKeyDown -= onKeyDown; if (e.NewValue != null) { //New source. Add the callbacks tb.TextChanged += onTextChanged; tb.PreviewKeyDown += onKeyDown; } } #endregion #region String Comparison public static StringComparison GetAutoCompleteStringComparison(DependencyObject obj) { return (StringComparison)obj.GetValue(AutoCompleteStringComparison); } public static void SetAutoCompleteStringComparison(DependencyObject obj, StringComparison value) { obj.SetValue(AutoCompleteStringComparison, value); } #endregion #region Indicator public static String GetAutoCompleteIndicator(DependencyObject obj) { return (String)obj.GetValue(AutoCompleteIndicator); } public static void SetAutoCompleteIndicator(DependencyObject obj, String value) { obj.SetValue(AutoCompleteIndicator, value); } #endregion /// /// Used for moving the caret to the end of the suggested auto-completion text. /// /// /// static void OnPreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Down) { ((UIElement)e.OriginalSource).MoveFocus (new TraversalRequest(FocusNavigationDirection.Down)); } if (e.Key != Key.Enter && e.Key != Key.Tab) return; TextBox tb = e.OriginalSource as TextBox; if (tb == null) return; //If we pressed enter and if the selected text goes all the way to the end, move our caret position to the end if (tb.SelectionLength > 0 && (tb.SelectionStart + tb.SelectionLength == tb.Text.Length)) { tb.SelectionStart = tb.CaretIndex = tb.Text.Length; tb.SelectionLength = 0; } } /// /// Search for auto-completion suggestions. /// /// /// /// static void OnTextChanged(object sender, TextChangedEventArgs e) { MatchText = String.Empty; TextBox tb = e.OriginalSource as TextBox; if (sender == null) return; IEnumerable values = GetAutoCompleteItemsSource(tb); //No reason to search if we don't have any values. if (values == null) return; if (String.IsNullOrEmpty(tb.Text)) { AutocompleteResult = values.ToList(); OnListUpdate?.Invoke(sender, e); } if ( (from change in e.Changes where change.RemovedLength > 0 select change).Any() && (from change in e.Changes where change.AddedLength > 0 select change).Any() == false ) return; //No reason to search if there's nothing there. if (String.IsNullOrEmpty(tb.Text)) return; MatchText = tb.Text; List indicators = new List() { " ", "(", ")", "," }; int startIndex = 0; //Start from the beginning of the line. string matchingString = tb.Text; //If we have a trigger string, make sure that it has been typed before //giving auto-completion suggestions. string rememberIndicator = string.Empty; if (indicators != null && !String.IsNullOrEmpty(indicators.First())) { if (tb.Text.Length > 0) { List indicatorsIndex = new(); indicatorsIndex = indicators.Select(a => tb.Text.LastIndexOf(a)).ToList(); int maxIndicatorIndex = indicatorsIndex.Max(); if (maxIndicatorIndex == -1) { startIndex = 0; } startIndex = 1 + maxIndicatorIndex; matchingString = tb.Text.Substring(startIndex, (tb.Text.Length - startIndex)); } } //If we don't have anything after the trigger string, return. if (String.IsNullOrEmpty(matchingString)) { AutocompleteResult = values.ToList(); OnListUpdate?.Invoke(sender, e); return; } Int32 textLength = matchingString.Length; StringComparison comparer = GetAutoCompleteStringComparison(tb); //Do search and changes here. AutoCompleteHistoryModel match = ( from value in ( from subvalue in values where subvalue != null && subvalue.Value.Length >= textLength select subvalue ) where value.Value.Substring(0, textLength).Equals(matchingString, comparer) select new AutoCompleteHistoryModel { Value = value.Value.Substring(textLength, value.Value.Length - textLength), RememberAsFavorit = value.RememberAsFavorit, PinIconPath = value.PinIconPath, Visibility = value.Visibility, Id = value.Id }/*Only select the last part of the suggestion*/ ).FirstOrDefault(); AutocompleteResult = ( from value in ( from subvalue in values where subvalue != null && subvalue.Value.Length >= textLength select subvalue ) where value.Value.Substring(0, textLength).Equals(matchingString, comparer) select new AutoCompleteHistoryModel { Value = value.Value.Substring(textLength, value.Value.Length - textLength), RememberAsFavorit = value.RememberAsFavorit, PinIconPath = value.PinIconPath, Visibility = value.Visibility, Id = value.Id }/*Only select the last part of the suggestion*/ ).ToList(); OnListUpdate?.Invoke(sender, e); //Nothing. Leave 'em alone if (match is null || String.IsNullOrEmpty(match.Value)) return; int matchStart = (startIndex + matchingString.Length); tb.TextChanged -= onTextChanged; tb.Text += match.Value; tb.CaretIndex = matchStart; tb.SelectionStart = matchStart; tb.SelectionLength = (tb.Text.Length - startIndex); tb.TextChanged += onTextChanged; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/CollectionElementsCounter.cs ================================================ using ClangPowerTools.Events; using System; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools.MVVM { /// /// Count certain elements from a given collection /// public static class CollectionElementsCounter { #region Members /// /// Count the wanted collection elements /// private static int count = 0; /// /// Collection length /// private static int length = 0; /// /// Flag for counting all the collection elements /// private static bool full = false; /// /// Event triggered when certain conditions are validated /// public static event EventHandler StateEvent; #endregion #region Methods /// /// Count collection elements and set the values for the other members /// /// The collection under surveillance public static void Initialize(IEnumerable collection) { count = 0; length = collection.Count(); foreach (var item in collection) { if (item.IsChecked) ++count; } full = count == length; } /// /// Increment the counter. Trigger the StateEvent if the counter riched the maximum value. /// public static void Add() { ++count; if (count == length) { full = true; StateEvent?.Invoke(null, new BoolEventArgs(true)); } } /// /// Decrement the counter. Trigger the StateEvent if in the previous state the counter riched the maximum value. /// public static void Remove() { --count; if (full) { full = false; StateEvent?.Invoke(null, new BoolEventArgs(false)); } } /// /// Check if the collection is empty. /// /// True is the collection is empty. False otherwise public static bool IsEmpty() => length == 0; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Command/RelayCommand.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace ClangPowerTools.MVVM.Command { public class RelayCommand : ICommand { public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } private readonly Action action; private Func canExecute; public RelayCommand(Action action, Func canExecute = null) { this.action = action; this.canExecute = canExecute; } public bool CanExecute(object parameter) { return canExecute == null ? true : canExecute.Invoke(); } public void Execute(object parameter) { action.Invoke(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Commands/FileCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.MVVM.Models; using ClangPowerTools.Services; using EnvDTE80; using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace ClangPowerToolsShared.MVVM.Commands { public static class FileCommand { [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, uint cchBuffer); public static string GetShortPath(string longPath) { StringBuilder shortPath = new StringBuilder(255); GetShortPathName(longPath, shortPath, 255); return shortPath.ToString(); } public static void TidyFixDiff(FileModel filePath, bool makeDiff = true) { SettingsPathBuilder settingsPathBuilder = new SettingsPathBuilder(); var clangTidyPath = settingsPathBuilder.GetCurrentExecutableLlvmPath(); try { FileInfo file = new(filePath.FullFileName); File.Copy(file.FullName, filePath.CopyFullFileName, true); System.Diagnostics.Process process = new(); process.StartInfo.FileName = clangTidyPath; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.Arguments = $"-fix \"{file.FullName}\""; process.Start(); process.WaitForExit(); if (makeDiff) DiffFilesUsingDefaultTool(filePath.CopyFullFileName, file.FullName); } catch (Exception e) { MessageBox.Show(e.Message, "Tidy-Diff Failed - you do not have an llvm set", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// Copy a file from temp to solution /// /// public static void CopyFileFromTempToSolution(FileModel file) { if (File.Exists(file.CopyFullFileName)) { try { File.Copy(file.CopyFullFileName, file.FullFileName, true); File.Delete(file.CopyFullFileName); } catch (UnauthorizedAccessException e) { MessageBox.Show($"File {file.FullFileName} can't be copied, access to path is denied", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } /// /// Copy a file from solution to temp folder /// /// public static void CopyFileFromSolutionToTemp(FileModel file) { FileInfo fileInfo = new(file.CopyFullFileName); Directory.CreateDirectory(fileInfo.Directory.FullName); try { File.Copy(file.FullFileName, file.CopyFullFileName, true); } catch (UnauthorizedAccessException e) { MessageBox.Show($"File {file.FullFileName} can't be copied, access to path is denied", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } public static void Copy(string source, string destination) { System.Diagnostics.Process process = new(); process.StartInfo.FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}"; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.Arguments = $"Copy-Item -LiteralPath " + source + " " + destination; process.Start(); process.WaitForExit(); } public static void CopyFilesInTempSolution(List files) { foreach (var file in files) { CopyFileFromSolutionToTemp(file); } } public static void DiffFilesUsingDefaultTool(string file1, string file2) { object args = $"\"{file1}\" \"{file2}\""; var dte = VsServiceProvider.GetService(typeof(DTE2)) as DTE2; dte.Commands.Raise(TidyConstants.ToolsDiffFilesCmd, TidyConstants.ToolsDiffFilesId, ref args, ref args); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Commands/RelayCommand.cs ================================================ using System; using System.Windows.Input; namespace ClangPowerTools.MVVM.Commands { public class RelayCommand : ICommand { #region Members private readonly Action action; private readonly Func canExecute; #endregion public RelayCommand(Action action, Func canExecute = null) { this.action = action; this.canExecute = canExecute; } #region Contructors public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } #endregion #region Public Methods public bool CanExecute(object parameter) { return canExecute == null ? true : canExecute(); } public void Execute(object parameter) { action(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Commands/TidyDiffCommand.cs ================================================ using ClangPowerTools; using ClangPowerTools.Services; using EnvDTE80; using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace ClangPowerToolsShared.MVVM.Commands { public static class TidyDiffCommand { public static void TidyFixDiff(string filePath, bool makeDiff = true) { SettingsPathBuilder settingsPathBuilder = new SettingsPathBuilder(); var clangTidyPath = settingsPathBuilder.GetCurrentExecutableLlvmPath(); try { FileInfo file = new(filePath); var copyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "Temp", file.Name); File.Copy(file.FullName, copyFile, true); System.Diagnostics.Process process = new(); process.StartInfo.FileName = clangTidyPath; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.Arguments = $"-fix \"{file.FullName}\""; process.Start(); process.WaitForExit(); if (makeDiff) DiffFilesUsingDefaultTool(copyFile, file.FullName); //File.Delete(copyFile); } catch (Exception e) { MessageBox.Show(e.Message, "Tidy-Diff Failed - you do not have an llvm set", MessageBoxButtons.OK, MessageBoxIcon.Error); } } public static void CopyFileInTemp(string filePath) { FileInfo file = new(filePath); var copyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "Temp", file.Name); File.Copy(file.FullName, copyFile, true); } public static void CopyFilesInTemp(List filePaths) { foreach(var path in filePaths) { FileInfo file = new(path); var copyFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "Temp", file.Name); File.Copy(file.FullName, copyFile, true); } } public static void DiffFilesUsingDefaultTool(string file1, string file2) { object args = $"\"{file1}\" \"{file2}\""; var dte = VsServiceProvider.GetService(typeof(DTE2)) as DTE2; dte.Commands.Raise(TidyConstants.ToolsDiffFilesCmd, TidyConstants.ToolsDiffFilesId, ref args, ref args); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Commands/VSThemeCommand.cs ================================================ using ClangPowerToolsShared.MVVM.Constants; using Microsoft.VisualStudio.Shell; using System.Linq; namespace ClangPowerToolsShared.MVVM.Commands { public static class VSThemeCommand { private const string darkThemeVs2022 = "4294638330"; private const string darkThemeVs2019 = "4294046193"; private const string textColorKey = "ToolWindowTextColorKey"; public static VsThemes GetCurrentVsTheme() { var colorValues = VsColors.GetCurrentThemedColorValues(); var cvPair = colorValues.Where(a => a.Key.ToString() == textColorKey).FirstOrDefault(); if ((cvPair.Value.ToString() == darkThemeVs2022) || (cvPair.Value.ToString() == darkThemeVs2019)) return VsThemes.Dark; return VsThemes.Light; } /// /// Get corresponding icon to visual studio theme /// public static string GetDiscardFixIconEnabled() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.DiscardFixDark; else return IconResourceConstants.DiscardFixLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetTidyFixIconEnabled() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.FixDark; else return IconResourceConstants.FixLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetRefreshTidyIconEnabled() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.RefreshTidyDark; else return IconResourceConstants.RefreshTidyLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetUnpinIcon() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.UnpinDark; else return IconResourceConstants.UnpinLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetPinIcon() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.PinDark; else return IconResourceConstants.PinLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetIgnoreIconEnabled() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.RemoveDark; else return IconResourceConstants.RemoveLight; } /// /// Get corresponding icon to visual studio theme /// public static string GetDiffIconEnabled() { if (VSThemeCommand.GetCurrentVsTheme() == VsThemes.Dark) return IconResourceConstants.DiffDark; else return IconResourceConstants.DiffLight; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/CommonSettingsFunctionality.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Models; using Microsoft.Win32; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace ClangPowerTools { public abstract class CommonSettingsFunctionality { #region Methods protected string OpenFile(string fileName, string defaultExt, string filter) { OpenFileDialog openFileDialog = new OpenFileDialog(); string path = string.Empty; openFileDialog.FileName = fileName; openFileDialog.DefaultExt = defaultExt; openFileDialog.Filter = filter; bool? result = openFileDialog.ShowDialog(); if (result == true) { string filename = openFileDialog.FileName; path = filename; } return path; } protected string[] OpenFiles(string fileName, string defaultExt, string filter) { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.FileName = fileName; openFileDialog.DefaultExt = defaultExt; openFileDialog.Filter = filter; openFileDialog.Multiselect = true; if (openFileDialog.ShowDialog() != true) return null; return openFileDialog.FileNames; } /// /// Browse for folder from where the files path acording to the given seach instruction will be collected /// /// Search pattern to apply in the file search /// Information about how to search inside the selected folder /// Array of files path protected string[] BrowseForFolderFiles(string searchFilePattern, SearchOption searchOption) { using var folderBrowseDialog = new System.Windows.Forms.FolderBrowserDialog(); System.Windows.Forms.DialogResult result = folderBrowseDialog.ShowDialog(); if (result != System.Windows.Forms.DialogResult.OK || string.IsNullOrWhiteSpace(folderBrowseDialog.SelectedPath)) return null; return Directory.GetFiles(folderBrowseDialog.SelectedPath, searchFilePattern, searchOption); } /// /// Browse for folder path /// /// Search pattern to apply in the file search /// Information about how to search inside the selected folder /// Path to the selected folder protected string BrowseForFolderFiles() { using var folderBrowseDialog = new System.Windows.Forms.FolderBrowserDialog(); System.Windows.Forms.DialogResult result = folderBrowseDialog.ShowDialog(); if (result != System.Windows.Forms.DialogResult.OK || string.IsNullOrWhiteSpace(folderBrowseDialog.SelectedPath)) return null; return folderBrowseDialog.SelectedPath; } protected string SaveFile(string fileName, string defaultExt, string filter) { SaveFileDialog saveFileDialog = new SaveFileDialog(); string path = string.Empty; // Set the default file extension saveFileDialog.FileName = fileName; saveFileDialog.DefaultExt = defaultExt; saveFileDialog.Filter = filter; //Display the dialog window bool? result = saveFileDialog.ShowDialog(); if (result == true) { path = saveFileDialog.FileName; } return path; } protected void WriteContentToFile(string path, string content) { FileSystem.WriteContentToFile(path, content); } protected string OpenContentDialog(string content, bool showFilesPicker = false, bool showFolderPicker = false) { InputDataViewModel inputDataViewModel = new InputDataViewModel(content, showFilesPicker, showFolderPicker); inputDataViewModel.ShowViewDialog(); string input = CreateInput(inputDataViewModel.Inputs.ToList()); return input; } private string CreateInput(List models) { StringBuilder sb = new StringBuilder(); foreach (var item in models) { if (string.IsNullOrWhiteSpace(item.InputData) == false) sb.Append(item.InputData).Append(";"); } if (sb.Length > 0) sb.Length--; return sb.ToString(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/CPPKeywords.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.MVVM.Constants { public static class CPPKeywords { public static HashSet keywords = new HashSet() { "asm", "else", "new", "this", "auto", "enum", "operator", "throw", "bool", "explicit", "private", "true", "break", "export", "protected", "try", "case", "extern", "public", "typedef", "catch", "false", "register", "typeid", "char", "float", "reinterpret_cast", "typename", "class", "for", "if", "int", "double", "void", "return", "do", "switch", "while", "And", "bitor", "not_eq", "xor", "and_eq", "compl", "or", "xor_eq", "bitand", "not", "or_eq", "union", "const", "static", "short", "unsigned", "const_cast", "goto", "signed", "using", "continue", "sizeof", "virtual", "default", "inline", "delete", "static_cast", "volatile", "long", "struct", "wchar_t", "mutable", "dynamic_cast", "namespace", "friend", "template" }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/ComboBoxConstants.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using System.ComponentModel; using System.Runtime.Serialization; using System.Xml.Serialization; namespace ClangPowerTools { [Serializable] [JsonConverter(typeof(StringEnumConverter))] public enum ClangFormatStyle { [EnumMember(Value = "file")] file = 0, [EnumMember(Value = "Chromium")] Chromium, [EnumMember(Value = "Google")] Google, [EnumMember(Value = "LLVM")] LLVM, [EnumMember(Value = "Microsoft")] Microsoft, [EnumMember(Value = "Mozilla")] Mozilla, [EnumMember(Value = "WebKit")] WebKit } [Serializable] [JsonConverter(typeof(StringEnumConverter))] public enum ClangFormatFallbackStyle { [EnumMember(Value = "none")] none = 0, [EnumMember(Value = "Chromium")] Chromium, [EnumMember(Value = "Google")] Google, [EnumMember(Value = "LLVM")] LLVM, [EnumMember(Value = "Microsoft")] Microsoft, [EnumMember(Value = "Mozilla")] Mozilla, [EnumMember(Value = "WebKit")] WebKit } [Serializable] [JsonConverter(typeof(StringEnumConverter))] public enum ClangGeneralAdditionalIncludes { [XmlEnum(Name = "include directories")] [EnumMember(Value = "IncludeDirectories")] IncludeDirectories, [XmlEnum(Name = "system include directories")] [EnumMember(Value = "SystemIncludeDirectories")] SystemIncludeDirectories } [Serializable] [JsonConverter(typeof(StringEnumConverter))] public enum ClangTidyUseChecksFrom { [XmlEnum(Name = "predefined checks")] [EnumMember(Value = "PredefinedChecks")] PredefinedChecks, [XmlEnum(Name = "custom checks")] [EnumMember(Value = "CustomChecks")] CustomChecks, [XmlEnum(Name = ".clang-tidy config file")] [EnumMember(Value = "TidyFile")] TidyFile } [Serializable] public enum ToggleValues { [XmlEnum(Name = "true")] [EnumMember(Value = "true")] True, [XmlEnum(Name = "false")] [EnumMember(Value = "false")] False } public sealed class ComboBoxConstants { #region Constants public const string kCustomChecks = "custom checks"; public const string kPredefinedChecks = "predefined checks"; public const string kTidyFile = ".clang-tidy config file"; public const string kDefaultHeaderFilter = ".*"; public const string kCorrespondingHeaderValue = "_"; public const string kCorrespondingHeaderName = "Corresponding Header"; public const string kNone = "none"; public const string kFile = "file"; public const string kChromium = "Chromium"; public const string kGoogle = "Google"; public const string kLLVM = "LLVM"; public const string kMozilla = "Mozilla"; public const string kWebKit = "WebKit"; public const string kIncludeDirectories = "include directories"; public const string kSystemIncludeDirectories = "system include directories"; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/EncodingConstants.cs ================================================ namespace ClangPowerTools.MVVM.Constants { public static class EncodingConstants { public const string InstallExeParameters = "RunPowerShellCommand Extension"; public const string UninstallExeParameters = "RunPowerShellCommand Visual Studio Extension Detailed Info"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/FormatEditorConstants.cs ================================================ using System; using System.IO; namespace ClangPowerTools { public static class FormatEditorConstants { public const string ExecutableName = "ClangFormatEditor.exe"; public const string ClangFormatEditorFolder = "ClangFormatEditor"; public const string UpdaterParameter = " VisualStudio"; public const string ClangFormatEditor = "Clang Format Editor"; public const string FrameworkdUrlDownload = @"https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-5.0.2-windows-x86-installer"; public const string FrameworkPath = @"C:\Program Files (x86)\dotnet\shared\Microsoft.WindowsDesktop.App"; public const string ClangFormatExe = "clang-format.exe"; public const string ClangFormatMsi = "Clang Format Editor.msi"; public const string SetupFailed = "Clang-Format Setup Failed"; public static string ClangFormatEditorPath { get; } = Path.Combine(Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%"), "Caphyon", ClangFormatEditor); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/IconResourceConstants.cs ================================================ using System.IO; namespace ClangPowerToolsShared.MVVM.Constants { public static class IconResourceConstants { private static DirectoryInfo directoryPath = new DirectoryInfo(Directory.GetCurrentDirectory()); public static string PinDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CTP]Pinned_dark.png"; public static string PinLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Pinned.png"; public static string UnpinDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CTP]UnPinned_dark.png"; public static string UnpinLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]UnPinned.png"; public static string RefreshTidyDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Refresh_dark.png"; public static string RefreshTidyLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Refresh-Tidy.png"; public static string RefreshDisabled { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Refresh_disabled.png"; public static string DiffDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Diff_dark.png"; public static string DiffLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Diff2.png"; public static string DiffDisabled { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Diff_disabled.png"; public static string FixDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Fix_dark.png"; public static string FixLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Fix.png"; public static string FixDisabled { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Fix_disabled.png"; public static string RemoveDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Remove_dark.png"; public static string RemoveLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Remove.png"; public static string RemoveDisabled { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]Remove_disabled.png"; public static string DiscardFixDark { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]RemoveFix_dark.png"; public static string DiscardFixLight { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]RemoveFix.png"; public static string DiscardFixDisabled { get; } = @"/ClangPowerTools;component/Resources/TidyToolWindow/[CPT]RemoveFix_disabled.png"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LLVMVersionsAlternate.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public static class LlvmVersionsAlternate { public static List VersionAlternateUri { get; } = new List { "21.1.6", "20.1.8", "20.1.0", "19.1.7", "19.1.0", "18.1.8", "18.1.2", "17.0.1", "16.0.6", "16.0.0", "15.0.7", "15.0.4", "15.0.0", "14.0.6", "14.0.3", "14.0.0", "13.0.1" }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LlvmConstants.cs ================================================ namespace ClangPowerTools.MVVM.Constants { public static class LlvmConstants { public const string InstallExeParameters = "/S /D="; public const string UninstallExeParameters = "/S"; public const string Arguments = @"/C reg delete HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\LLVM /f &"; public const string ProcessFileName = "cmd.exe"; public const string ProcessVerb = "runas"; public const string ReleasesUri = @"http://releases.llvm.org"; public const string GitHubUri = @"https://github.com/llvm/llvm-project/releases/download"; public const string Llvm = "LLVM"; public const string Uninstall = "Uninstall"; public const string Os64Paramater = "-win64.exe"; public const string Os32Paramater = "-win32.exe"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/LlvmVersions.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public static class LlvmVersions { public static List Versions { get; } = new List { "21.1.6", "20.1.8", "20.1.0", "19.1.7", "19.1.0", "18.1.8", "18.1.2", "17.0.1", "16.0.6", "16.0.0", "15.0.7", "15.0.4", "15.0.0", "14.0.6", "14.0.3", "14.0.0", "13.0.1" }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/MatchConstants.cs ================================================ using ClangPowerTools.Helpers; using System.Collections.Generic; namespace ClangPowerToolsShared.MVVM.Constants { /// /// AST Matchers /// public static class MatchConstants { /// /// Match a called expersion with a default argument on a position. /// Replace {0} with expersion name. /// Replace {1} with position of default arg /// public const string CalledExprDefaultArg = "match callExpr(callee(functionDecl(hasName(\"{0}\"))), hasArgument({1}, cxxDefaultArgExpr()))"; /// /// Diagnostic mode can be re-entered with set output diag for source code exploration /// public const string SetOutpuDump = "set output dump"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/PathConstants.cs ================================================ using ClangPowerTools; using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using System; using System.IO; namespace ClangPowerToolsShared.MVVM.Constants { public static class PathConstants { public static string CacheRepositoryPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "CacheRepository"); public static string LlvmLitePath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "LLVM_Lite"); public static string SolutionDirPath { get { var dte2 = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); var solution = dte2.Solution.FullName; return new FileInfo(solution).Directory.FullName; } } private static string vcxprojPath = string.Empty; public static string VcxprojPath { get { if (vcxprojPath == string.Empty) { ItemsCollector itemsCollector = new(); var items = itemsCollector.CollectActiveProjectItem(); if (items is not null && items[0] is not null) { var projectItem = items[0].GetObject() as ProjectItem; vcxprojPath = projectItem.ContainingProject.FullName; } } return vcxprojPath; } } public static string GetPathToFindCommands { get { return Path.Combine(SolutionDirPath, "commands_find.txt"); } } public static string JsonCompilationDBPath { get { return Path.Combine(SolutionDirPath, "compile_commands.json"); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/PsUpdaterConstants.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.MVVM.Constants { public static class PsUpdaterConstants { public const string PowerShellScriptsFolder = "PowerShellScripts"; public const string ToolingFolder = "Tooling"; public const string V1Folder = "v1"; public const string PsClangFolder = "psClang"; public const string ClangBuildScript = "clang-build.ps1"; public const string GitHubUri = @"https://raw.githubusercontent.com/Caphyon/clang-power-tools/master/ClangPowerTools/ClangPowerToolsShared/Tooling/v1/"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/ResourceConstants.cs ================================================ namespace ClangPowerTools.MVVM.Constants { public static class ResourceConstants { public const string DeselectAllTooltipText = "Deselect all"; public const string EncodingError = "encoding is not supported"; public const string SelectAllTooltipText = "Select all"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/ThemeConstants.cs ================================================ namespace ClangPowerToolsShared.MVVM.Constants { public enum VsThemes { Dark, Light } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/TidyConstants.cs ================================================ using System; using System.IO; namespace ClangPowerTools { public static class TidyConstants { public static string FlagsUri { get; } = @"https://clang.llvm.org/extra/clang-tidy/checks/"; // This is the guid and id for the Tools.DiffFiles command public static string ToolsDiffFilesCmd { get; } = "{5D4C0442-C0A2-4BE8-9B4D-AB1C28450942}"; public static int ToolsDiffFilesId { get; } = 256; public static string LongFilePrefix { get; } = @"\\?\"; public static string SolutionTempGuid { get; } = Guid.NewGuid().ToString(); public static string TempsFolderPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ClangPowerTools", "Temp"); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Constants/UIElementsConstants.cs ================================================ namespace ClangPowerToolsShared.MVVM.Constants { public static class UIElementsConstants { public static string Hidden { get; } = "Hidden"; public static string Visibile { get; } = "Visible"; public static string Pin { get; } = "Pin"; public static string Unpin { get; } = "Unpin"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/AccountController.cs ================================================ using ClangPowerTools.MVVM.WebApi; using Newtonsoft.Json; using System; using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace ClangPowerTools.MVVM.Controllers { public class AccountController { #region Public Methods public async Task LoginAsync(UserModel userModel) { try { HttpResponseMessage userAccoutHttpRestul = await GetUserAccountHttpRestulAsync(userModel); if (userAccoutHttpRestul.IsSuccessStatusCode) { TokenModel tokenModel = JsonConvert.DeserializeObject(await userAccoutHttpRestul.Content.ReadAsStringAsync()); if (string.IsNullOrWhiteSpace(tokenModel.jwt)) return false; SaveToken(tokenModel.jwt); return true; } else { return false; } } catch (Exception) { return false; } } #endregion #region Private Methods private async Task GetUserAccountHttpRestulAsync(UserModel userModel) { using StringContent content = new StringContent(SeralizeUserModel(userModel), Encoding.UTF8, "application/json"); return await ApiUtility.ApiClient.PostAsync(WebApiUrl.loginUrl, content); } private void SaveToken(string token) { var settingsPathBuilder = new SettingsPathBuilder(); string filePath = settingsPathBuilder.GetPath("ctpjwt"); DeleteExistingToken(filePath); using var streamWriter = new StreamWriter(filePath); streamWriter.WriteLine(token); File.SetAttributes(filePath, File.GetAttributes(filePath) | FileAttributes.Hidden); } private void DeleteExistingToken(string filePath) { if (File.Exists(filePath)) { File.Delete(filePath); } } private string SeralizeUserModel(UserModel userModel) { string jsonObject = JsonConvert.SerializeObject(userModel); userModel.Dispose(); return jsonObject; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/FindController.cs ================================================ using ClangPowerTools; using ClangPowerTools.Views; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Models.ToolWindowModels; using Newtonsoft.Json; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; namespace ClangPowerToolsShared.MVVM.Controllers { public class FindController : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected FindToolWindowView findToolWindowView; protected FindToolWindowModel findToolWindowModel = new(); private Dictionary pathCommandPairs = new(); private List commands = new(); private string pathToClangQuery; private string mInteractiveModeDocumentName = string.Empty; private int mInteractiveModeDocumentHash = 0; public List MenuOptions { get { return LookInMenuController.MenuOptions; } } public MenuItem SMenuOption { get { return LookInMenuController.MenuOptions.Last(); } } public FindToolWindowModel FindToolWindowModel { get { return findToolWindowModel; } set { findToolWindowModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FindToolWindowModel")); } } public FindController() { pathToClangQuery = string.Empty; } public void LaunchCommand() { if (pathToClangQuery == string.Empty) GetPathToClangQuery(); if (commands.Count > 0) commands.Clear(); commands.Add(MatchConstants.SetOutpuDump); switch (findToolWindowModel.CurrentViewMatcher.Id) { case FindCommandIds.kDefaultArgsId: { commands.Add(MatchConstants.CalledExprDefaultArg.Replace("{0}", findToolWindowModel.DefaultArgsModel .FunctionName).Replace("{1}", findToolWindowModel.DefaultArgsModel.DefaultArgsPosition.ToString())); break; } case FindCommandIds.kCustomMatchesId: { if ((findToolWindowModel.CustomMatchesModel.Matchers.Length > 0 && findToolWindowModel.CustomMatchesModel.Matchers[0] == 'm')) { commands.Add(findToolWindowModel.CustomMatchesModel.Matchers); } else { commands.Add("m " + findToolWindowModel.CustomMatchesModel.Matchers); } break; } default: break; } } public void RunPowershellQuery() { using (StreamWriter sw = File.AppendText(PathConstants.GetPathToFindCommands)) { foreach (var command in commands) { sw.WriteLine(command); } } DisplayMessageBeforeFind(); if (LookInMenuController.GetSelectedMenuItem().LookInMenu == LookInMenu.CurrentActiveDocument) { pathCommandPairs = GetCommandForPowershellInteractiveMode(pathToClangQuery); CheckFileNameActiveInteractiveMode(pathCommandPairs.First().Key); PowerShellWrapper.InvokeInteractiveMode(pathCommandPairs.First()); } else { pathCommandPairs = GetCommandForPowershell(pathToClangQuery); PowerShellWrapper.InvokePassSequentialCommands(pathCommandPairs); } DisplayMessageAfterFind(); File.Delete(PathConstants.GetPathToFindCommands); } private void DisplayMessageAfterFind() { CommandControllerInstance.CommandController.DisplayMessage(false, "\nⒾ Find all matches in Error List -> Ⓘ Messages \nMake sure that [Build + IntelliSense] is selected\n"); } private void DisplayMessageBeforeFind() { CommandControllerInstance.CommandController.DisplayMessage(false, "\n⌛ Please wait ...\n"); // 1 - verbose if (SettingsProvider.CompilerSettingsModel.VerbosityLevel != "1") CommandControllerInstance.CommandController.DisplayMessage(false, "\nYou can select verbose mode to see the" + " complete output. Settings -> Compile -> Verbosity level\n"); } protected void BeforeCommand() { findToolWindowModel.IsRunning = true; FindToolWindowModel = findToolWindowModel; } protected void AfterCommand() { findToolWindowModel.IsRunning = false; FindToolWindowModel = findToolWindowModel; } private void GetPathToClangQuery() { if (pathToClangQuery == string.Empty) { pathToClangQuery = PowerShellWrapper.DownloadTool(ScriptConstants.kQueryFile); pathToClangQuery = Path.Combine(pathToClangQuery, ScriptConstants.kQueryFile); } } private class FileCompilationDB { public string file { get; set; } } private Dictionary GetCommandForPowershell(string pathToBinary) { string compilationDatabaseContent = string.Empty; if (File.Exists(PathConstants.JsonCompilationDBPath)) { compilationDatabaseContent = File.ReadAllText(PathConstants.JsonCompilationDBPath); } List files = JsonConvert.DeserializeObject>(compilationDatabaseContent); Dictionary commands = new(); foreach (var path in files.Select(a => a.file).ToList()) { var command = $"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive " + $"-command \" & '{pathToBinary}' '{path}' " + $"-p '{PathConstants.JsonCompilationDBPath}' " + $"-f '{PathConstants.GetPathToFindCommands}' \""; if (!commands.ContainsKey(path)) commands.Add(path, command); } return commands; } private void CheckFileNameActiveInteractiveMode(string aFileName) { bool modifedFile = false; if(File.Exists(aFileName)) { int contentHash = File.ReadAllText(aFileName).GetHashCode(); if (contentHash != mInteractiveModeDocumentHash) modifedFile = true; mInteractiveModeDocumentHash = contentHash; } if (!string.IsNullOrEmpty(mInteractiveModeDocumentName) && (mInteractiveModeDocumentName != aFileName || modifedFile)) PowerShellWrapper.EndInteractiveMode(); mInteractiveModeDocumentName = aFileName; } private Dictionary GetCommandForPowershellInteractiveMode(string pathToBinary) { string compilationDatabaseContent = string.Empty; if (File.Exists(PathConstants.JsonCompilationDBPath)) { compilationDatabaseContent = File.ReadAllText(PathConstants.JsonCompilationDBPath); } List files = JsonConvert.DeserializeObject>(compilationDatabaseContent); Dictionary commands = new(); foreach (var path in files.Select(a => a.file).ToList()) { var command = $"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive " + $"-command \"& '{pathToBinary}' '{path}' " + $"-p '{PathConstants.JsonCompilationDBPath}' \""; if (!commands.ContainsKey(path)) commands.Add(path, command); } return commands; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/FormatEditorController.cs ================================================ using ClangPowerTools.Helpers; using System; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using System.Windows; namespace ClangPowerTools { public class FormatEditorController { #region Members public static Process EditorProcess; private static string vsixPath; #endregion #region Constructor public FormatEditorController() { vsixPath = Path.GetDirectoryName(GetType().Assembly.Location); CreateEditorDirectory(); } #endregion #region Methods public void OpenEditor() { try { EditorProcess = new Process(); EditorProcess.StartInfo.FileName = Path.Combine(FormatEditorConstants.ClangFormatEditorPath, FormatEditorConstants.ExecutableName); EditorProcess.Start(); } catch (Exception e) { MessageBox.Show(e.Message, FormatEditorConstants.ClangFormatEditor, MessageBoxButton.OK, MessageBoxImage.Error); } } //Install Clang Format Editor if this is not already installed public void InstallClangFormatEditorSilent() { if (File.Exists(Path.Combine(FormatEditorConstants.ClangFormatEditorPath, FormatEditorConstants.ExecutableName))) return; try { EditorProcess = new Process(); EditorProcess.StartInfo.FileName = "msiexec.exe"; EditorProcess.StartInfo.Arguments = $" /i \"{Path.Combine(vsixPath, FormatEditorConstants.ClangFormatMsi)}\" /qn "; EditorProcess.StartInfo.UseShellExecute = true; EditorProcess.StartInfo.Verb = "runas"; EditorProcess.Start(); EditorProcess.WaitForExit(); } catch (Exception e) { MessageBox.Show(e.Message, FormatEditorConstants.ClangFormatEditor, MessageBoxButton.OK, MessageBoxImage.Error); } } private static void CreateEditorDirectory() { var appDataDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FormatEditorConstants.ClangFormatEditorFolder); try { FileSystem.CreateDirectory(appDataDirectory); File.Copy(Path.Combine(vsixPath, FormatEditorConstants.ClangFormatExe), Path.Combine(appDataDirectory, FormatEditorConstants.ClangFormatExe), true); } catch (Exception e) { MessageBox.Show(e.Message, FormatEditorConstants.SetupFailed, MessageBoxButton.OK, MessageBoxImage.Error); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/FreeTrialController.cs ================================================ using ClangPowerTools.Helpers; using System; namespace ClangPowerTools.MVVM.Controllers { public class FreeTrialController { #region Members private readonly RegistryUtility registryUtility; private readonly string registryName = @"Software\Caphyon\Clang Power Tools"; private readonly string keyName = "DateTimeT"; private readonly int trialDays = 14; private readonly string expiredDate = "9/12/2002 7:52:51 PM"; #endregion #region Constructor public FreeTrialController() => registryUtility = new RegistryUtility(registryName); #endregion #region Public Methods public bool Start() => registryUtility.WriteCurrentUserKey(keyName, DateTime.Now.ToString()); public bool MarkAsExpired() => registryUtility.WriteCurrentUserKey(keyName, expiredDate); public string GetStartTime() { if (WasEverInTrial() == false) return string.Empty; return registryUtility.ReadCurrentUserKey(keyName); } public string GetExpirationDateAsString() { var freeTrialStartTimeAsString = GetStartTime(); if (string.IsNullOrWhiteSpace(freeTrialStartTimeAsString)) return string.Empty; if (WasEverInTrial() == false) return string.Empty; var freeTrialStartTime = DateTime.Parse(freeTrialStartTimeAsString); var expirationDate = freeTrialStartTime.AddDays(trialDays); return expirationDate.ToString(); } public bool IsActive() { var freeTrialStartTimeAsString = GetStartTime(); if (string.IsNullOrWhiteSpace(freeTrialStartTimeAsString)) return false; var freeTrialStartTime = DateTime.Parse(freeTrialStartTimeAsString); return DateTime.Now.Subtract(freeTrialStartTime).Days <= trialDays; } public bool WasEverInTrial() => registryUtility.Exists() && !string.IsNullOrWhiteSpace(registryUtility.ReadCurrentUserKey(keyName)); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/LicenseController.cs ================================================ using ClangPowerTools.MVVM.LicenseValidation; using System.Threading.Tasks; namespace ClangPowerTools.MVVM.Controllers { public class LicenseController { #region Public Methods public async Task GetUserLicenseTypeAsync() { if (await new CommercialLicenseValidator().ValidateAsync()) return LicenseType.Commercial; if (await new PersonalLicenseValidator().ValidateAsync()) return LicenseType.Personal; if (new FreeTrialController().IsActive()) return LicenseType.Trial; if (await new LocalLicenseValidator().ValidateAsync()) return LicenseType.SessionExpired; return LicenseType.NoLicense; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/LlvmController.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Constants; using ClangPowerTools.MVVM.Interfaces; using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Net; using System.Threading; using System.Windows.Forms; namespace ClangPowerTools.MVVM.Controllers { public class LlvmController : IDownload, IInstall { #region Members public LlvmModel llvmModel = new LlvmModel(); public CancellationTokenSource downloadCancellationToken = new CancellationTokenSource(); public delegate void OnOperationCanceled(); public event OnOperationCanceled OnOperationCanceldEvent; private Process process; private readonly SettingsPathBuilder settingsPathBuilder = new SettingsPathBuilder(); private const string registryLlvmUninstall = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\LLVM"; private const string keyDisplayVersion = "DisplayVersion"; private const string registryLlvm = @"SOFTWARE\WOW6432Node\LLVM\LLVM"; private const string keyInstallPath = ""; #endregion #region Properties public EventHandler InstallFinished { get; set; } public EventHandler UninstallFinished { get; set; } public CancelEventHandler SettingsWindowClosed { get; set; } #endregion #region Constructor public LlvmController() { SettingsWindowClosed += WindowClosed; } #endregion #region Public Methods public string GetLlvmPathFromRegistry() { var registryUtility = new RegistryUtility(registryLlvm); var path = registryUtility.ReadLocalMachineKey(keyInstallPath); if (path == null) return string.Empty; return Path.Combine(path, "bin"); } public string GetVersionFromRegistry() { var registryUtility = new RegistryUtility(registryLlvmUninstall); var version = registryUtility.ReadLocalMachineKey(keyDisplayVersion); if (version == null) return string.Empty; return version; } public void Download(string version, DownloadProgressChangedEventHandler method) { CreateVersionDirectory(version); var llvmUri = new LlvmUri(); var executablePath = settingsPathBuilder.GetLlvmExecutablePath(version, LlvmConstants.Llvm + version); var uri = string.Empty; if (LlvmVersionsAlternate.VersionAlternateUri.Contains(version)) { uri = llvmUri.GetGitHubUri(version); } else { uri = llvmUri.GetDefaultUri(version); } try { using var client = new WebClient(); client.DownloadProgressChanged += method; client.DownloadFileCompleted += DownloadCompleted; downloadCancellationToken.Token.Register(client.CancelAsync); client.DownloadFileAsync(new Uri(uri), executablePath); } catch (Exception) { DownloadCanceled(); } } public void Install(string version) { var llVmVersionPath = settingsPathBuilder.GetLlvmPath(version); var executablePath = settingsPathBuilder.GetLlvmExecutablePath(version, LlvmConstants.Llvm + version); var startInfoArguments = string.Concat(LlvmConstants.Arguments, " ", "\"", executablePath, "\"", " ", LlvmConstants.InstallExeParameters, llVmVersionPath); try { process = new Process(); process.StartInfo.FileName = LlvmConstants.ProcessFileName; process.StartInfo.Arguments = startInfoArguments; process.StartInfo.Verb = LlvmConstants.ProcessVerb; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.EnableRaisingEvents = true; process.Exited += InstallProcessExited; process.Exited += InstallFinished; process.Start(); } catch (Exception e) { DefaultState(); if (OnOperationCanceldEvent != null) OnOperationCanceldEvent(); DeleteLlvmDirectory(llvmModel.Version); MessageBox.Show(e.Message, "Installation Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } public void Uninstall(string version) { if (DoesUninstallExist(version) == false) { DeleteLlvmDirectory(version); return; } try { process = new Process(); process.StartInfo.FileName = settingsPathBuilder.GetLlvmExecutablePath(version, LlvmConstants.Uninstall); process.StartInfo.Arguments = LlvmConstants.UninstallExeParameters; process.StartInfo.Verb = LlvmConstants.ProcessVerb; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.EnableRaisingEvents = true; process.Exited += UninstallProcessExited; process.Exited += UninstallFinished; process.Start(); } catch (Exception e) { InstallFinishedState(); if (OnOperationCanceldEvent != null) OnOperationCanceldEvent(); MessageBox.Show(e.Message, "Uninstall Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } public bool IsVersionExeOnDisk(string version, string name) { var executablePath = settingsPathBuilder.GetLlvmExecutablePath(version, name); return File.Exists(executablePath); } public void DownloadCompleted(object sender, AsyncCompletedEventArgs e) { if (downloadCancellationToken.IsCancellationRequested || llvmModel.DownloadProgress != llvmModel.MaxProgress) { DownloadCanceled(); } else { BeginInstallation(); } } #endregion #region Private Methods private void InstallFinishedState() { llvmModel.IsInstalled = true; llvmModel.IsInstalling = false; } private void InstallingState() { llvmModel.IsInstalling = true; llvmModel.IsDownloading = false; } private void DefaultState() { llvmModel.IsInstalled = false; llvmModel.IsDownloading = false; llvmModel.IsInstalling = false; } private void DownloadCanceled() { DefaultState(); if (OnOperationCanceldEvent != null) OnOperationCanceldEvent(); DeleteLlvmDirectory(llvmModel.Version); ResetDownloadProgressState(); MessageBox.Show("The download process has stopped.", "LLVM Download", MessageBoxButtons.OK, MessageBoxIcon.Warning); } private void BeginInstallation() { InstallingState(); ResetDownloadProgressState(); Install(llvmModel.Version); } private void ResetDownloadProgressState() { llvmModel.DownloadProgress = 0; downloadCancellationToken.Dispose(); downloadCancellationToken = new CancellationTokenSource(); } private void InstallProcessExited(object sender, EventArgs e) { process.Close(); DeleteInstallerFile(llvmModel.Version); InstallFinishedState(); } private void UninstallProcessExited(object sender, EventArgs e) { process.Close(); DeleteLlvmDirectory(llvmModel.Version); DefaultState(); } private void WindowClosed(object sender, EventArgs e) { if (llvmModel.DownloadProgress > 0 && llvmModel.DownloadProgress != llvmModel.MaxProgress) { downloadCancellationToken.Cancel(); } SettingsWindowClosed -= WindowClosed; } private void CreateVersionDirectory(string version) { var path = settingsPathBuilder.GetLlvmPath(version); FileSystem.CreateDirectory(path); } private void DeleteLlvmDirectory(string version) { var path = settingsPathBuilder.GetLlvmPath(version); FileSystem.DeleteDirectory(path); } private void DeleteInstallerFile(string version) { var exeName = string.Concat(LlvmConstants.Llvm, llvmModel.Version, ".exe"); var path = Path.Combine(settingsPathBuilder.GetLlvmPath(version), exeName); FileSystem.DeleteFile(path); } private bool DoesUninstallExist(string version) { return IsVersionExeOnDisk(version, LlvmConstants.Uninstall); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/LookInMenuController.cs ================================================ using System.Collections.Generic; namespace ClangPowerToolsShared.Commands { public static class LookInMenuController { private static MenuItem selectedMenuItem = new(); public static void SetSelectedOption(MenuItem menuItem) { selectedMenuItem = menuItem; } public static MenuItem GetSelectedMenuItem() { return selectedMenuItem; } public static List MenuOptions { get { return new List() { new MenuItem ("Entire solution", LookInMenu.EntireSolution), new MenuItem ("Current project", LookInMenu.CurrentProject), new MenuItem ("Current active document", LookInMenu.CurrentActiveDocument), }; } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Controllers/TidyToolWindowController.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Models; using ClangPowerTools.Services; using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels; using EnvDTE80; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.MVVM.Controllers { public class TidyToolWindowController { #region Properties public ObservableCollection files = new ObservableCollection(); private List headers = new List(); public TidyToolWindowModel tidyToolWindowModel = new TidyToolWindowModel(); #endregion #region Public Methods /// /// This method need to be run first. /// In this method all values of tidy tool window will be refreshed: files list, check number. After that will be made tidy /// /// public void InitTidyToolWindow(List filesPath) { RefreshValues(); CheckAll(); TidyFilesAsync(filesPath); } /// /// Create and add new headers in files list based on file path /// /// public void AddHeadersInFilesList(List filesPath) { //if tidy fix was made List resultHeadersList = new List(); foreach (string file in filesPath) { FileInfo path = new FileInfo(file); if (CheckIsHeader(file)) { var currentHeader = headers.Where(a => a.FullFileName == path.FullName).FirstOrDefault(); if (currentHeader != null) { currentHeader.IsChecked = true; UpdateCheckedNumber(currentHeader); //Remove old header (with disabled diff icon) if already exists in files list, add the new one var index = files.IndexOf(files.Where(f => f.FullFileName == currentHeader.FullFileName).FirstOrDefault()); if (index > -1) { files.RemoveAt(index); } //Add current header on wich was made tidy to files MarkFixedFiles(new List { currentHeader }); resultHeadersList.Add(currentHeader); } } } var result = UnifyFileModelLists(files.ToList(), resultHeadersList); files.Clear(); foreach (var currentFile in result) { files.Add(new FileModel(currentFile)); } UpdateTidyToolWindowCheckBox(); } /// /// Refresh values, create and add new fils in files list based on file path /// /// public void AddFilesInFilesList(List filesPath) { RefreshValues(); foreach (string file in filesPath) { FileInfo path = new FileInfo(file); if (CheckIsHeader(file)) { headers.Add(new FileModel { FileName = ". . . " + Path.Combine(path.Directory.Name, path.Name), FullFileName = path.FullName, CopyFullFileName = Path.Combine(TidyConstants.TempsFolderPath, TidyConstants.SolutionTempGuid, Guid.NewGuid().ToString()) + path.Extension, FilesType = FileType.Header }); } else { files.Add(new FileModel { FileName = ". . . " + Path.Combine(path.Directory.Name, path.Name), FullFileName = path.FullName, CopyFullFileName = Path.Combine(TidyConstants.TempsFolderPath, TidyConstants.SolutionTempGuid, Guid.NewGuid().ToString()) + path.Extension, FilesType = FileType.SourceFile }); } } CheckAll(); } private string GetExtension(string path) { Regex regex = new Regex(@"([A-Z]:\\.+?\.(cpp|cu|cc|cp|tlh|c|cxx|tli|h|hh|hpp|hxx))(\W|$)"); Match match = regex.Match(path); return match.Value; } /// /// Applies tidy fix on all selected source files or just on single file and makes diff after /// /// /// public async Task FixAllFilesAsync(FileModel file = null) { BeforeCommand(); var filesPaths = new List(); var filesPathsCopy = new List(); if (file is null) { //Get checked and unfixed files filesPathsCopy = files.Where(f => f.IsChecked && f.IsFixed == false && f.FilesType != FileType.Header).ToList(); filesPaths = files.Where(f => f.IsChecked && f.FilesType != FileType.Header).Select(f => f.FullFileName).ToList(); } else { if (!file.IsChecked) { file.IsChecked = true; UpdateCheckedNumber(file); } filesPathsCopy = new List { file }; filesPaths = new List { file.FullFileName }; } FileCommand.CopyFilesInTempSolution(UnifyFileModelLists(filesPathsCopy, headers)); await CommandControllerInstance.CommandController.LaunchCommandAsync(CommandIds.kTidyFixId, CommandUILocation.ContextMenu, filesPaths); MarkFixedFiles(filesPathsCopy); if (file is not null) { DiffBetweenCopyAndCurrent(file); } AfterCommand(); } /// /// Update checked numer on check and uncheck action /// /// public void UpdateCheckedNumber(FileModel file) { if (file.IsChecked) { //Check "global" checkbox if all files are checked tidyToolWindowModel.CountFilesModel.CheckFileUpdate(file); tidyToolWindowModel.IsChecked = tidyToolWindowModel.CountFilesModel.TotalCheckedFiles == files.Count ? true : false; } else { //Uncheck "global" checkbox if no file is checked tidyToolWindowModel.CountFilesModel.UnCheckFileUpdate(file); tidyToolWindowModel.IsChecked = tidyToolWindowModel.CountFilesModel.TotalCheckedFiles == 0 || tidyToolWindowModel.CountFilesModel.TotalCheckedFiles != files.Count ? false : true; } } /// /// Update Tidy Tool Window checkbox /// public void UpdateTidyToolWindowCheckBox() { tidyToolWindowModel.IsChecked = tidyToolWindowModel.CountFilesModel.TotalCheckedFiles == files.Count ? true : false; tidyToolWindowModel.IsChecked = tidyToolWindowModel.CountFilesModel.TotalCheckedFiles == 0 || tidyToolWindowModel.CountFilesModel.TotalCheckedFiles != files.Count ? false : true; } /// /// Make a diff betweeen copy file and current file /// /// public void DiffBetweenCopyAndCurrent(FileModel file) { BeforeCommand(); FileCommand.DiffFilesUsingDefaultTool(FileCommand.GetShortPath(file.CopyFullFileName), FileCommand.GetShortPath(file.FullFileName)); AfterCommand(); } public void CheckOrUncheckAll() { if (tidyToolWindowModel.IsChecked) { CheckAll(); } else { UncheckAll(); } } /// /// Set isRunning for every file to make icons disabled /// public void BeforeCommand() { tidyToolWindowModel.IsRunning = true; foreach (var file in files) { file.IsRunning = true; } } /// /// Set isRunning for every file to make icons disabled /// public void AfterCommand() { tidyToolWindowModel.IsRunning = false; foreach (var file in files) { file.IsRunning = false; } } /// /// Mark fixed files by adding a dot charcter "•" to the end of file name and /// update total number of fixed source files and headers /// /// public void MarkFixedFiles(List fixedFiles) { foreach (var file in fixedFiles) { if (!file.IsFixed) { file.IsFixed = true; file.FileName += " •"; tidyToolWindowModel.CountFilesModel.UpdateFixFileState(file); } } } /// /// Replace current file on which was made tidy fix with a copy /// /// public void DiscardFile(FileModel file) { var fileChangerWatcher = new FileChangerWatcher(); var dte2 = VsServiceProvider.GetService(typeof(DTE2)) as DTE2; string solutionFolderPath = SolutionInfo.IsOpenFolderModeActive() ? dte2.Solution.FullName : dte2.Solution.FullName .Substring(0, dte2.Solution.FullName.LastIndexOf('\\')); fileChangerWatcher.Run(solutionFolderPath); FileCommand.CopyFileFromTempToSolution(file); MarkUnfixedFiles(file); } /// /// Remove selected files from files list /// public void RemoveFiles(FileModel customFile = null) { BeforeCommand(); if (customFile is not null) { //Remove file from list var removeFile = files.Where(f => f.IsChecked && f.FullFileName == customFile.FullFileName).SingleOrDefault(); if (removeFile is not null) { //Mark as checked, and restore to initial properties to be removed after removeFile.IsChecked = false; UpdateCheckedNumber(removeFile); removeFile.IsChecked = true; files.Remove(removeFile); } } else { foreach (var file in files.ToList()) { if (file.IsChecked) { //Mark as checked, and restore to initial properties to be removed after file.IsChecked = false; UpdateCheckedNumber(file); file.IsChecked = true; files.Remove(file); } } } UpdateTidyToolWindowCheckBox(); AfterCommand(); } public async Task TidyFilesAsync(List paths = null) { BeforeCommand(); if (paths is null) { paths = files.Where(f => f.IsChecked && f.FilesType != FileType.Header).Select(f => f.FullFileName).ToList(); } await CommandControllerInstance.CommandController.LaunchCommandAsync(CommandIds.kTidyToolWindowId, CommandUILocation.ContextMenu, paths); AfterCommand(); } /// /// Mark unfixed files by removing a dot charcter "•" to the end of file name and /// update total number of unfixed source files and headers /// /// public void MarkUnfixedFiles(List checkedFiles) { foreach (var file in checkedFiles) { MarkUnfixedFiles(file); } } #endregion #region Private Method private bool CheckIsHeader(string fullFilePath) { FileInfo path = new FileInfo(fullFilePath); return path.FullName.Contains(".h") || path.FullName.Contains(".hpp") || path.FullName.Contains(".hh") || path.FullName.Contains(".hxx"); } /// /// Check all files /// private void CheckAll() { foreach (var file in files) { file.IsChecked = true; UpdateCheckedNumber(file); } tidyToolWindowModel.IsChecked = true; tidyToolWindowModel.CountFilesModel.UpdateTotalChecked(files); } private void UncheckAll() { foreach (var file in files) { file.IsChecked = false; UpdateCheckedNumber(file); } tidyToolWindowModel.IsChecked = false; tidyToolWindowModel.CountFilesModel.UpdateToUncheckAll(); } private void MarkUnfixedFiles(FileModel file) { if (file.IsFixed) { file.IsFixed = false; file.FileName = file.FileName.Remove(file.FileName.Length - 2, 2); tidyToolWindowModel.CountFilesModel.UpdateFixFileState(file); } } private List UnifyFileModelLists(List firstList, List secondList) { var fileUnion = new List(); foreach (var file in firstList) { fileUnion.Add(file); } foreach (var file in secondList) { fileUnion.Add(file); } return fileUnion; } /// /// Refresh values after tidy from toolbar or contextMenu /// private void RefreshValues() { files.Clear(); headers.Clear(); tidyToolWindowModel.IsChecked = false; tidyToolWindowModel.CountFilesModel.UpdateToUncheckAll(); } } #endregion } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/FindToolWindowHandler.cs ================================================ using ClangPowerTools; using ClangPowerToolsShared.MVVM.Provider; using ClangPowerToolsShared.MVVM.ViewModels; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace ClangPowerToolsShared.MVVM { public class FindToolWindowHandler { public static Action RefreshHistoryMatchersView; private const string matchersHistoryFileName = "matchersHistory.json"; private string matcherHistoryPath = string.Empty; public FindToolWindowHandler() { var settingsPathBuilder = new SettingsPathBuilder(); matcherHistoryPath = Path.Combine(settingsPathBuilder.GetPath(matcherHistoryPath), matchersHistoryFileName); } public void Initialize() { if (File.Exists(matcherHistoryPath)) { LoadFindToolWindowData(); } } public void SaveMatchersHistoryData() { SerializeHistoryData(FindToolWindowProvider.AutoCompleteHistory, matcherHistoryPath); } private void SerializeHistoryData(List models, string path) { using StreamWriter file = File.CreateText(path); var serializer = new JsonSerializer { Formatting = Formatting.Indented }; serializer.Serialize(file, models); file.Close(); } private string ReadFile(string path) { using StreamReader sw = new StreamReader(path); return sw.ReadToEnd(); } public void LoadFindToolWindowData() { if (File.Exists(matcherHistoryPath)) { string json = ReadFile(matcherHistoryPath); if (!string.IsNullOrEmpty(json)) DeserializeMatchersHistory(json); } } public void LoadFindToolWindowData(string path) { if (File.Exists(path)) { string json = ReadFile(path); DeserializeMatchersHistory(json); RefreshHistoryMatchersView?.Invoke(); } } private void DeserializeMatchersHistory(string json) { try { var history = JsonConvert.DeserializeObject>(json); FindToolWindowProvider.UpdateAutoCompleteList(history); } catch (Exception e) { MessageBox.Show(e.Message, "Cannot Load Clang Power Tools Find Tool Window Data", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/IAccountValidator.cs ================================================ namespace ClangPowerTools.MVVM.Interfaces { interface IAccountValidator: ILicense { } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/IDownload.cs ================================================ using System.ComponentModel; using System.Net; namespace ClangPowerTools.MVVM.Interfaces { public interface IDownload { void Download(string uri, DownloadProgressChangedEventHandler method); void DownloadCompleted(object sender, AsyncCompletedEventArgs e); CancelEventHandler SettingsWindowClosed { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/IInstall.cs ================================================ using System; namespace ClangPowerTools.MVVM.Interfaces { public interface IInstall { void Install(string path); void Uninstall(string path); EventHandler InstallFinished { get; set; } EventHandler UninstallFinished { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/ILicense.cs ================================================ using System.Threading.Tasks; namespace ClangPowerTools.MVVM.Interfaces { /// /// Contains license validation and token retrival main behavior /// public interface ILicense { /// /// Check if the user license is active /// /// True if the license is active. False otherwise Task ValidateAsync(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/IView.cs ================================================ namespace ClangPowerTools.MVVM.Interfaces { interface IView { public void ResetView(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Interfaces/IViewMatche.cs ================================================ namespace ClangPowerToolsShared.MVVM.Interfaces { public interface IViewMatcher { string Name { get; } int Id { get; } string Details { get; } string Visibility { get; } void Hide(); void Show(); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LicenseValidation/CommercialLicenseValidator.cs ================================================ using ClangPowerTools.MVVM.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; namespace ClangPowerTools.MVVM.LicenseValidation { /// /// Contains the logic for the commercial license verification /// public class CommercialLicenseValidator : PersonalLicenseValidator { #region ILicenseValidator Implementation /// /// Verify if the user license is active. /// /// True if the user license is active. False otherwise. public new async Task ValidateAsync() { try { var token = new Token(); if (token.GetToken(out string jwt) == false) return false; KeyValuePair httpResponse = await CheckUserAccountAsync(jwt); if (httpResponse.Key == false) return false; List licenses = JsonConvert.DeserializeObject < List < LicenseModel >> (await httpResponse.Value.Content.ReadAsStringAsync()); return licenses.Count > 0 && VerifyLicense(licenses); } catch (Exception) { return false; } } #endregion #region Private Methods /// /// Verify if at least one of the user licenses is active. /// /// The HTTP server response for user token /// True if at least one of the user licenses is active. False otherwise. private bool VerifyLicense(List licenses) { return licenses.Any(license => CheckExpirationDate(license.expires)) == false; } /// /// Check if the license expired /// /// The expiration date as string /// True if the license expired. False otherwise. private bool CheckExpirationDate(string expirationDate) { DateTime.TryParse(expirationDate, out DateTime expirationDateTime); return DateTime.Compare(DateTime.Now, expirationDateTime) > 0; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LicenseValidation/LicenseType.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using System.Runtime.Serialization; namespace ClangPowerTools.MVVM.LicenseValidation { [Serializable] [JsonConverter(typeof(StringEnumConverter))] public enum LicenseType { [EnumMember(Value = "Commercial")] Commercial, [EnumMember(Value = "Personal")] Personal, [EnumMember(Value = "Trial")] Trial, [EnumMember(Value = "SessionExpired")] SessionExpired, [EnumMember(Value = "NoLicense")] NoLicense } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LicenseValidation/LocalLicenseValidator.cs ================================================ using ClangPowerTools.MVVM.Interfaces; using System.Threading.Tasks; namespace ClangPowerTools.MVVM.LicenseValidation { public class LocalLicenseValidator : ILicense { #region ILicense Implementation /// /// Check the if the user license from the disk is active. /// /// True if the license is active. False otherwise public Task ValidateAsync() { var token = new Token(); return Task.FromResult(token.GetToken(out _)); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LicenseValidation/PersonalLicenseValidator.cs ================================================ using ClangPowerTools.MVVM.Interfaces; using ClangPowerTools.MVVM.WebApi; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; namespace ClangPowerTools.MVVM.LicenseValidation { public class PersonalLicenseValidator : ILicense { public async Task ValidateAsync() { try { var token = new Token(); if (token.GetToken(out string jwt) == false) return false; KeyValuePair httpResponse = await CheckUserAccountAsync(jwt); return httpResponse.Key; } catch (Exception) { return false; } } /// /// Check if a user account is associeted to the given token /// /// The user license token /// Pair of status code and HTTP resonse message. Status code is true if the user account is active. /// Otherwise status code is false protected async Task> CheckUserAccountAsync(string token) { ApiUtility.InitializeApiClient(); ApiUtility.ApiClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); HttpResponseMessage userTokenHttpResponse = await ApiUtility.ApiClient.GetAsync(WebApiUrl.licenseUrl); return new KeyValuePair(userTokenHttpResponse.IsSuccessStatusCode == true, userTokenHttpResponse); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LicenseValidation/Token.cs ================================================ using System.IO; namespace ClangPowerTools.MVVM.LicenseValidation { public class Token { #region Members /// /// License token name /// private readonly string fileName = "ctpjwt"; #endregion #region ILicense Implementation /// /// Get the license token path /// /// License token path if the file exists. Empty string otherwise. private string GetTokenPath() { var settingsPathBuilder = new SettingsPathBuilder(); string filePath = settingsPathBuilder.GetPath(fileName); return File.Exists(filePath) == true ? filePath : string.Empty; } /// /// Get the content of the license token /// /// Content of license token /// True if the content of license token was succesfully extracted. False otherwise public bool GetToken(out string jwt) { jwt = null; var filePath = GetTokenPath(); if (string.IsNullOrWhiteSpace(filePath)) return false; using var streamReader = new StreamReader(filePath); jwt = streamReader.ReadLine(); return string.IsNullOrWhiteSpace(jwt) == false; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/LlvmUri.cs ================================================ using ClangPowerTools.MVVM.Constants; using System; namespace ClangPowerTools.MVVM { public class LlvmUri { public string GetDefaultUri(string version) { return string.Concat(LlvmConstants.ReleasesUri, "/", version, "/", LlvmConstants.Llvm, "-", version, GetOperatingSystemParamaters()); } public string GetGitHubUri(string version) { return string.Concat(LlvmConstants.GitHubUri, "/llvmorg-", version, "/", LlvmConstants.Llvm, "-", version, GetOperatingSystemParamaters()); } private string GetOperatingSystemParamaters() { return Environment.Is64BitOperatingSystem ? LlvmConstants.Os64Paramater : LlvmConstants.Os32Paramater; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/AccountApiModel.cs ================================================ namespace ClangPowerTools.MVVM.Models { public class AccountApiModel { #region Properties public string firstname { get; set; } = string.Empty; public string lastname { get; set; } = string.Empty; public string email { get; set; } = string.Empty; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/AccountModel.cs ================================================ using ClangPowerTools.MVVM.LicenseValidation; namespace ClangPowerTools.MVVM.Models { public class AccountModel { #region Properties public string UserName { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public LicenseType LicenseType { get; set; } = LicenseType.NoLicense; public string LicenseExpirationDate { get; set; } = "Never"; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/CompilerSettingsModel.cs ================================================ using System.ComponentModel; using System.Windows.Forms; namespace ClangPowerTools { public class CompilerSettingsModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool powershell7 = false; public string CompileFlags { get; set; } = DefaultOptions.ClangFlags; public string FilesToIgnore { get; set; } = string.Empty; public string ProjectsToIgnore { get; set; } = string.Empty; public ClangGeneralAdditionalIncludes AdditionalIncludes { get; set; } = ClangGeneralAdditionalIncludes.IncludeDirectories; public bool WarningsAsErrors { get; set; } = false; public bool ContinueOnError { get; set; } = false; public bool ClangAfterMSVC { get; set; } = false; public string VerbosityLevel { get; set; } = "0"; public bool Powershell7 { get { return powershell7; } set { if(value && string.IsNullOrEmpty(PowerShellWrapper.GetFilePathFromEnviromentVar(ScriptConstants.kPwsh))) { MessageBox.Show("Sorry, we can't find Powershell 7 in PATH enviroment variables", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } powershell7 = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Powershell7")); } } public bool ShowErrorList { get; set; } = true; public bool ShowOutputWindow { get; set; } = true; public bool ShowSquiggles { get; set; } = false; public int CpuLimit { get; set; } = 100; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/FileModel.cs ================================================ using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Models; using ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels; using System.ComponentModel; namespace ClangPowerTools.MVVM.Models { public class FileModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private bool isRunning; private bool isFixed; private bool isChecked; private string filename; #endregion #region Constructor public FileModel() { //init private icons diffIcon = new IconModel(VSThemeCommand.GetDiffIconEnabled(), UIElementsConstants.Hidden, false, "Diff"); tidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true, "Fix"); //init public icons DiffIcon = new IconModel(VSThemeCommand.GetDiffIconEnabled(), UIElementsConstants.Hidden, false); TidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true); } public FileModel(FileModel file) { //init private icons diffIcon = new IconModel(VSThemeCommand.GetDiffIconEnabled(), UIElementsConstants.Hidden, false, "Diff"); tidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true, "Fix"); //init public icons DiffIcon = new IconModel(VSThemeCommand.GetDiffIconEnabled(), UIElementsConstants.Hidden, false); TidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true); this.FileName = file.FileName; this.FullFileName = file.FullFileName; this.CopyFullFileName = file.CopyFullFileName; this.DiffIcon = file.DiffIcon; this.TidyFixIcon = file.TidyFixIcon; this.IsFixed = file.IsFixed; this.IsRunning = file.IsRunning; this.IsChecked = file.IsChecked; this.FilesType = file.FilesType; } #endregion #region Public Properities public FileType FilesType { get; set; } public string FilesTypeString { get { if (FilesType == FileType.SourceFile) return "Source files"; else return "Affected headers"; } } public string FileName { get { return filename; } set { filename = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FileName")); } } public string FullFileName { get; set; } public string CopyFullFileName { get; set; } private IconModel diffIcon; public IconModel DiffIcon { get { return diffIcon; } set { diffIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DiffIcon")); } } private IconModel tidyFixIcon; public IconModel TidyFixIcon { get { return tidyFixIcon; } set { tidyFixIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyFixIcon")); } } public bool IsFixed { get { return isFixed; } set { if (value) { DiffIcon.Visibility = UIElementsConstants.Visibile; DiffIcon.IsEnabled = true; TidyFixIcon.Visibility = UIElementsConstants.Hidden; TidyFixIcon.IsEnabled = false; } else { TidyFixIcon.Visibility = UIElementsConstants.Visibile; TidyFixIcon.IsEnabled = true; DiffIcon.Visibility = UIElementsConstants.Hidden; DiffIcon.IsEnabled = false; } if (isFixed == value) return; isFixed = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsFixed")); } } public bool IsRunning { get { return isRunning; } set { if (value) { TidyFixIcon.IsEnabled = false; TidyFixIcon.IconPath = IconResourceConstants.FixDisabled; DiffIcon.IsEnabled = false; DiffIcon.IconPath = IconResourceConstants.DiffDisabled; } else { TidyFixIcon.IsEnabled = true; TidyFixIcon.IconPath = VSThemeCommand.GetTidyFixIconEnabled(); DiffIcon.IsEnabled = true; DiffIcon.IconPath = VSThemeCommand.GetDiffIconEnabled(); } isRunning = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsRunning")); } } public bool IsChecked { get { return isChecked; } set { if (isChecked == value) { return; } isChecked = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked")); } } /// /// Change theme just for enabled icons /// public void ChangeIconsTheme() { DiffIcon.IconPath = DiffIcon.IsEnabled == true ? VSThemeCommand.GetDiffIconEnabled() : IconResourceConstants.DiffDisabled; TidyFixIcon.IconPath = TidyFixIcon.IsEnabled == true ? VSThemeCommand.GetTidyFixIconEnabled() : IconResourceConstants.FixDisabled; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/FormatSettingsModel.cs ================================================ namespace ClangPowerTools { public class FormatSettingsModel { public string FileExtensions { get; set; } = DefaultOptions.FileExtensions; public string FilesToIgnore { get; set; } = DefaultOptions.IgnoreFiles; public string AssumeFilename { get; set; } = string.Empty; public string CustomExecutable { get; set; } = string.Empty; public ClangFormatStyle Style { get; set; } = ClangFormatStyle.file; public ClangFormatFallbackStyle FallbackStyle { get; set; } = ClangFormatFallbackStyle.none; public bool FormatOnSave { get; set; } = false; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/GeneralSettingsModel.cs ================================================ namespace ClangPowerTools { public class GeneralSettingsModel { public string Version { get; set; } = string.Empty; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/InputDataModel.cs ================================================ using System.ComponentModel; namespace ClangPowerTools.MVVM.Models { public class InputDataModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private bool isReadOnly = false; private string inputData = string.Empty; #endregion public InputDataModel(string input) { inputData = input; } #region Properties public string InputData { get { return inputData; } set { inputData = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("InputData")); } } public bool IsReadOnly { get { return isReadOnly; } set { isReadOnly = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CanEdit")); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/LicenseModel.cs ================================================ namespace ClangPowerTools.MVVM.Models { public class LicenseModel { public string _id { get; set; } = ""; public bool active = false; public string expires = ""; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/LlvmModel.cs ================================================ using System.ComponentModel; namespace ClangPowerTools { public class LlvmModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private readonly LlvmSettingsModel llvmSettingsModel = new LlvmSettingsModel(); private bool isDownloading = false; private bool isInstalling = false; private bool isInstalled = false; private bool hasPreinstalledLlvm = false; private bool canExecuteCommand = true; private int downloadProgress = 0; #endregion #region Properties public string Version { get { return llvmSettingsModel.LlvmSelectedVersion; } set { llvmSettingsModel.LlvmSelectedVersion = value; } } public bool IsInstalled { get { return isInstalled; } set { isInstalled = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsInstalled")); } } public bool IsInstalling { get { return isInstalling; } set { isInstalling = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsInstalling")); } } public bool IsDownloading { get { return isDownloading; } set { isDownloading = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsDownloading")); } } public bool CanExecuteCommand { get { return canExecuteCommand; } set { canExecuteCommand = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CanExecuteCommand")); } } public int DownloadProgress { get { return downloadProgress; } set { downloadProgress = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DownloadProgress")); } } public int MinProgress { get; set; } = 0; public int MaxProgress { get; set; } = 100; public string PreinstalledLlvmPath { get { return llvmSettingsModel.PreinstalledLlvmPath; } set { llvmSettingsModel.PreinstalledLlvmPath = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreinstalledLlvmPath")); } } public bool HasPreinstalledLlvm { get { return hasPreinstalledLlvm; } set { hasPreinstalledLlvm = value; } } #endregion Properties } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/LlvmSettingsModel.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClangPowerTools { public class LlvmSettingsModel { public string LlvmSelectedVersion { get; set; } = string.Empty; public string PreinstalledLlvmVersion { get; set; } = string.Empty; public string PreinstalledLlvmPath { get; set; } = string.Empty; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/MessageModel.cs ================================================ using ClangPowerToolsShared.MVVM.Constants; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models { public class MessageModel { #region Members public event PropertyChangedEventHandler PropertyChanged; private string textMessage = string.Empty; private string visibility = UIElementsConstants.Hidden; #endregion #region Properities public string Visibility { get { return visibility; } set { visibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Visibility")); } } public string TextMessage { get { return textMessage; } set { textMessage = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TextMessage")); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/SelectedFileModel.cs ================================================ using System.IO; namespace ClangPowerTools.MVVM.Models { public class SelectedFileModel { #region Members private const int MAX_FILE_SIZE = 80; // KB #endregion #region Constructor public SelectedFileModel(string path, string pathToShow) { if (!File.Exists(path)) return; FilePath = path; FileSize = new FileInfo(FilePath).Length / 1000; if (FileSize == 0) { FileSize = 1; } FilePathToShow = pathToShow; ForgroundColor = FileSize > MAX_FILE_SIZE ? "DarkOrange" : "Black"; FileSizeAsString = FileSize.ToString() + " KB"; } #endregion #region Properties public string FilePath { get; private set; } public string FilePathToShow { get; private set; } public long FileSize { get; private set; } public string FileSizeAsString { get; private set; } public string ForgroundColor { get; private set; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/TidyCheckModel.cs ================================================ using ClangPowerTools.MVVM; using System.ComponentModel; namespace ClangPowerTools { public class TidyCheckModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private bool isChecked = false; #endregion #region Properties public string Name { get; set; } = string.Empty; public bool IsChecked { get { return isChecked; } set { // Take in consideration every change of the state if the collection is not empty if (!CollectionElementsCounter.IsEmpty()) { if (value) CollectionElementsCounter.Add(); else CollectionElementsCounter.Remove(); } isChecked = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked")); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/TidySettingsModel.cs ================================================ namespace ClangPowerTools { public class TidySettingsModel { public string HeaderFilter { get; set; } = DefaultOptions.HeaderFilter; public ClangTidyUseChecksFrom UseChecksFrom { get; set; } = ClangTidyUseChecksFrom.PredefinedChecks; public string PredefinedChecks { get; set; } = string.Empty; public string CustomChecks { get; set; } = string.Empty; public string CustomExecutable { get; set; } = string.Empty; public string CompilationDatabase { get; set; } = string.Empty; public bool DetectClangTidyFile { get; set; } = true; public bool FormatAfterTidy { get; set; } = false; public bool TidyOnSave { get; set; } = false; public bool ApplyTidyFix { get; set; } = false; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToggleModel.cs ================================================ namespace ClangPowerTools.MVVM.Models { public class ToggleModel { #region Properties public string Name { get; set; } public ToggleValues Value { get; set; } #endregion #region Constructor public ToggleModel(string name, ToggleValues value) { Name = name; Value = value; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/TokenModel.cs ================================================ namespace ClangPowerTools { public class TokenModel { public string jwt { get; set; } = ""; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/AutoCompleteHistoryModel.cs ================================================ using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Provider; using ClangPowerToolsShared.MVVM.ViewModels; using System; using System.ComponentModel; using System.Windows.Forms; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class AutoCompleteHistoryModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public string Id { get; set; } = Guid.NewGuid().ToString(); public string Value { get; set; } = string.Empty; private string visibility = string.Empty; private string tooltip = string.Empty; public string Tooltip { get { return tooltip; } set { tooltip = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Tooltip")); } } public string Visibility { get { return visibility; } set { visibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Visibility")); } } private bool rememberAsFavorit = false; public bool RememberAsFavorit { get { return rememberAsFavorit; } set { SetIcon(value); } } private string pinIconPath { get; set; } public string PinIconPath { get { return pinIconPath; } set { pinIconPath = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PinIconPath")); } } public AutoCompleteHistoryModel(bool isHistory = false) { UpdateVisibility(isHistory); } public bool Pin() { if (FindToolWindowProvider.CheckRememberFavoritIsMax(this) && !rememberAsFavorit) { DialogResult dialogResult = MessageBox.Show("You reached the limit(20 matchers) of favorite custom matchers, unpin from favorite to add new matcher", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } rememberAsFavorit = !rememberAsFavorit; RememberAsFavorit = rememberAsFavorit; FindToolWindowProvider.UpdateFavoriteValue(this, !rememberAsFavorit); FindToolWindowHandler findToolWindowHandler = new FindToolWindowHandler(); findToolWindowHandler.SaveMatchersHistoryData(); return true; } public AutoCompleteHistoryModel(AutoCompleteHistoryViewModel autoCompleteHistoryViewModel, bool isHistory = true) { Id = autoCompleteHistoryViewModel.Id; rememberAsFavorit = autoCompleteHistoryViewModel.RememberAsFavorit; RememberAsFavorit = rememberAsFavorit; Value = autoCompleteHistoryViewModel.Value; UpdateVisibility(isHistory); rememberAsFavorit = autoCompleteHistoryViewModel.RememberAsFavorit; } private void UpdateVisibility(bool isHistory) { if (isHistory) visibility = UIElementsConstants.Visibile; else visibility = UIElementsConstants.Hidden; Visibility = visibility; } private void SetIcon(bool value) { if (value) { tooltip = UIElementsConstants.Unpin; pinIconPath = VSThemeCommand.GetPinIcon(); } else { tooltip = UIElementsConstants.Pin; pinIconPath = VSThemeCommand.GetUnpinIcon(); } Tooltip = tooltip; PinIconPath = pinIconPath; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/ComponentVisibility.cs ================================================ using ClangPowerToolsShared.MVVM.Constants; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class ComponentVisibility : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string visibility = string.Empty; public ComponentVisibility() { visibility = UIElementsConstants.Hidden; } public string Visibility { get { return visibility; } } public void Hide() { visibility = UIElementsConstants.Hidden; } public void Show() { visibility = UIElementsConstants.Visibile; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/CountStateFilesModel.cs ================================================ using ClangPowerTools.MVVM.Models; using System.Collections.ObjectModel; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels { /// /// This class can be used to store all data about files state /// public class CountFilesModel : INotifyPropertyChanged { #region Properies public event PropertyChangedEventHandler PropertyChanged; private int totalCheckedFixedFiles = 0; private int totalCheckedFixedHeaders = 0; private int totalCheckedFixedSouceFiles = 0; private int totalCheckedSourceFiles = 0; private int totalCheckedHeaders = 0; private int totalCheckedFiles = 0; /// /// Returns number of checked fixed files at this moment /// public int TotalCheckedFixedFiles { get { return totalCheckedFixedFiles; } private set { totalCheckedFixedFiles = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedFixedFiles")); } } /// /// Returns number of checked fixed headers at this moment /// public int TotalCheckedFixedHeaders { get { return totalCheckedFixedHeaders; } private set { totalCheckedFixedHeaders = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedFixedHeaders")); } } /// /// Returns number of checked fixed source files at this moment /// public int TotalCheckedFixedSouceFiles { get { return totalCheckedFixedSouceFiles; } private set { totalCheckedFixedSouceFiles = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedFixedSouceFiles")); } } /// /// Returns number of checked source files at this moment /// public int TotalCheckedSourceFiles { get { return totalCheckedSourceFiles; } private set { totalCheckedSourceFiles = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedSourceFiles")); } } /// /// Returns number of checked headers at this moment /// public int TotalCheckedHeaders { get { return totalCheckedHeaders; } private set { totalCheckedHeaders = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedHeaders")); } } /// /// Returns number of checked files at this moment /// public int TotalCheckedFiles { get { return totalCheckedFiles; } private set { totalCheckedFiles = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCheckedFiles")); } } #endregion #region Methods /// /// Total checked property will be updated with number of files /// /// public void UpdateTotalChecked(ObservableCollection files) { TotalCheckedFiles = files.Count; } /// /// Update properties refering on check file /// public void CheckFileUpdate(FileModel file) { if (file is not null && file.IsChecked) { ++TotalCheckedFiles; if (file.FilesType == FileType.SourceFile) ++TotalCheckedSourceFiles; if (file.FilesType == FileType.Header) ++TotalCheckedHeaders; //Update values for fixed files if (file.IsFixed) { ++TotalCheckedFixedFiles; if (file.FilesType == FileType.SourceFile) { ++TotalCheckedFixedSouceFiles; } if (file.FilesType == FileType.Header) { ++TotalCheckedFixedHeaders; } } } } /// /// Update properties refering on uncheck file /// public void UnCheckFileUpdate(FileModel file) { if (file is not null && !file.IsChecked) { --TotalCheckedFiles; if (file.FilesType == FileType.SourceFile) --TotalCheckedSourceFiles; if (file.FilesType == FileType.Header) --TotalCheckedHeaders; //Update values for fixed files if (file.IsFixed) { --TotalCheckedFixedFiles; if (file.FilesType == FileType.SourceFile) { --TotalCheckedFixedSouceFiles; } if (file.FilesType == FileType.Header) { --TotalCheckedFixedHeaders; } } } } /// /// Update all properties to 0 /// public void UpdateToUncheckAll() { TotalCheckedFixedFiles = 0; TotalCheckedFixedHeaders = 0; TotalCheckedFixedSouceFiles = 0; TotalCheckedSourceFiles = 0; TotalCheckedHeaders = 0; TotalCheckedFiles = 0; } /// /// Update fixed and unfixed number for source file and headers. /// Make changes of peroperties based on fact that passed file is fixed or unfixed /// public void UpdateFixFileState(FileModel file) { if (file.IsChecked) { if (file.IsFixed) { //Update just fix properties ++TotalCheckedFixedFiles; if (file.FilesType == FileType.SourceFile) { ++TotalCheckedFixedSouceFiles; } if (file.FilesType == FileType.Header) { ++TotalCheckedFixedHeaders; } } else { //Update just unfixed properties --TotalCheckedFixedFiles; if (file.FilesType == FileType.SourceFile) { --TotalCheckedFixedSouceFiles; } if (file.FilesType == FileType.Header) { --TotalCheckedFixedHeaders; } } } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/CustomMatchesModel.cs ================================================ using ClangPowerTools; using ClangPowerTools.Helpers; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Interfaces; using System.Collections.Generic; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class CustomMatchesModel : ComponentVisibility, IViewMatcher { public event PropertyChangedEventHandler PropertyChanged; private string matches = string.Empty; public CustomMatchesModel() { } public string Name { get; } = "Custom matches"; public int Id { get; } = FindCommandIds.kCustomMatchesId; public string Matchers { get { return matches; } set { matches = value; PowerShellWrapper.InteractivCommands = JoinUtility.AddMatcherKeyword(value); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Matches")); } } public string Details { get; } = "Ex: match functionDecl(hasName(\"test\")) // Matches call expressions with name test"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/DefaultArgsModel.cs ================================================ using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Interfaces; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class DefaultArgsModel : ComponentVisibility, IViewMatcher { public event PropertyChangedEventHandler PropertyChanged; private string functionName = string.Empty; private int defaultArgsPosition = 0; public DefaultArgsModel() { } public string Name { get; } = "Function called with default argument(s)"; public int Id { get; } = FindCommandIds.kDefaultArgsId; public string FunctionName { get { return functionName; } set { functionName = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FunctionName")); } } public int DefaultArgsPosition { get { return defaultArgsPosition; } set { defaultArgsPosition = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DefaultArgsPosition")); } } public string Details { get; } = "Matches invocations of a function where some of the parameters are not explicitly set (default parameters).\n\n" + "For example:\nvoid test(int p1 = 10, string p2 = \"a\") { }\n" + "test(); // Matched by 1 or 0 explicit arguments\n" + "test(20); // Matched by 1 explicit arguments\n" + "test(20, \"Z\"); // Never matched \n"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/FileType.cs ================================================ using System; using System.Collections.Generic; using System.Text; namespace ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels { public enum FileType { SourceFile, Header } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/FindControllerModel.cs ================================================ using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Interfaces; using System.Collections.Generic; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class FindControllerModel { protected string matcherDetails = string.Empty; public DefaultArgsModel DefaultArgsModel { get; set; } public CustomMatchesModel CustomMatchesModel { get; set; } public List ViewMatchers; protected IViewMatcher currentViewMatcher; public FindControllerModel() { DefaultArgsModel = new DefaultArgsModel(); CustomMatchesModel = new CustomMatchesModel(); ViewMatchers = new List(); ViewMatchers.Add(DefaultArgsModel); ViewMatchers.Add(CustomMatchesModel); currentViewMatcher = DefaultArgsModel; ShowSelectedModel(currentViewMatcher); } protected void HidePreviousSelectedModel() { currentViewMatcher.Hide(); } protected void ShowSelectedModel(IViewMatcher viewMatcher) { currentViewMatcher = viewMatcher; currentViewMatcher.Show(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/FindToolWindowModel.cs ================================================ using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Interfaces; using System.Collections.Generic; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.ToolWindowModels { public class FindToolWindowModel : FindControllerModel, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool isRunning = false; private ComponentVisibility progressBarVisibility = new(); private ComponentVisibility menuVisibility = new(); public FindToolWindowModel() { HideProgressBar(); menuVisibility.Show(); } public void UpdateUiToSelectedModel(IViewMatcher viewMatcher) { HidePreviousSelectedModel(); ShowSelectedModel(viewMatcher); CurrentViewMatcher = currentViewMatcher; } public string ProgressBarVisibility { get { return progressBarVisibility.Visibility; } } public string MenuVisibility { get { return menuVisibility.Visibility; } } public IViewMatcher CurrentViewMatcher { get { return currentViewMatcher; } set { currentViewMatcher = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentViewMatcher")); } } public bool IsEnabled { get { return !IsRunning; } set { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled")); } } public bool IsRunning { get { return isRunning; } set { if (value) ShowProgressBar(); else HideProgressBar(); isRunning = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsRunning")); } } private void ShowProgressBar() { progressBarVisibility.Show(); menuVisibility.Hide(); } private void HideProgressBar() { progressBarVisibility.Hide(); menuVisibility.Show(); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/IconModel.cs ================================================ using ClangPowerToolsShared.MVVM.Constants; using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace ClangPowerToolsShared.MVVM.Models { public class IconModel : INotifyPropertyChanged { #region Members private string iconPath; private string visibility; private string tooltip; private bool isEnabled; #endregion #region Constructors public IconModel() { } public IconModel(string iconPath, string visibility, bool isEnabled, string tooltip = "") { this.iconPath = iconPath; this.visibility = visibility; this.isEnabled = isEnabled; this.tooltip = tooltip; } #endregion #region Properties public event PropertyChangedEventHandler PropertyChanged; public string IconPath { get { return iconPath; } set { iconPath = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconPath")); } } public string Tooltip { get { return tooltip; } set { tooltip = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Tooltip")); } } public string Visibility { get { return visibility; } set { visibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Visibility")); } } public bool IsEnabled { get { return isEnabled; } set { isEnabled = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled")); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/ToolWindowModels/TidyToolWindowModel.cs ================================================ using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.Constants; using System.ComponentModel; namespace ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels { public class TidyToolWindowModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private bool isRunning; private string progressBarVisibility; private string buttonVisibility; private bool isChecked; public bool isDiscardEnabled; public CountFilesModel CountFilesModel; #endregion #region Constructors public TidyToolWindowModel() { //init private icons discardFixIcon = new IconModel(IconResourceConstants.DiscardFixDisabled, UIElementsConstants.Visibile, false); tidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true); refreshTidyIcon = new IconModel(VSThemeCommand.GetRefreshTidyIconEnabled(), UIElementsConstants.Visibile, true); removeIcon = new IconModel(VSThemeCommand.GetIgnoreIconEnabled(), UIElementsConstants.Visibile, true); //Init CountFilesModel = new CountFilesModel(); //Register events CountFilesModel.PropertyChanged += UpdateIconsOnPropertyChange; //Init public icons RemoveIcon = new IconModel(VSThemeCommand.GetIgnoreIconEnabled(), UIElementsConstants.Visibile, true); DiscardFixIcon = new IconModel(IconResourceConstants.DiscardFixDisabled, UIElementsConstants.Visibile, false); TidyFixIcon = new IconModel(VSThemeCommand.GetTidyFixIconEnabled(), UIElementsConstants.Visibile, true); RefreshTidyIcon = new IconModel(VSThemeCommand.GetRefreshTidyIconEnabled(), UIElementsConstants.Visibile, true); //Hide progress bar ProgressBarVisibility = UIElementsConstants.Hidden; ButtonVisibility = UIElementsConstants.Visibile; } #endregion #region Icons private IconModel discardFixIcon; public IconModel DiscardFixIcon { get { return discardFixIcon; } set { if (CountFilesModel.TotalCheckedFixedFiles == 0) { discardFixIcon.IconPath = IconResourceConstants.DiscardFixDisabled; discardFixIcon.IsEnabled = false; } else { discardFixIcon.IconPath = VSThemeCommand.GetDiscardFixIconEnabled(); discardFixIcon.IsEnabled = true; } discardFixIcon.Tooltip = $"Discard fix {CountFilesModel.TotalCheckedFixedFiles} files"; discardFixIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DiscardFixIcon")); } } private IconModel tidyFixIcon; public IconModel TidyFixIcon { get { return tidyFixIcon; } set { if (CountFilesModel.TotalCheckedFiles == 0 || CountFilesModel.TotalCheckedSourceFiles == CountFilesModel.TotalCheckedFixedSouceFiles || CountFilesModel.TotalCheckedSourceFiles == 0) { tidyFixIcon.IconPath = IconResourceConstants.FixDisabled; tidyFixIcon.IsEnabled = false; } else { tidyFixIcon.IconPath = VSThemeCommand.GetTidyFixIconEnabled(); tidyFixIcon.IsEnabled = true; } tidyFixIcon.Tooltip = $"Fix {CountFilesModel.TotalCheckedSourceFiles - CountFilesModel.TotalCheckedFixedSouceFiles} source files"; tidyFixIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyFixIcon")); } } private IconModel refreshTidyIcon; public IconModel RefreshTidyIcon { get { return refreshTidyIcon; } set { if (CountFilesModel.TotalCheckedFiles == 0 || CountFilesModel.TotalCheckedHeaders == CountFilesModel.TotalCheckedFiles) { refreshTidyIcon.IconPath = IconResourceConstants.RefreshDisabled; refreshTidyIcon.IsEnabled = false; } else { refreshTidyIcon.IconPath = VSThemeCommand.GetRefreshTidyIconEnabled(); refreshTidyIcon.IsEnabled = true; } refreshTidyIcon.Tooltip = $"Refresh tidy {CountFilesModel.TotalCheckedSourceFiles} source files"; refreshTidyIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("RefreshTidyIcon")); } } private IconModel removeIcon { get; set; } public IconModel RemoveIcon { get { return removeIcon; } set { if (CountFilesModel.TotalCheckedFiles == 0) { removeIcon.IconPath = IconResourceConstants.RemoveDisabled; removeIcon.IsEnabled = false; } else { removeIcon.IconPath = VSThemeCommand.GetIgnoreIconEnabled(); removeIcon.IsEnabled = true; } removeIcon.Tooltip = $"Ignore {CountFilesModel.TotalCheckedFiles} files"; removeIcon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("RemoveIcon")); } } #endregion #region Properties public bool IsChecked { get { return isChecked; } set { if (isChecked == value) { return; } isChecked = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsChecked")); } } public bool IsRunning { get { return isRunning; } set { if (value) { ProgressBarVisibility = UIElementsConstants.Visibile; ButtonVisibility = UIElementsConstants.Hidden; } else { ProgressBarVisibility = UIElementsConstants.Hidden; ButtonVisibility = UIElementsConstants.Visibile; } isRunning = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsRunning")); } } public string ProgressBarVisibility { get { return progressBarVisibility; } set { progressBarVisibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ProgressBarVisibility")); } } public string ButtonVisibility { get { return buttonVisibility; } set { buttonVisibility = value; RefreshTidyIcon.Visibility = value; TidyFixIcon.Visibility = value; DiscardFixIcon.Visibility = value; RemoveIcon.Visibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ButtonVisibility")); } } #endregion #region Methods /// /// Change theme just for enabled icons /// public void ChangeIconsTheme() { RefreshTidyIcon.IconPath = RefreshTidyIcon.IsEnabled ? VSThemeCommand.GetRefreshTidyIconEnabled() : IconResourceConstants.DiffDisabled; TidyFixIcon.IconPath = TidyFixIcon.IsEnabled ? VSThemeCommand.GetTidyFixIconEnabled() : IconResourceConstants.FixDisabled; DiscardFixIcon.IconPath = DiscardFixIcon.IsEnabled ? VSThemeCommand.GetDiscardFixIconEnabled() : IconResourceConstants.FixDisabled; RemoveIcon.IconPath = RemoveIcon.IsEnabled ? VSThemeCommand.GetIgnoreIconEnabled() : IconResourceConstants.FixDisabled; } /// /// Update icons /// /// /// private void UpdateIconsOnPropertyChange(object sender, System.EventArgs e) { TidyFixIcon = tidyFixIcon; DiscardFixIcon = discardFixIcon; RefreshTidyIcon = refreshTidyIcon; RemoveIcon = removeIcon; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Models/UserModel.cs ================================================ using System; namespace ClangPowerTools { public class UserModel : IDisposable { #region Properties public string email { get; set; } public string password { get; set; } #endregion #region Constructor public UserModel(string email, string password) { this.email = email; this.password = password; } public UserModel() { } public void Dispose() { email = string.Empty; password = string.Empty; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/ClangFormatPathValue.cs ================================================ namespace ClangPowerTools { public class ClangFormatPathValue { #region Members private string mValue = string.Empty; #endregion #region Properties public bool Enable { get; set; } = false; public string Value { get { return mValue; } set { mValue = value; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/ClangTidyPathValue.cs ================================================ namespace ClangPowerTools { public class ClangTidyPathValue { #region Members private string mValue = string.Empty; #endregion #region Properties public bool Enable { get; set; } = false; public string Value { get { return mValue; } set { mValue = value; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/HeaderFiltersValue.cs ================================================ namespace ClangPowerTools { public class HeaderFiltersValue { #region Members private string mHeaderFilterValue; #endregion #region Constructor public HeaderFiltersValue(string aValue) { mHeaderFilterValue = aValue; } #endregion #region Properties public string HeaderFilters { get { return mHeaderFilterValue; } set { mHeaderFilterValue = value; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/OldModels/ClangFormatOptions.cs ================================================ using System; namespace ClangPowerTools { [Serializable] public class ClangFormatOptions { #region Properties #region Format On Save public bool EnableFormatOnSave { get; set; } public string FileExtensions { get; set; } public string SkipFiles { get; set; } #endregion #region Format Options public string AssumeFilename { get; set; } public ClangFormatFallbackStyle FallbackStyle { get; set; } public ClangFormatStyle Style { get; set; } #endregion #region Clang-Format executable path public ClangFormatPathValue ClangFormatPath { get; set; } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/OldModels/ClangOptions.cs ================================================ namespace ClangPowerTools { public class ClangOptions { public string ProjectsToIgnore { get; set; } = string.Empty; public string ProjectsToIgnoreCollection { get; set; } = string.Empty; public string FilesToIgnore { get; set; } = string.Empty; public string FilesToIgnoreCollection { get; set; } = string.Empty; public bool Continue { get; set; } = false; public bool TreatWarningsAsErrors { get; set; } = false; public ClangGeneralAdditionalIncludes AdditionalIncludes { get; set; } = ClangGeneralAdditionalIncludes.IncludeDirectories; public string VerbosityLevel { get; set; } = "0"; public bool VerboseMode { get; set; } = false; public string ClangFlags { get; set; } = string.Empty; public string ClangFlagsCollection { get; set; } = DefaultOptions.ClangFlags; public bool ClangCompileAfterVsCompile { get; set; } = false; public string Version { get; set; } = string.Empty; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/OldModels/ClangTidyOptions.cs ================================================ using System; using System.Collections.Generic; namespace ClangPowerTools { [Serializable] public class ClangTidyOptions { #region Properties [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public List TidyChecks { get; set; } = new List(); public string TidyChecksCollection { get; set; } public bool AutoTidyOnSave { get; set; } public bool FormatAfterTidy { get; set; } public string HeaderFilter { get; set; } public ClangTidyUseChecksFrom TidyMode { get; set; } public ClangTidyPathValue ClangTidyPath { get; set; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/OldSettings/OldModels/DefaultOptions.cs ================================================ namespace ClangPowerTools { public class DefaultOptions { public const string ClangFlags = "-Wall;-fms-compatibility-version=19.10;-Wmicrosoft;-Wno-invalid-token-paste;-Wno-unknown-pragmas;-Wno-unused-value"; public const string HeaderFilter = ".*"; public const string FileExtensions = ".c;.cpp;.cxx;.cc;.cs;.tli;.tlh;.h;.hh;.hpp;.hxx;.inl;.ixx"; public const string IgnoreFiles = "resource.h"; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/PreinstalledLlvm.cs ================================================ using ClangPowerTools.MVVM.Controllers; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; namespace ClangPowerTools { public class PreinstalledLlvm { #region Members private readonly List llvms; private readonly ObservableCollection installedLlvms; private readonly LlvmController llvmController = new LlvmController(); #endregion public PreinstalledLlvm(List llvms, ObservableCollection installedLlvms) { this.llvms = llvms; this.installedLlvms = installedLlvms; } #region Methods public void SetPreinstalledLlvm(string path = null, string version = null) { var llvmSettingsModel = SettingsProvider.LlvmSettingsModel; if (path == null || version == null) GetPathAndVersion(out path, out version); if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(version)) return; SetPathAndVersion(path, version); if (llvmSettingsModel.PreinstalledLlvmVersion == string.Empty) return; if (!IsVersionInstalled(version)) installedLlvms.Add(llvmSettingsModel.PreinstalledLlvmVersion); } private bool IsVersionInstalled(string version) { foreach (var llvm in installedLlvms) { if (llvm == version) { return true; } } return false; } private void SetPathAndVersion(string path, string version) { var settingsProviderLlvmModel = SettingsProvider.LlvmSettingsModel; if (string.IsNullOrWhiteSpace(settingsProviderLlvmModel.PreinstalledLlvmVersion) || string.IsNullOrWhiteSpace(settingsProviderLlvmModel.PreinstalledLlvmPath) || (!string.IsNullOrWhiteSpace(path) && !string.IsNullOrWhiteSpace(version) && version != settingsProviderLlvmModel.PreinstalledLlvmVersion)) { settingsProviderLlvmModel.PreinstalledLlvmVersion = version; settingsProviderLlvmModel.PreinstalledLlvmPath = path; CommandControllerInstance.CommandController.DisplayMessage(true, $"ℹ Added successfully LLVM path: {path}"); } if (Directory.Exists(settingsProviderLlvmModel.PreinstalledLlvmPath) == false) { if (settingsProviderLlvmModel.PreinstalledLlvmVersion == settingsProviderLlvmModel.LlvmSelectedVersion) { settingsProviderLlvmModel.LlvmSelectedVersion = string.Empty; } settingsProviderLlvmModel.PreinstalledLlvmPath = string.Empty; settingsProviderLlvmModel.PreinstalledLlvmVersion = string.Empty; CommandControllerInstance.CommandController.DisplayMessage(false, $"ℹ Remove LLVM " + $"{settingsProviderLlvmModel.PreinstalledLlvmPath} from Clang Power Tools"); } } private void GetPathAndVersion(out string path, out string version) { path = string.Empty; version = string.Empty; var llvmSettingsModel = SettingsProvider.LlvmSettingsModel; if (installedLlvms.Count == 0) { path = llvmController.GetLlvmPathFromRegistry(); version = llvmController.GetVersionFromRegistry(); llvmSettingsModel.LlvmSelectedVersion = version; } if (path == string.Empty || version == string.Empty) { path = llvmSettingsModel.PreinstalledLlvmPath; version = llvmSettingsModel.PreinstalledLlvmVersion; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Provider/FindToolWindowProvider.cs ================================================ using ClangPowerToolsShared.MVVM.Models.ToolWindowModels; using ClangPowerToolsShared.MVVM.ViewModels; using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace ClangPowerToolsShared.MVVM.Provider { public class FindToolWindowProvider { private static readonly FindToolWindowProvider instance = new FindToolWindowProvider(); private static List autoCompleteHistory { get; set; } = new List(); public static FindToolWindowProvider Instance = new FindToolWindowProvider(); public static List AutoCompleteHistory { get { return autoCompleteHistory; } } public const int maxHistoryCount = 100; public const int maxFavoritHistoryCount = 20; public const int countToDelete = 15; public static void AddAutoCompleteHistory(AutoCompleteHistoryViewModel matcher) { if (autoCompleteHistory is null) autoCompleteHistory = new(); autoCompleteHistory.Insert(0, matcher); } public static void RemoveFromFullList() { if (autoCompleteHistory.Count >= maxHistoryCount) { autoCompleteHistory = autoCompleteHistory.OrderBy(u => u.RememberAsFavorit ? 0 : 1).ToList(); autoCompleteHistory.RemoveRange(maxFavoritHistoryCount, countToDelete); } } public static void UpdateFavoriteValue(AutoCompleteHistoryModel autoCompleteHistoryViewModel, bool favoriteValueChange) { var historyModel = autoCompleteHistory.Find(a => a.Value == autoCompleteHistoryViewModel.Value); if (historyModel != null) { historyModel.RememberAsFavorit = autoCompleteHistoryViewModel.RememberAsFavorit; } } public static bool CheckRememberFavoritIsMax(AutoCompleteHistoryModel autoCompleteHistoryViewModel) { var test = autoCompleteHistory.FindAll(a => a.RememberAsFavorit == true).Count >= maxFavoritHistoryCount; return autoCompleteHistory.FindAll(a => a.RememberAsFavorit == true).Count >= maxFavoritHistoryCount; } public static void UpdateAutoCompleteList(List autoCompleteHistoryViewModels) { if (autoCompleteHistory is null || autoCompleteHistoryViewModels is null) autoCompleteHistory = new List(); autoCompleteHistory = autoCompleteHistoryViewModels.OrderBy(u => u.RememberAsFavorit ? 0 : 1).ToList(); } static FindToolWindowProvider() { } private FindToolWindowProvider() { } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Provider/SettingsProvider.cs ================================================ using ClangPowerTools.MVVM.Models; using ClangPowerTools.Views; namespace ClangPowerTools { public class SettingsProvider { #region Properties public static CompilerSettingsModel CompilerSettingsModel { get; set; } = new CompilerSettingsModel(); public static FormatSettingsModel FormatSettingsModel { get; set; } = new FormatSettingsModel(); public static TidySettingsModel TidySettingsModel { get; set; } = new TidySettingsModel(); public static GeneralSettingsModel GeneralSettingsModel { get; set; } = new GeneralSettingsModel(); public static LlvmSettingsModel LlvmSettingsModel { get; set; } = new LlvmSettingsModel(); public static AccountModel AccountModel { get; set; } = new AccountModel(); public static SettingsView SettingsView { get; set; } public SettingsProvider Instance { get { return instance; } } #endregion #region Members private static readonly SettingsProvider instance = new SettingsProvider(); #endregion #region Constructor // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static SettingsProvider() { } private SettingsProvider() { } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/SettingsHandler.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Controllers; using ClangPowerTools.MVVM.LicenseValidation; using ClangPowerTools.MVVM.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace ClangPowerTools { public class SettingsHandler { #region Members public static Action RefreshSettingsView; private readonly string settingsPath = string.Empty; private const string SettingsFileName = "settings.json"; private const string UserProfileFileName = "userProfile.json"; private const string GeneralConfigurationFileName = "GeneralConfiguration.config"; private const string FormatConfigurationFileName = "FormatConfiguration.config"; private const string TidyOptionsConfigurationFileName = "TidyOptionsConfiguration.config"; private const string TidyPredefinedChecksConfigurationFileName = "TidyPredefinedChecksConfiguration.config"; private const int MinJsonElements = 5; #endregion #region Constructor public SettingsHandler() { var settingsPathBuilder = new SettingsPathBuilder(); settingsPath = settingsPathBuilder.GetPath(""); } #endregion #region Public Methods /// /// Load settings or import old settings /// public void InitializeSettings() { if (SettingsFileExists()) { LoadSettings(); } else if (OldGeneralSettingsExists()) { ImportOldSettings(); } else { CreateDeaultSettings(); } } public async Task InitializeAccountSettingsAsync() { SettingsProvider.AccountModel = new AccountModel(); AccountModel loadedAccountModel = null; var networkConnected = await NetworkUtility.CheckInternetConnectionAsync(); if (networkConnected) { loadedAccountModel = await LoadServerAccountSettingsAsync(); } else if (!networkConnected || loadedAccountModel == null) { loadedAccountModel = LoadLocalAccountSettings(); } if (loadedAccountModel == null) return; SettingsProvider.AccountModel = new AccountModel { UserName = loadedAccountModel.UserName, Email = loadedAccountModel.Email, LicenseType = loadedAccountModel.LicenseType, LicenseExpirationDate = loadedAccountModel.LicenseExpirationDate, }; } /// /// Save settings at a custom path /// /// public void SaveSettings(string path) { List models = CreateModelsList(); SerializeSettings(models, path); } /// /// Save settings at the predefined path /// public void SaveSettings() { List models = CreateModelsList(); string path = GetSettingsFilePath(settingsPath, SettingsFileName); SerializeSettings(models, path); string userProfilePath = GetSettingsFilePath(settingsPath, UserProfileFileName); SerializeSettings(SettingsProvider.AccountModel, userProfilePath); } /// /// Load settings from a custom path /// /// public void LoadSettings(string path) { if (File.Exists(path)) { string json = ReadSettingsFile(path); DeserializeSettings(json); RefreshSettingsView?.Invoke(); } } /// /// Load settings from the predefined path /// public void LoadSettings() { string path = GetSettingsFilePath(settingsPath, SettingsFileName); if (File.Exists(path)) { string json = ReadSettingsFile(path); DeserializeSettings(json); } else { CreateDeaultSettings(); } } public bool SettingsFileExists() { string path = GetSettingsFilePath(settingsPath, SettingsFileName); return File.Exists(path); } public void ResetSettings() { CreateDeaultSettings(); RefreshSettingsView?.Invoke(); } public string GetSettingsAsJson() { List models = CreateModelsList(); return JsonConvert.SerializeObject(models); } public void LoadCloudSettings(string json) { DeserializeSettings(json); SaveSettings(); RefreshSettingsView?.Invoke(); } public async Task LicenseInfoUpdateAsync() { KeyValuePair licenseInfo = await GetLicenseInfoAsync(); SettingsProvider.AccountModel.LicenseType = licenseInfo.Key; if (licenseInfo.Key == LicenseType.Trial) { SettingsProvider.AccountModel.LicenseExpirationDate = GetTrialLicenseExpirationDate(); } else { SettingsProvider.AccountModel.LicenseExpirationDate = !string.IsNullOrWhiteSpace(licenseInfo.Value) ? DateTime.Parse(licenseInfo.Value).ToString("MMMM dd yyyy") : "Never"; } } public async Task UserProfileInfoUpdateAsync() { var accountModel = await GetUserProfileAsync(); SettingsProvider.AccountModel.UserName = $"{accountModel.firstname} {accountModel.lastname}"; SettingsProvider.AccountModel.Email = accountModel.email; } public string GetTrialLicenseExpirationDate() { var expirationDate = new FreeTrialController().GetExpirationDateAsString(); return !string.IsNullOrWhiteSpace(expirationDate) ? DateTime.Parse(expirationDate).ToString("MMMM dd yyyy") : string.Empty; } #endregion #region Private Methods private void CreateDeaultSettings() { SettingsProvider.CompilerSettingsModel = new CompilerSettingsModel(); SettingsProvider.FormatSettingsModel = new FormatSettingsModel(); SettingsProvider.TidySettingsModel = new TidySettingsModel(); SettingsProvider.LlvmSettingsModel = new LlvmSettingsModel(); SetDefaultTidyPredefindedChecks(); } private void SetDefaultTidyPredefindedChecks() { var checks = new StringBuilder(); foreach (var item in TidyChecksDefault.Checks) { checks.Append(item).Append(";"); } checks.Length--; SettingsProvider.TidySettingsModel.PredefinedChecks = checks.ToString(); } private void ImportOldSettings() { MapOldSettings(); SaveSettings(); DeleteOldSettings(); } private bool OldGeneralSettingsExists() { string path = GetSettingsFilePath(settingsPath, GeneralConfigurationFileName); return File.Exists(path); } private void MapOldSettings() { ClangOptions clangOptions = LoadOldSettingsFromFile(new ClangOptions(), GeneralConfigurationFileName); MapClangOptionsToSettings(clangOptions); ClangFormatOptions clangFormatOptions = LoadOldSettingsFromFile(new ClangFormatOptions(), FormatConfigurationFileName); MapClangFormatOptionsToSettings(clangFormatOptions); ClangTidyOptions clangTidyOptions = LoadOldSettingsFromFile(new ClangTidyOptions(), TidyOptionsConfigurationFileName); MapClangTidyOptionsToSettings(clangTidyOptions); } private T LoadOldSettingsFromFile(T settings, string settingsFileName) where T : new() { string path = GetSettingsFilePath(settingsPath, settingsFileName); if (File.Exists(path)) { SerializeSettings(path, ref settings); } return settings; } private void DeleteOldSettings() { string[] files = Directory.GetFiles(settingsPath, "*.config"); foreach (var file in files) { File.Delete(file); } } private List CreateModelsList() { List models = new List { SettingsProvider.CompilerSettingsModel, SettingsProvider.FormatSettingsModel, SettingsProvider.TidySettingsModel, SettingsProvider.GeneralSettingsModel, SettingsProvider.LlvmSettingsModel, }; return models; } private void SerializeSettings(List models, string path) { using StreamWriter file = File.CreateText(path); var serializer = new JsonSerializer { Formatting = Formatting.Indented }; serializer.Serialize(file, models); } private void SerializeSettings(object models, string path) { // Remove the hidden attribute of the file in order to overwrite it FileInfo fileInfo; if (File.Exists(path)) { fileInfo = new FileInfo(path); fileInfo.Attributes &= ~FileAttributes.Hidden; } // Overwrite the file using StreamWriter file = new StreamWriter(path); var serializer = new JsonSerializer { Formatting = Formatting.Indented }; serializer.Serialize(file, models); // Set back the hidden attribute fileInfo = new FileInfo(path); fileInfo.Attributes |= FileAttributes.Hidden; } private void DeserializeSettings(string json) { try { var models = JsonConvert.DeserializeObject>(json); var compilerModel = JsonConvert.DeserializeObject(models[0].ToString()); var formatModel = JsonConvert.DeserializeObject(models[1].ToString()); var tidyModel = JsonConvert.DeserializeObject(models[2].ToString()); var generalModel = JsonConvert.DeserializeObject(models[3].ToString()); LlvmSettingsModel llvmModel; if (models.Count >= MinJsonElements) { llvmModel = JsonConvert.DeserializeObject(models[4].ToString()); } else { llvmModel = new LlvmSettingsModel(); } SetSettingsModels(compilerModel, formatModel, tidyModel, generalModel, llvmModel); } catch (Exception e) { MessageBox.Show(e.Message, "Cannot Load Clang Power Tools Settings", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private string ReadSettingsFile(string path) { using StreamReader sw = new StreamReader(path); return sw.ReadToEnd(); } private void SetSettingsModels(CompilerSettingsModel compilerModel, FormatSettingsModel formatModel, TidySettingsModel tidyModel, GeneralSettingsModel generalModel, LlvmSettingsModel llvmModel) { SettingsProvider.CompilerSettingsModel = compilerModel; SettingsProvider.FormatSettingsModel = formatModel; SettingsProvider.TidySettingsModel = tidyModel; SettingsProvider.GeneralSettingsModel = generalModel; SettingsProvider.LlvmSettingsModel = llvmModel; } private string GetSettingsFilePath(string path, string fileName) { return Path.Combine(path, fileName); } private void SerializeSettings(string path, ref T config) where T : new() { XmlSerializer serializer = new XmlSerializer(); config = serializer.DeserializeFromFile(path); } private void MapClangOptionsToSettings(ClangOptions clangOptions) { var compilerSettingsModel = new CompilerSettingsModel(); var generalSettingsModel = new GeneralSettingsModel(); compilerSettingsModel.CompileFlags = clangOptions.ClangFlagsCollection; compilerSettingsModel.FilesToIgnore = clangOptions.FilesToIgnore; compilerSettingsModel.ProjectsToIgnore = clangOptions.ProjectsToIgnore; compilerSettingsModel.WarningsAsErrors = clangOptions.TreatWarningsAsErrors; compilerSettingsModel.ContinueOnError = clangOptions.Continue; compilerSettingsModel.ClangAfterMSVC = clangOptions.ClangCompileAfterVsCompile; compilerSettingsModel.VerbosityLevel = clangOptions.VerbosityLevel; generalSettingsModel.Version = clangOptions.Version; SettingsProvider.CompilerSettingsModel = compilerSettingsModel; SettingsProvider.GeneralSettingsModel = generalSettingsModel; } private void MapClangFormatOptionsToSettings(ClangFormatOptions clangFormat) { var formatSettingsModel = new FormatSettingsModel { FileExtensions = clangFormat.FileExtensions, FilesToIgnore = clangFormat.SkipFiles, AssumeFilename = clangFormat.AssumeFilename, CustomExecutable = clangFormat.ClangFormatPath.Value, Style = clangFormat.Style, FallbackStyle = clangFormat.FallbackStyle, FormatOnSave = clangFormat.EnableFormatOnSave }; SettingsProvider.FormatSettingsModel = formatSettingsModel; } private void MapClangTidyOptionsToSettings(ClangTidyOptions clangTidy) { var tidySettingsModel = new TidySettingsModel { HeaderFilter = clangTidy.HeaderFilter, CustomChecks = clangTidy.TidyChecksCollection, CustomExecutable = clangTidy.ClangTidyPath.Value, FormatAfterTidy = clangTidy.FormatAfterTidy, TidyOnSave = clangTidy.AutoTidyOnSave }; SettingsProvider.TidySettingsModel = tidySettingsModel; } /// /// Load the user profile data from the local file /// /// The loaded user profile model private AccountModel LoadLocalAccountSettings() { var path = GetSettingsFilePath(settingsPath, UserProfileFileName); if (!File.Exists(path)) return null; var json = ReadSettingsFile(path); var accountModel = JsonConvert.DeserializeObject(json); return accountModel; } /// /// Load the user profile data from the server /// /// The loaded user profile model private async Task LoadServerAccountSettingsAsync() { // User profile var accountApiModel = await GetUserProfileAsync(); // License KeyValuePair licenseInfo = await GetLicenseInfoAsync(); // Create the complete Account model object var accountModel = new AccountModel { UserName = $"{accountApiModel.firstname} {accountApiModel.lastname}", Email = accountApiModel.email, LicenseType = licenseInfo.Key, LicenseExpirationDate = !string.IsNullOrWhiteSpace(licenseInfo.Value) ? DateTime.Parse(licenseInfo.Value).ToString("MMMM dd yyyy") : "Never" }; return accountModel; } /// /// Get the user profile information from the server /// /// User profile data as a model object private async Task GetUserProfileAsync() { var settingsApi = new SettingsApi(); var accountDetailsJson = await settingsApi.GetUserProfileJsonAsync(); return !string.IsNullOrWhiteSpace(accountDetailsJson) ? DeserializeUserAccountDetails(accountDetailsJson) : new AccountApiModel(); } /// /// Get the user license type and the expiration date /// /// A KeyValuePair with the license type as the key and license expiration date as the value private async Task> GetLicenseInfoAsync() { // License type LicenseType licenseType = await new LicenseController().GetUserLicenseTypeAsync(); // License expiration date var settingsApi = new SettingsApi(); var licenseDetailsJson = await settingsApi.GetLicenseDetailsJsonAsync(); // check for invalid return type after license request // check the length because personal license will return "[]" - empty json array var expirationDate = !string.IsNullOrWhiteSpace(licenseDetailsJson) && licenseDetailsJson.Length > 3 ? DeserializeLicenseDetails(licenseDetailsJson).expires : string.Empty; return new KeyValuePair(licenseType, expirationDate); } private AccountApiModel DeserializeUserAccountDetails(string json) { var accoutApiModel = JsonConvert.DeserializeObject(json); return accoutApiModel; } private LicenseModel DeserializeLicenseDetails(string json) { var userLicenseCollection = JsonConvert.DeserializeObject>(json); return userLicenseCollection[0]; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/SettingsTooltips.cs ================================================ namespace ClangPowerTools.MVVM { public class SettingsTooltips { #region Compile public string CompileFlags { get; } = "Flags given to clang++ when compiling project, alongside project - specific defines. If empty the default flags will be loaded."; public string FilesToIgnoreCompile { get; } = "Array of file(s) to ignore, from the matched ones. If empty, all already matched files are compiled."; public string ProjectsToIgnore { get; } = "Array of project(s) to ignore, from the matched ones. If empty, all already matched projects are compiled."; public string AdditionalIncludes { get; } = "Specify how clang interprets project additional include directories: as regular includes(-I) or system includes (-isystem )."; public string WarningsAsErrors { get; } = "Treats all compiler warnings as errors. For a new project, it may be best to use in all compilations; resolving all warnings will ensure the fewest possible hard to find code defects."; public string ContinueOnError { get; } = "Switch to continue project compilation even when errors occur."; public string ClangAfterMSVC { get; } = "Automatically run Clang compile on the current source file, after successful MSVC compilation."; public string VerboseLevel { get; } = "Select verbosity level displayed in output. Verbosity Level order: 0-minimal, 1-detailed, 2-complete"; public string ShowErrorList { get; } = "Always show Error List if Clang compile/tidy finishes with errors."; public string ShowOutputWindow { get; } = "Always show Output window after Clang compile/tidy or when any Clang Power Tools information message occurs."; public string ShowSquiggles { get; } = "Show squiggles for every suggestion generated by Clang."; public string CpuLimit { get; } = "Limit the number of cores for compile, tidy, tidy-fix and optimize includes"; #endregion #region Tidy public string HeaderFilter { get; } = "Regular expression matching the names of the headers to output diagnostics from. Diagnostics from the source file are always displayed." + "This option overrides the 'HeaderFilterRegex' option in .clang-tidy file, if any.\n" + "\"Corresponding Header\" : output diagnostics/fix only the corresponding header (same filename) for each source file analyzed."; public string UseChecksFrom { get; } = "Tidy checks: switch between explicitly specified checks (predefined or custom) and using checks from .clang-tidy configuration files.\n" + "Other options are always loaded from .clang-tidy files."; public string PredefinedChecks { get; } = "A list of clang-tidy static analyzer and diagnostics checks from LLVM."; public string CustomChecks { get; } = "Specify clang-tidy checks to run using the standard tidy syntax. You can use wildcards to match multiple checks, combine them, etc (Eg. \"modernize-*, readability-*\")."; public string CustomExecutableTidy { get; } = "Specify a custom path for \"clang-tidy.exe\" file to run instead of the built-in one (v8.0)."; public string CompilationDatabase{ get; } = "Specify a custom \"compile_commands.json\" file path to use as a source of compilation flags instead of the flags generated by extension."; public string DetectClangTidyFile { get; } = "Automatically detect the \".clang-tidy\" file and set the \"Use checks from\" option to \"TidyFile\" if the file exists. Otherwise, set the \"Use checks from\" option to \"PredefinedChecks\"."; public string FormatAfterTidy { get; } = "Automatically run clang-format after clang-tidy finished."; public string TidyOnSave { get; } = "Automatically run clang-tidy when saving the current source file."; public string ApplyTidyFix { get; } = "Replace Tidy with Tidy-Fix, in context menu and toolbar"; public string TidyFileConfig { get; } = "Export tidy options into a \".clang-tidy\" config file."; #endregion #region Format public string FileExtensions { get; } = "When formatting on save, clang-format will be applied only to files with these extensions."; public string FilesToIgnoreFormat { get; } = "When formatting on save, clang-format will not be applied on these files."; public string AssumeFilename { get; } = "When reading from stdin, clang-format assumes this filename to look for a style config file (with -style=file) and to determine the language."; public string CustomExecutableFormat { get; } = "Specify a custom path for \"clang-format.exe\" file to run instead of the built-in one."; public string Style { get; } = "Coding style, currently supports: LLVM, Google, Chromium, Mozilla, WebKit.\nUse -style=file to load " + "style configuration from .clang-format file located in one of the parent directories of the " + "source file(or current directory for stdin).\nUse -style=\"{key: value, ...}\" to set specific parameters, " + "e.g.: -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"."; public string FallbackStyle { get; } = "The name of the predefined style used as a fallback in case clang-format is invoked with -style=file, " + "but can not find the .clang-format file to use.\nUse -fallback-style=none to skip formatting."; public string FormatOnSave { get; } = "Enable running clang-format when modified files are saved. Will only format if Style is found (ignores Fallback Style)."; public string FormatEditor { get; } = "Create a .clang-format file from scratch or configure a predefined one. Detect the best matching format style for your code."; public string PowerShellScripts { get; } = "Manually update the PowerShell scripts used for running Clang commands."; public string AliasPowerShellScripts { get; } = "Manually add cpt alias in Windows PowerShell used for running Clang commands."; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/TextManipulation.cs ================================================ using System; using System.Collections.Generic; using System.Windows.Documents; using System.Windows.Media; namespace ClangPowerTools { /// /// Class for text manipulation operations /// public class TextManipulation { public static void HighlightKeywords(TextPointer startPointer, TextPointer endPointer, HashSet keywords, Brush foreground) { if (startPointer == null) throw new ArgumentNullException(nameof(startPointer)); if (endPointer == null) throw new ArgumentNullException(nameof(endPointer)); TextRange text = new TextRange(startPointer, endPointer); TextPointer position = text.Start.GetInsertionPosition(LogicalDirection.Forward); while (position != null) { string textInRun = position.GetTextInRun(LogicalDirection.Forward); if (string.IsNullOrWhiteSpace(textInRun)) { position = position.GetNextContextPosition(LogicalDirection.Forward); continue; } ChangeTextColor(keywords, foreground, text, position, textInRun); position = position.GetNextContextPosition(LogicalDirection.Forward); } } public static void ReplaceAllTextInFlowDocument(FlowDocument document, string text) { TextRange textRange = new TextRange(document.ContentStart, document.ContentEnd); textRange.Text = text; } private static void ChangeTextColor(HashSet keywords, Brush foreground, TextRange text, TextPointer position, string textInRun) { foreach (var keyword in keywords) { int index = textInRun.IndexOf(keyword); if (index != -1 && CheckForSpaceAfterKeyword(textInRun, keyword, index)) { TextRange selection = CreateSelection(position, keyword.Length, index); selection.ApplyPropertyValue(TextElement.ForegroundProperty, foreground); } } } private static bool CheckForSpaceAfterKeyword(string text, string keyword, int index) { int keywordLength = keyword.Length; if (index + keywordLength > text.Length - 1) return false; var characterToCheck = text[index + keywordLength]; if (characterToCheck == ' ' || characterToCheck == '/') return true; return false; } private static TextRange CreateSelection(TextPointer position, int keywordLength, int index) { TextPointer selectionStart = position.GetPositionAtOffset(index, LogicalDirection.Forward); TextPointer selectionEnd = selectionStart.GetPositionAtOffset(keywordLength, LogicalDirection.Forward); TextRange selection = new TextRange(selectionStart, selectionEnd); return selection; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/TidyChecks.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public class TidyChecks { // You can use tidy checks automation, search in dir root Tidy_Checks_Automation public List Checks { get; set; } = new() { new TidyCheckModel { Name = "abseil-cleanup-ctad", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-addition", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-comparison", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-conversion-cast", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-division", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-factory-float", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-factory-scale", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-subtraction", IsChecked = false }, new TidyCheckModel { Name = "abseil-duration-unnecessary-conversion", IsChecked = false }, new TidyCheckModel { Name = "abseil-faster-strsplit-delimiter", IsChecked = false }, new TidyCheckModel { Name = "abseil-no-internal-dependencies", IsChecked = false }, new TidyCheckModel { Name = "abseil-no-namespace", IsChecked = false }, new TidyCheckModel { Name = "abseil-redundant-strcat-calls", IsChecked = false }, new TidyCheckModel { Name = "abseil-str-cat-append", IsChecked = false }, new TidyCheckModel { Name = "abseil-string-find-startswith", IsChecked = false }, new TidyCheckModel { Name = "abseil-string-find-str-contains", IsChecked = false }, new TidyCheckModel { Name = "abseil-time-comparison", IsChecked = false }, new TidyCheckModel { Name = "abseil-time-subtraction", IsChecked = false }, new TidyCheckModel { Name = "abseil-upgrade-duration-conversions", IsChecked = false }, new TidyCheckModel { Name = "altera-id-dependent-backward-branch", IsChecked = false }, new TidyCheckModel { Name = "altera-kernel-name-restriction", IsChecked = false }, new TidyCheckModel { Name = "altera-single-work-item-barrier", IsChecked = false }, new TidyCheckModel { Name = "altera-struct-pack-align", IsChecked = false }, new TidyCheckModel { Name = "altera-unroll-loops", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-accept", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-accept4", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-creat", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-dup", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-epoll-create", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-epoll-create1", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-fopen", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-inotify-init", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-inotify-init1", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-memfd-create", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-open", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-pipe", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-pipe2", IsChecked = false }, new TidyCheckModel { Name = "android-cloexec-socket", IsChecked = false }, new TidyCheckModel { Name = "android-comparison-in-temp-failure-retry", IsChecked = false }, new TidyCheckModel { Name = "boost-use-ranges", IsChecked = false }, new TidyCheckModel { Name = "boost-use-to-string", IsChecked = false }, new TidyCheckModel { Name = "bugprone-argument-comment", IsChecked = false }, new TidyCheckModel { Name = "bugprone-assert-side-effect", IsChecked = false }, new TidyCheckModel { Name = "bugprone-assignment-in-if-condition", IsChecked = false }, new TidyCheckModel { Name = "bugprone-bad-signal-to-kill-thread", IsChecked = false }, new TidyCheckModel { Name = "bugprone-bitwise-pointer-cast", IsChecked = false }, new TidyCheckModel { Name = "bugprone-bool-pointer-implicit-conversion", IsChecked = false }, new TidyCheckModel { Name = "bugprone-branch-clone", IsChecked = false }, new TidyCheckModel { Name = "bugprone-capturing-this-in-member-variable", IsChecked = false }, new TidyCheckModel { Name = "bugprone-casting-through-void", IsChecked = false }, new TidyCheckModel { Name = "bugprone-chained-comparison", IsChecked = false }, new TidyCheckModel { Name = "bugprone-command-processor", IsChecked = false }, new TidyCheckModel { Name = "bugprone-compare-pointer-to-member-virtual-function", IsChecked = false }, new TidyCheckModel { Name = "bugprone-copy-constructor-init", IsChecked = false }, new TidyCheckModel { Name = "bugprone-copy-constructor-mutates-argument", IsChecked = false }, new TidyCheckModel { Name = "bugprone-crtp-constructor-accessibility", IsChecked = false }, new TidyCheckModel { Name = "bugprone-dangling-handle", IsChecked = false }, new TidyCheckModel { Name = "bugprone-default-operator-new-on-overaligned-type", IsChecked = false }, new TidyCheckModel { Name = "bugprone-derived-method-shadowing-base-method", IsChecked = false }, new TidyCheckModel { Name = "bugprone-dynamic-static-initializers", IsChecked = false }, new TidyCheckModel { Name = "bugprone-easily-swappable-parameters", IsChecked = false }, new TidyCheckModel { Name = "bugprone-empty-catch", IsChecked = false }, new TidyCheckModel { Name = "bugprone-exception-copy-constructor-throws", IsChecked = false }, new TidyCheckModel { Name = "bugprone-exception-escape", IsChecked = false }, new TidyCheckModel { Name = "bugprone-float-loop-counter", IsChecked = false }, new TidyCheckModel { Name = "bugprone-fold-init-type", IsChecked = false }, new TidyCheckModel { Name = "bugprone-forward-declaration-namespace", IsChecked = false }, new TidyCheckModel { Name = "bugprone-forwarding-reference-overload", IsChecked = false }, new TidyCheckModel { Name = "bugprone-implicit-widening-of-multiplication-result", IsChecked = false }, new TidyCheckModel { Name = "bugprone-inaccurate-erase", IsChecked = false }, new TidyCheckModel { Name = "bugprone-inc-dec-in-conditions", IsChecked = false }, new TidyCheckModel { Name = "bugprone-incorrect-enable-if", IsChecked = false }, new TidyCheckModel { Name = "bugprone-incorrect-enable-shared-from-this", IsChecked = false }, new TidyCheckModel { Name = "bugprone-incorrect-roundings", IsChecked = false }, new TidyCheckModel { Name = "bugprone-infinite-loop", IsChecked = false }, new TidyCheckModel { Name = "bugprone-integer-division", IsChecked = false }, new TidyCheckModel { Name = "bugprone-invalid-enum-default-initialization", IsChecked = false }, new TidyCheckModel { Name = "bugprone-lambda-function-name", IsChecked = false }, new TidyCheckModel { Name = "bugprone-macro-parentheses", IsChecked = false }, new TidyCheckModel { Name = "bugprone-macro-repeated-side-effects", IsChecked = false }, new TidyCheckModel { Name = "bugprone-misleading-setter-of-reference", IsChecked = false }, new TidyCheckModel { Name = "bugprone-misplaced-operator-in-strlen-in-alloc", IsChecked = false }, new TidyCheckModel { Name = "bugprone-misplaced-pointer-arithmetic-in-alloc", IsChecked = false }, new TidyCheckModel { Name = "bugprone-misplaced-widening-cast", IsChecked = false }, new TidyCheckModel { Name = "bugprone-move-forwarding-reference", IsChecked = false }, new TidyCheckModel { Name = "bugprone-multi-level-implicit-pointer-conversion", IsChecked = false }, new TidyCheckModel { Name = "bugprone-multiple-new-in-one-expression", IsChecked = false }, new TidyCheckModel { Name = "bugprone-multiple-statement-macro", IsChecked = false }, new TidyCheckModel { Name = "bugprone-narrowing-conversions", IsChecked = false }, new TidyCheckModel { Name = "bugprone-no-escape", IsChecked = false }, new TidyCheckModel { Name = "bugprone-nondeterministic-pointer-iteration-order", IsChecked = false }, new TidyCheckModel { Name = "bugprone-non-zero-enum-to-bool-conversion", IsChecked = false }, new TidyCheckModel { Name = "bugprone-not-null-terminated-result", IsChecked = false }, new TidyCheckModel { Name = "bugprone-optional-value-conversion", IsChecked = false }, new TidyCheckModel { Name = "bugprone-parent-virtual-call", IsChecked = false }, new TidyCheckModel { Name = "bugprone-pointer-arithmetic-on-polymorphic-object", IsChecked = false }, new TidyCheckModel { Name = "bugprone-posix-return", IsChecked = false }, new TidyCheckModel { Name = "bugprone-random-generator-seed", IsChecked = false }, new TidyCheckModel { Name = "bugprone-raw-memory-call-on-non-trivial-type", IsChecked = false }, new TidyCheckModel { Name = "bugprone-redundant-branch-condition", IsChecked = false }, new TidyCheckModel { Name = "bugprone-reserved-identifier", IsChecked = false }, new TidyCheckModel { Name = "bugprone-return-const-ref-from-parameter", IsChecked = false }, new TidyCheckModel { Name = "bugprone-shared-ptr-array-mismatch", IsChecked = false }, new TidyCheckModel { Name = "bugprone-signal-handler", IsChecked = false }, new TidyCheckModel { Name = "bugprone-signed-char-misuse", IsChecked = false }, new TidyCheckModel { Name = "bugprone-sizeof-container", IsChecked = false }, new TidyCheckModel { Name = "bugprone-sizeof-expression", IsChecked = false }, new TidyCheckModel { Name = "bugprone-spuriously-wake-up-functions", IsChecked = false }, new TidyCheckModel { Name = "bugprone-standalone-empty", IsChecked = false }, new TidyCheckModel { Name = "bugprone-std-namespace-modification", IsChecked = false }, new TidyCheckModel { Name = "bugprone-string-constructor", IsChecked = false }, new TidyCheckModel { Name = "bugprone-string-integer-assignment", IsChecked = false }, new TidyCheckModel { Name = "bugprone-string-literal-with-embedded-nul", IsChecked = false }, new TidyCheckModel { Name = "bugprone-stringview-nullptr", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-enum-usage", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-include", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-memory-comparison", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-memset-usage", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-missing-comma", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-realloc-usage", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-semicolon", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-string-compare", IsChecked = false }, new TidyCheckModel { Name = "bugprone-suspicious-stringview-data-usage", IsChecked = false }, new TidyCheckModel { Name = "bugprone-swapped-arguments", IsChecked = false }, new TidyCheckModel { Name = "bugprone-switch-missing-default-case", IsChecked = false }, new TidyCheckModel { Name = "bugprone-tagged-union-member-count", IsChecked = false }, new TidyCheckModel { Name = "bugprone-terminating-continue", IsChecked = false }, new TidyCheckModel { Name = "bugprone-throwing-static-initialization", IsChecked = false }, new TidyCheckModel { Name = "bugprone-throw-keyword-missing", IsChecked = false }, new TidyCheckModel { Name = "bugprone-too-small-loop-variable", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unchecked-optional-access", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unchecked-string-to-number-conversion", IsChecked = false }, new TidyCheckModel { Name = "bugprone-undefined-memory-manipulation", IsChecked = false }, new TidyCheckModel { Name = "bugprone-undelegated-constructor", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unhandled-exception-at-new", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unhandled-self-assignment", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unintended-char-ostream-output", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unique-ptr-array-mismatch", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unsafe-functions", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unused-local-non-trivial-variable", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unused-raii", IsChecked = false }, new TidyCheckModel { Name = "bugprone-unused-return-value", IsChecked = false }, new TidyCheckModel { Name = "bugprone-use-after-move", IsChecked = false }, new TidyCheckModel { Name = "bugprone-virtual-near-miss", IsChecked = false }, new TidyCheckModel { Name = "cert-arr39-c", IsChecked = false }, new TidyCheckModel { Name = "cert-con36-c", IsChecked = false }, new TidyCheckModel { Name = "cert-con54-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-ctr56-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl03-c", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl16-c", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl37-c", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl50-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl51-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl54-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl58-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-dcl59-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-env33-c", IsChecked = false }, new TidyCheckModel { Name = "cert-err09-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-err33-c", IsChecked = false }, new TidyCheckModel { Name = "cert-err34-c", IsChecked = false }, new TidyCheckModel { Name = "cert-err52-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-err58-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-err60-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-err61-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-exp42-c", IsChecked = false }, new TidyCheckModel { Name = "cert-fio38-c", IsChecked = false }, new TidyCheckModel { Name = "cert-flp30-c", IsChecked = false }, new TidyCheckModel { Name = "cert-flp37-c", IsChecked = false }, new TidyCheckModel { Name = "cert-int09-c", IsChecked = false }, new TidyCheckModel { Name = "cert-mem57-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-msc24-c", IsChecked = false }, new TidyCheckModel { Name = "cert-msc30-c", IsChecked = false }, new TidyCheckModel { Name = "cert-msc32-c", IsChecked = false }, new TidyCheckModel { Name = "cert-msc33-c", IsChecked = false }, new TidyCheckModel { Name = "cert-msc50-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-msc51-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-msc54-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-oop11-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-oop54-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-oop57-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-oop58-cpp", IsChecked = false }, new TidyCheckModel { Name = "cert-pos44-c", IsChecked = false }, new TidyCheckModel { Name = "cert-pos47-c", IsChecked = false }, new TidyCheckModel { Name = "cert-sig30-c", IsChecked = false }, new TidyCheckModel { Name = "cert-str34-c", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.BitwiseShift", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.CallAndMessage", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.DivideZero", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.NonNullParamChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.NullDereference", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.StackAddressEscape", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.UndefinedBinaryOperatorResult", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.ArraySubscript", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.Assign", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.Branch", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.CapturedBlockVariable", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.NewArraySize", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.uninitialized.UndefReturn", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-core.VLASize", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.ArrayDelete", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.InnerPointer", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.Move", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.NewDelete", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.NewDeleteLeaks", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.PlacementNew", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.SelfAssignment", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-cplusplus.StringChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-deadcode.DeadStores", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-fuchsia.HandleChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-nullability.NullableDereferenced", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-nullability.NullablePassedToNonnull", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-nullability.NullableReturnedFromNonnull", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-nullability.NullPassedToNonnull", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-nullability.NullReturnedFromNonnull", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.core.EnumCastOutOfRange", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.cplusplus.UninitializedObject", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.cplusplus.VirtualCall", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.mpi.MPI-Checker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.performance.GCDAntipattern", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.performance.Padding", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.portability.UnixAPI", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-optin.taint.TaintedAlloc", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.API", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.AtSync", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.AutoreleaseWrite", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.ClassRelease", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.Dealloc", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.IncompatibleMethodTypes", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.Loops", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.MissingSuperCall", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.NilArg", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.NonNilReturnValue", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.NSAutoreleasePool", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.NSError", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.ObjCGenerics", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.RetainCount", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.SelfInit", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.SuperDealloc", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.UnusedIvars", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.cocoa.VariadicMethodTypes", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.coreFoundation.CFError", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.coreFoundation.CFNumber", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.coreFoundation.CFRetainRelease", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.coreFoundation.containers.OutOfBounds", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.coreFoundation.containers.PointerSizedValues", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.NumberObjectConversion", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.ObjCProperty", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-osx.SecKeychainAPI", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.cert.env.InvalidPtr", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.FloatLoopCounter", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.bcmp", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.bcopy", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.bzero", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.decodeValueOfObjCType", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.getpw", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.gets", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.mkstemp", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.mktemp", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.rand", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.strcpy", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.UncheckedReturn", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.insecureAPI.vfork", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.PutenvStackArray", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-security.SetgidSetuidOrder", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.API", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.BlockInCriticalSection", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.cstring.BadSizeArg", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.cstring.NullArg", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.Errno", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.Malloc", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.MallocSizeof", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.MismatchedDeallocator", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.StdCLibraryFunctions", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.Stream", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-unix.Vfork", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-webkit.NoUncountedMemberChecker", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-webkit.RefCntblBaseVirtualDtor", IsChecked = false }, new TidyCheckModel { Name = "clang-analyzer-webkit.UncountedLambdaCapturesChecker", IsChecked = false }, new TidyCheckModel { Name = "concurrency-mt-unsafe", IsChecked = false }, new TidyCheckModel { Name = "concurrency-thread-canceltype-asynchronous", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-capturing-lambda-coroutines", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-c-arrays", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-const-or-ref-data-members", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-do-while", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-goto", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-magic-numbers", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-non-const-global-variables", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-avoid-reference-coroutine-parameters", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-c-copy-assignment-signature", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-explicit-virtual-functions", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-init-variables", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-interfaces-global-init", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-macro-to-enum", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-macro-usage", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-misleading-capture-default-by-value", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-missing-std-forward", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-narrowing-conversions", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-noexcept-destructor", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-noexcept-move-operations", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-noexcept-swap", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-no-malloc", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-non-private-member-variables-in-classes", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-no-suspend-with-lock", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-owning-memory", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-prefer-member-initializer", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-bounds-array-to-pointer-decay", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-bounds-avoid-unchecked-container-access", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-bounds-constant-array-index", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-bounds-pointer-arithmetic", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-const-cast", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-cstyle-cast", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-member-init", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-reinterpret-cast", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-static-cast-downcast", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-union-access", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-pro-type-vararg", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-rvalue-reference-param-not-moved", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-slicing", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-special-member-functions", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-use-default-member-init", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-use-enum-class", IsChecked = false }, new TidyCheckModel { Name = "cppcoreguidelines-virtual-class-destructor", IsChecked = false }, new TidyCheckModel { Name = "darwin-avoid-spinlock", IsChecked = false }, new TidyCheckModel { Name = "darwin-dispatch-once-nonstatic", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-default-arguments-calls", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-default-arguments-declarations", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-header-anon-namespaces", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-multiple-inheritance", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-overloaded-operator", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-statically-constructed-objects", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-temporary-objects", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-trailing-return", IsChecked = false }, new TidyCheckModel { Name = "fuchsia-virtual-inheritance", IsChecked = false }, new TidyCheckModel { Name = "google-build-explicit-make-pair", IsChecked = false }, new TidyCheckModel { Name = "google-build-namespaces", IsChecked = false }, new TidyCheckModel { Name = "google-build-using-namespace", IsChecked = false }, new TidyCheckModel { Name = "google-default-arguments", IsChecked = false }, new TidyCheckModel { Name = "google-explicit-constructor", IsChecked = false }, new TidyCheckModel { Name = "google-global-names-in-headers", IsChecked = false }, new TidyCheckModel { Name = "google-objc-avoid-nsobject-new", IsChecked = false }, new TidyCheckModel { Name = "google-objc-avoid-throwing-exception", IsChecked = false }, new TidyCheckModel { Name = "google-objc-function-naming", IsChecked = false }, new TidyCheckModel { Name = "google-objc-global-variable-declaration", IsChecked = false }, new TidyCheckModel { Name = "google-readability-avoid-underscore-in-googletest-name", IsChecked = false }, new TidyCheckModel { Name = "google-readability-braces-around-statements", IsChecked = false }, new TidyCheckModel { Name = "google-readability-casting", IsChecked = false }, new TidyCheckModel { Name = "google-readability-function-size", IsChecked = false }, new TidyCheckModel { Name = "google-readability-namespace-comments", IsChecked = false }, new TidyCheckModel { Name = "google-readability-todo", IsChecked = false }, new TidyCheckModel { Name = "google-runtime-float", IsChecked = false }, new TidyCheckModel { Name = "google-runtime-int", IsChecked = false }, new TidyCheckModel { Name = "google-runtime-operator", IsChecked = false }, new TidyCheckModel { Name = "google-upgrade-googletest-case", IsChecked = false }, new TidyCheckModel { Name = "hicpp-avoid-c-arrays", IsChecked = false }, new TidyCheckModel { Name = "hicpp-avoid-goto", IsChecked = false }, new TidyCheckModel { Name = "hicpp-braces-around-statements", IsChecked = false }, new TidyCheckModel { Name = "hicpp-deprecated-headers", IsChecked = false }, new TidyCheckModel { Name = "hicpp-exception-baseclass", IsChecked = false }, new TidyCheckModel { Name = "hicpp-explicit-conversions", IsChecked = false }, new TidyCheckModel { Name = "hicpp-function-size", IsChecked = false }, new TidyCheckModel { Name = "hicpp-ignored-remove-result", IsChecked = false }, new TidyCheckModel { Name = "hicpp-invalid-access-moved", IsChecked = false }, new TidyCheckModel { Name = "hicpp-member-init", IsChecked = false }, new TidyCheckModel { Name = "hicpp-move-const-arg", IsChecked = false }, new TidyCheckModel { Name = "hicpp-multiway-paths-covered", IsChecked = false }, new TidyCheckModel { Name = "hicpp-named-parameter", IsChecked = false }, new TidyCheckModel { Name = "hicpp-new-delete-operators", IsChecked = false }, new TidyCheckModel { Name = "hicpp-no-array-decay", IsChecked = false }, new TidyCheckModel { Name = "hicpp-no-assembler", IsChecked = false }, new TidyCheckModel { Name = "hicpp-noexcept-move", IsChecked = false }, new TidyCheckModel { Name = "hicpp-no-malloc", IsChecked = false }, new TidyCheckModel { Name = "hicpp-signed-bitwise", IsChecked = false }, new TidyCheckModel { Name = "hicpp-special-member-functions", IsChecked = false }, new TidyCheckModel { Name = "hicpp-static-assert", IsChecked = false }, new TidyCheckModel { Name = "hicpp-undelegated-constructor", IsChecked = false }, new TidyCheckModel { Name = "hicpp-uppercase-literal-suffix", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-auto", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-emplace", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-equals-default", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-equals-delete", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-noexcept", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-nullptr", IsChecked = false }, new TidyCheckModel { Name = "hicpp-use-override", IsChecked = false }, new TidyCheckModel { Name = "hicpp-vararg", IsChecked = false }, new TidyCheckModel { Name = "linuxkernel-must-check-errs", IsChecked = false }, new TidyCheckModel { Name = "llvm-else-after-return", IsChecked = false }, new TidyCheckModel { Name = "llvm-header-guard", IsChecked = false }, new TidyCheckModel { Name = "llvm-include-order", IsChecked = false }, new TidyCheckModel { Name = "llvmlibc-callee-namespace", IsChecked = false }, new TidyCheckModel { Name = "llvmlibc-implementation-in-namespace", IsChecked = false }, new TidyCheckModel { Name = "llvmlibc-inline-function-decl", IsChecked = false }, new TidyCheckModel { Name = "llvmlibc-restrict-system-libc-headers", IsChecked = false }, new TidyCheckModel { Name = "llvm-namespace-comment", IsChecked = false }, new TidyCheckModel { Name = "llvm-prefer-isa-or-dyn-cast-in-conditionals", IsChecked = false }, new TidyCheckModel { Name = "llvm-prefer-register-over-unsigned", IsChecked = false }, new TidyCheckModel { Name = "llvm-prefer-static-over-anonymous-namespace", IsChecked = false }, new TidyCheckModel { Name = "llvm-qualified-auto", IsChecked = false }, new TidyCheckModel { Name = "llvm-twine-local", IsChecked = false }, new TidyCheckModel { Name = "llvm-use-new-mlir-op-builder", IsChecked = false }, new TidyCheckModel { Name = "llvm-use-ranges", IsChecked = false }, new TidyCheckModel { Name = "misc-confusable-identifiers", IsChecked = false }, new TidyCheckModel { Name = "misc-const-correctness", IsChecked = false }, new TidyCheckModel { Name = "misc-coroutine-hostile-raii", IsChecked = false }, new TidyCheckModel { Name = "misc-definitions-in-headers", IsChecked = false }, new TidyCheckModel { Name = "misc-header-include-cycle", IsChecked = false }, new TidyCheckModel { Name = "misc-include-cleaner", IsChecked = false }, new TidyCheckModel { Name = "misc-misleading-bidirectional", IsChecked = false }, new TidyCheckModel { Name = "misc-misleading-identifier", IsChecked = false }, new TidyCheckModel { Name = "misc-misplaced-const", IsChecked = false }, new TidyCheckModel { Name = "misc-new-delete-overloads", IsChecked = false }, new TidyCheckModel { Name = "misc-non-copyable-objects", IsChecked = false }, new TidyCheckModel { Name = "misc-non-private-member-variables-in-classes", IsChecked = false }, new TidyCheckModel { Name = "misc-no-recursion", IsChecked = false }, new TidyCheckModel { Name = "misc-override-with-different-visibility", IsChecked = false }, new TidyCheckModel { Name = "misc-predictable-rand", IsChecked = false }, new TidyCheckModel { Name = "misc-redundant-expression", IsChecked = false }, new TidyCheckModel { Name = "misc-static-assert", IsChecked = false }, new TidyCheckModel { Name = "misc-throw-by-value-catch-by-reference", IsChecked = false }, new TidyCheckModel { Name = "misc-unconventional-assign-operator", IsChecked = false }, new TidyCheckModel { Name = "misc-uniqueptr-reset-release", IsChecked = false }, new TidyCheckModel { Name = "misc-unused-alias-decls", IsChecked = false }, new TidyCheckModel { Name = "misc-unused-parameters", IsChecked = false }, new TidyCheckModel { Name = "misc-unused-using-decls", IsChecked = false }, new TidyCheckModel { Name = "misc-use-anonymous-namespace", IsChecked = false }, new TidyCheckModel { Name = "misc-use-internal-linkage", IsChecked = false }, new TidyCheckModel { Name = "modernize-avoid-bind", IsChecked = false }, new TidyCheckModel { Name = "modernize-avoid-c-arrays", IsChecked = false }, new TidyCheckModel { Name = "modernize-avoid-setjmp-longjmp", IsChecked = false }, new TidyCheckModel { Name = "modernize-avoid-variadic-functions", IsChecked = false }, new TidyCheckModel { Name = "modernize-concat-nested-namespaces", IsChecked = false }, new TidyCheckModel { Name = "modernize-deprecated-headers", IsChecked = false }, new TidyCheckModel { Name = "modernize-deprecated-ios-base-aliases", IsChecked = false }, new TidyCheckModel { Name = "modernize-loop-convert", IsChecked = false }, new TidyCheckModel { Name = "modernize-macro-to-enum", IsChecked = false }, new TidyCheckModel { Name = "modernize-make-shared", IsChecked = false }, new TidyCheckModel { Name = "modernize-make-unique", IsChecked = false }, new TidyCheckModel { Name = "modernize-min-max-use-initializer-list", IsChecked = false }, new TidyCheckModel { Name = "modernize-pass-by-value", IsChecked = false }, new TidyCheckModel { Name = "modernize-raw-string-literal", IsChecked = false }, new TidyCheckModel { Name = "modernize-redundant-void-arg", IsChecked = false }, new TidyCheckModel { Name = "modernize-replace-auto-ptr", IsChecked = false }, new TidyCheckModel { Name = "modernize-replace-disallow-copy-and-assign-macro", IsChecked = false }, new TidyCheckModel { Name = "modernize-replace-random-shuffle", IsChecked = false }, new TidyCheckModel { Name = "modernize-return-braced-init-list", IsChecked = false }, new TidyCheckModel { Name = "modernize-shrink-to-fit", IsChecked = false }, new TidyCheckModel { Name = "modernize-type-traits", IsChecked = false }, new TidyCheckModel { Name = "modernize-unary-static-assert", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-auto", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-bool-literals", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-constraints", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-default-member-init", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-designated-initializers", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-emplace", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-equals-default", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-equals-delete", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-integer-sign-comparison", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-nodiscard", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-noexcept", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-nullptr", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-override", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-ranges", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-scoped-lock", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-starts-ends-with", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-std-format", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-std-numbers", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-std-print", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-trailing-return-type", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-transparent-functors", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-uncaught-exceptions", IsChecked = false }, new TidyCheckModel { Name = "modernize-use-using", IsChecked = false }, new TidyCheckModel { Name = "mpi-buffer-deref", IsChecked = false }, new TidyCheckModel { Name = "mpi-type-mismatch", IsChecked = false }, new TidyCheckModel { Name = "objc-assert-equals", IsChecked = false }, new TidyCheckModel { Name = "objc-avoid-nserror-init", IsChecked = false }, new TidyCheckModel { Name = "objc-dealloc-in-category", IsChecked = false }, new TidyCheckModel { Name = "objc-forbidden-subclassing", IsChecked = false }, new TidyCheckModel { Name = "objc-missing-hash", IsChecked = false }, new TidyCheckModel { Name = "objc-nsdate-formatter", IsChecked = false }, new TidyCheckModel { Name = "objc-nsinvocation-argument-lifetime", IsChecked = false }, new TidyCheckModel { Name = "objc-property-declaration", IsChecked = false }, new TidyCheckModel { Name = "objc-super-self", IsChecked = false }, new TidyCheckModel { Name = "openmp-exception-escape", IsChecked = false }, new TidyCheckModel { Name = "openmp-use-default-none", IsChecked = false }, new TidyCheckModel { Name = "performance-avoid-endl", IsChecked = false }, new TidyCheckModel { Name = "performance-enum-size", IsChecked = false }, new TidyCheckModel { Name = "performance-faster-string-find", IsChecked = false }, new TidyCheckModel { Name = "performance-for-range-copy", IsChecked = false }, new TidyCheckModel { Name = "performance-implicit-conversion-in-loop", IsChecked = false }, new TidyCheckModel { Name = "performance-inefficient-algorithm", IsChecked = false }, new TidyCheckModel { Name = "performance-inefficient-string-concatenation", IsChecked = false }, new TidyCheckModel { Name = "performance-inefficient-vector-operation", IsChecked = false }, new TidyCheckModel { Name = "performance-move-const-arg", IsChecked = false }, new TidyCheckModel { Name = "performance-move-constructor-init", IsChecked = false }, new TidyCheckModel { Name = "performance-no-automatic-move", IsChecked = false }, new TidyCheckModel { Name = "performance-noexcept-destructor", IsChecked = false }, new TidyCheckModel { Name = "performance-noexcept-move-constructor", IsChecked = false }, new TidyCheckModel { Name = "performance-noexcept-swap", IsChecked = false }, new TidyCheckModel { Name = "performance-no-int-to-ptr", IsChecked = false }, new TidyCheckModel { Name = "performance-trivially-destructible", IsChecked = false }, new TidyCheckModel { Name = "performance-type-promotion-in-math-fn", IsChecked = false }, new TidyCheckModel { Name = "performance-unnecessary-copy-initialization", IsChecked = false }, new TidyCheckModel { Name = "performance-unnecessary-value-param", IsChecked = false }, new TidyCheckModel { Name = "portability-avoid-pragma-once", IsChecked = false }, new TidyCheckModel { Name = "portability-restrict-system-includes", IsChecked = false }, new TidyCheckModel { Name = "portability-simd-intrinsics", IsChecked = false }, new TidyCheckModel { Name = "portability-std-allocator-const", IsChecked = false }, new TidyCheckModel { Name = "portability-template-virtual-member-function", IsChecked = false }, new TidyCheckModel { Name = "readability-ambiguous-smartptr-reset-call", IsChecked = false }, new TidyCheckModel { Name = "readability-avoid-const-params-in-decls", IsChecked = false }, new TidyCheckModel { Name = "readability-avoid-nested-conditional-operator", IsChecked = false }, new TidyCheckModel { Name = "readability-avoid-return-with-void-value", IsChecked = false }, new TidyCheckModel { Name = "readability-avoid-unconditional-preprocessor-if", IsChecked = false }, new TidyCheckModel { Name = "readability-braces-around-statements", IsChecked = false }, new TidyCheckModel { Name = "readability-const-return-type", IsChecked = false }, new TidyCheckModel { Name = "readability-container-contains", IsChecked = false }, new TidyCheckModel { Name = "readability-container-data-pointer", IsChecked = false }, new TidyCheckModel { Name = "readability-container-size-empty", IsChecked = false }, new TidyCheckModel { Name = "readability-convert-member-functions-to-static", IsChecked = false }, new TidyCheckModel { Name = "readability-delete-null-pointer", IsChecked = false }, new TidyCheckModel { Name = "readability-duplicate-include", IsChecked = false }, new TidyCheckModel { Name = "readability-else-after-return", IsChecked = false }, new TidyCheckModel { Name = "readability-enum-initial-value", IsChecked = false }, new TidyCheckModel { Name = "readability-function-cognitive-complexity", IsChecked = false }, new TidyCheckModel { Name = "readability-function-size", IsChecked = false }, new TidyCheckModel { Name = "readability-identifier-length", IsChecked = false }, new TidyCheckModel { Name = "readability-identifier-naming", IsChecked = false }, new TidyCheckModel { Name = "readability-implicit-bool-conversion", IsChecked = false }, new TidyCheckModel { Name = "readability-inconsistent-declaration-parameter-name", IsChecked = false }, new TidyCheckModel { Name = "readability-isolate-declaration", IsChecked = false }, new TidyCheckModel { Name = "readability-magic-numbers", IsChecked = false }, new TidyCheckModel { Name = "readability-make-member-function-const", IsChecked = false }, new TidyCheckModel { Name = "readability-math-missing-parentheses", IsChecked = false }, new TidyCheckModel { Name = "readability-misleading-indentation", IsChecked = false }, new TidyCheckModel { Name = "readability-misplaced-array-index", IsChecked = false }, new TidyCheckModel { Name = "readability-named-parameter", IsChecked = false }, new TidyCheckModel { Name = "readability-non-const-parameter", IsChecked = false }, new TidyCheckModel { Name = "readability-operators-representation", IsChecked = false }, new TidyCheckModel { Name = "readability-qualified-auto", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-access-specifiers", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-casting", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-control-flow", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-declaration", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-function-ptr-dereference", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-inline-specifier", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-member-init", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-parentheses", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-preprocessor", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-smartptr-get", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-string-cstr", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-string-init", IsChecked = false }, new TidyCheckModel { Name = "readability-redundant-typename", IsChecked = false }, new TidyCheckModel { Name = "readability-reference-to-constructed-temporary", IsChecked = false }, new TidyCheckModel { Name = "readability-simplify-boolean-expr", IsChecked = false }, new TidyCheckModel { Name = "readability-simplify-subscript-expr", IsChecked = false }, new TidyCheckModel { Name = "readability-static-accessed-through-instance", IsChecked = false }, new TidyCheckModel { Name = "readability-static-definition-in-anonymous-namespace", IsChecked = false }, new TidyCheckModel { Name = "readability-string-compare", IsChecked = false }, new TidyCheckModel { Name = "readability-suspicious-call-argument", IsChecked = false }, new TidyCheckModel { Name = "readability-uniqueptr-delete-release", IsChecked = false }, new TidyCheckModel { Name = "readability-uppercase-literal-suffix", IsChecked = false }, new TidyCheckModel { Name = "readability-use-anyofallof", IsChecked = false }, new TidyCheckModel { Name = "readability-use-concise-preprocessor-directives", IsChecked = false }, new TidyCheckModel { Name = "readability-use-std-min-max", IsChecked = false }, new TidyCheckModel { Name = "zircon-temporary-objects", IsChecked = false }, }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/TidyChecksDefault.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public static class TidyChecksDefault { public static HashSet Checks { get; } = new() { "clang-analyzer-apiModeling.StdCLibraryFunctions", "clang-analyzer-apiModeling.TrustNonnull", "clang-analyzer-apiModeling.google.GTest", "clang-analyzer-apiModeling.llvm.CastValue", "clang-analyzer-apiModeling.llvm.ReturnValue", "clang-analyzer-core.CallAndMessage", "clang-analyzer-core.CallAndMessageModeling", "clang-analyzer-core.DivideZero", "clang-analyzer-core.DynamicTypePropagation", "clang-analyzer-core.NonNullParamChecker", "clang-analyzer-core.NonnilStringConstants", "clang-analyzer-core.NullDereference", "clang-analyzer-core.StackAddrEscapeBase", "clang-analyzer-core.StackAddressEscape", "clang-analyzer-core.UndefinedBinaryOperatorResult", "clang-analyzer-core.VLASize", "clang-analyzer-core.builtin.BuiltinFunctions", "clang-analyzer-core.builtin.NoReturnFunctions", "clang-analyzer-core.uninitialized.ArraySubscript", "clang-analyzer-core.uninitialized.Assign", "clang-analyzer-core.uninitialized.Branch", "clang-analyzer-core.uninitialized.CapturedBlockVariable", "clang-analyzer-core.uninitialized.UndefReturn", "clang-analyzer-cplusplus.InnerPointer", "clang-analyzer-cplusplus.Move", "clang-analyzer-cplusplus.NewDelete", "clang-analyzer-cplusplus.NewDeleteLeaks", "clang-analyzer-cplusplus.PlacementNew", "clang-analyzer-cplusplus.PureVirtualCall", "clang-analyzer-cplusplus.SelfAssignment", "clang-analyzer-cplusplus.SmartPtrModeling", "clang-analyzer-cplusplus.VirtualCallModeling", "clang-analyzer-deadcode.DeadStores", "clang-analyzer-fuchsia.HandleChecker", "clang-analyzer-nullability.NullPassedToNonnull", "clang-analyzer-nullability.NullReturnedFromNonnull", "clang-analyzer-nullability.NullabilityBase", "clang-analyzer-nullability.NullableDereferenced", "clang-analyzer-nullability.NullablePassedToNonnull", "clang-analyzer-nullability.NullableReturnedFromNonnull", "clang-analyzer-optin.cplusplus.UninitializedObject", "clang-analyzer-optin.cplusplus.VirtualCall", "clang-analyzer-optin.mpi.MPI-Checker", "clang-analyzer-optin.osx.OSObjectCStyleCast", "clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker", "clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker", "clang-analyzer-optin.performance.GCDAntipattern", "clang-analyzer-optin.performance.Padding", "clang-analyzer-optin.portability.UnixAPI", "clang-analyzer-osx.API", "clang-analyzer-osx.MIG", "clang-analyzer-osx.NSOrCFErrorDerefChecker", "clang-analyzer-osx.NumberObjectConversion", "clang-analyzer-osx.OSObjectRetainCount", "clang-analyzer-osx.ObjCProperty", "clang-analyzer-osx.SecKeychainAPI", "clang-analyzer-osx.cocoa.AtSync", "clang-analyzer-osx.cocoa.AutoreleaseWrite", "clang-analyzer-osx.cocoa.ClassRelease", "clang-analyzer-osx.cocoa.Dealloc", "clang-analyzer-osx.cocoa.IncompatibleMethodTypes", "clang-analyzer-osx.cocoa.Loops", "clang-analyzer-osx.cocoa.MissingSuperCall", "clang-analyzer-osx.cocoa.NSAutoreleasePool", "clang-analyzer-osx.cocoa.NSError", "clang-analyzer-osx.cocoa.NilArg", "clang-analyzer-osx.cocoa.NonNilReturnValue", "clang-analyzer-osx.cocoa.ObjCGenerics", "clang-analyzer-osx.cocoa.RetainCount", "clang-analyzer-osx.cocoa.RetainCountBase", "clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak", "clang-analyzer-osx.cocoa.SelfInit", "clang-analyzer-osx.cocoa.SuperDealloc", "clang-analyzer-osx.cocoa.UnusedIvars", "clang-analyzer-osx.cocoa.VariadicMethodTypes", "clang-analyzer-osx.coreFoundation.CFError", "clang-analyzer-osx.coreFoundation.CFNumber", "clang-analyzer-osx.coreFoundation.CFRetainRelease", "clang-analyzer-osx.coreFoundation.containers.OutOfBounds", "clang-analyzer-osx.coreFoundation.containers.PointerSizedValues", "clang-analyzer-security.FloatLoopCounter", "clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling", "clang-analyzer-security.insecureAPI.SecuritySyntaxChecker", "clang-analyzer-security.insecureAPI.UncheckedReturn", "clang-analyzer-security.insecureAPI.bcmp", "clang-analyzer-security.insecureAPI.bcopy", "clang-analyzer-security.insecureAPI.bzero", "clang-analyzer-security.insecureAPI.decodeValueOfObjCType", "clang-analyzer-security.insecureAPI.getpw", "clang-analyzer-security.insecureAPI.gets", "clang-analyzer-security.insecureAPI.mkstemp", "clang-analyzer-security.insecureAPI.mktemp", "clang-analyzer-security.insecureAPI.rand", "clang-analyzer-security.insecureAPI.strcpy", "clang-analyzer-security.insecureAPI.vfork", "clang-analyzer-unix.API", "clang-analyzer-unix.DynamicMemoryModeling", "clang-analyzer-unix.Malloc", "clang-analyzer-unix.MallocSizeof", "clang-analyzer-unix.MismatchedDeallocator", "clang-analyzer-unix.Vfork", "clang-analyzer-unix.cstring.BadSizeArg", "clang-analyzer-unix.cstring.CStringModeling", "clang-analyzer-unix.cstring.NullArg", "clang-analyzer-valist.CopyToSelf", "clang-analyzer-valist.Uninitialized", "clang-analyzer-valist.Unterminated", "clang-analyzer-valist.ValistBase", "clang-analyzer-webkit.NoUncountedMemberChecker", "clang-analyzer-webkit.RefCntblBaseVirtualDtor", "clang-analyzer-webkit.UncountedLambdaCapturesChecker" }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/AboutSettingsViewModel.cs ================================================ using ClangPowerTools; using ClangPowerTools.MVVM.Command; using ClangPowerTools.MVVM.Models; using System.ComponentModel; using System.Windows.Forms; using System.Windows.Input; namespace ClangPowerToolsShared.MVVM.ViewModels { public class AboutSettingsViewModel : CommonSettingsFunctionality { #region Members private readonly SettingsHandler settingsHandler = new SettingsHandler(); private ICommand exportSettingsCommand; private ICommand importSettingsCommand; private ICommand resetSettingsCommand; private GeneralSettingsModel generalModel; public event PropertyChangedEventHandler PropertyChanged; #endregion #region Constructor public AboutSettingsViewModel() { generalModel = SettingsProvider.GeneralSettingsModel; } #endregion #region Properties public GeneralSettingsModel GeneralSettingsModel { get { return generalModel; } set { generalModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("GeneralSettingsModel")); } } public string DisplayMessage { get { return displayMessage; } set { displayMessage = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayMessage")); } } public bool CanExecute { get { return true; } } private string displayMessage; #endregion public ICommand ExportSettingsCommand { get => exportSettingsCommand ??= new RelayCommand(() => ExportSettings(), () => CanExecute); } public ICommand ImportSettingssCommand { get => importSettingsCommand ??= new RelayCommand(() => ImportSettings(), () => CanExecute); } public ICommand ResetSettingsCommand { get => resetSettingsCommand ??= new RelayCommand(() => ResetSettings(), () => CanExecute); } private void ExportSettings() { string path = SaveFile("settings", ".json", "Settings files (.json)|*.json"); if (string.IsNullOrEmpty(path) == false) { settingsHandler.SaveSettings(path); MessageBox.Show("Settings exported.", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void ImportSettings() { string path = OpenFile("settings", ".json", "Settings files (.json)|*.json"); if (string.IsNullOrEmpty(path) == false) { settingsHandler.LoadSettings(path); MessageBox.Show("Settings imported.", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void ResetSettings() { settingsHandler.ResetSettings(); MessageBox.Show("Settings were reset to their default values.", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/AutoCompleteHistoryViewModel.cs ================================================ using System; namespace ClangPowerToolsShared.MVVM.ViewModels { public class AutoCompleteHistoryViewModel { public string Id { get; set; } = string.Empty; public string Value { get; set; } = string.Empty; public bool RememberAsFavorit { get; set; } = false; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/CompilerSettingsViewModel.cs ================================================ using ClangPowerTools.MVVM; using ClangPowerTools.MVVM.Commands; using ClangPowerTools.Services; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Windows.Forms; using System.Windows.Input; namespace ClangPowerTools { public class CompilerSettingsViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private CompilerSettingsModel compilerModel; private readonly PowerShellService powerShellService; private ICommand compileFlagsAddDataCommand; private ICommand filesToIgnoreAddDataCommand; private ICommand projectsToIgnoreAddDataCommand; private ICommand powerShellUpdateScriptsCommand; private ICommand addCptAliasCommand; #endregion #region Constructor public CompilerSettingsViewModel() { compilerModel = SettingsProvider.CompilerSettingsModel; powerShellService = new PowerShellService(); } #endregion #region Properties public CompilerSettingsModel CompilerModel { get { return compilerModel; } set { compilerModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CompilerModel")); } } public bool CanExecute { get { return true; } } public IEnumerable AdditionalIncludesItems { get { return Enum.GetValues(typeof(ClangGeneralAdditionalIncludes)).Cast(); } } public List VerbosityLevelItems { get { return new List() { "0", "1", "2" }; } } public SettingsTooltips Tooltip { get; } = new SettingsTooltips(); #endregion #region Commands public ICommand CompileFlagsAddDataCommand { get => compileFlagsAddDataCommand ?? (compileFlagsAddDataCommand = new RelayCommand(() => UpdateCompileFlags(), () => CanExecute)); } public ICommand FilesToIgnoreAddDataCommand { get => filesToIgnoreAddDataCommand ?? (filesToIgnoreAddDataCommand = new RelayCommand(() => UpdateFilesToIgnore(), () => CanExecute)); } public ICommand ProjectsToIgnoreAddDataCommand { get => projectsToIgnoreAddDataCommand ?? (projectsToIgnoreAddDataCommand = new RelayCommand(() => UpdateProjectsToIgnore(), () => CanExecute)); } public ICommand PowerShellUpdateScriptsCommand { get => powerShellUpdateScriptsCommand ?? (powerShellUpdateScriptsCommand = new RelayCommand(() => UpdateScripts(), () => CanExecute)); } public ICommand AddCptAliasCommand { get => addCptAliasCommand ?? (addCptAliasCommand = new RelayCommand(() => AddCptAlias(), () => CanExecute)); } #endregion #region Methods private void UpdateCompileFlags() { compilerModel.CompileFlags = OpenContentDialog(compilerModel.CompileFlags); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CompilerModel")); } private void UpdateFilesToIgnore() { compilerModel.FilesToIgnore = OpenContentDialog(compilerModel.FilesToIgnore, true, true); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CompilerModel")); } private void UpdateProjectsToIgnore() { compilerModel.ProjectsToIgnore = OpenContentDialog(compilerModel.ProjectsToIgnore); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CompilerModel")); } private void AddCptAlias() { string ScriptWindowsPowerShell = "if ((Test-Path -Path $profile -PathType Leaf) -eq $false) { New-Item -Path $profile -ItemType \"file\" -Force};" + $"Add-Content $profile ' Set-Alias -Name cpt -Value ''{PowerShellWrapper.GetClangBuildScriptPath()}'' ' "; if(PowerShellWrapper.Invoke(ScriptWindowsPowerShell, true)) { MessageBox.Show("Cpt alias for Clang Power Tools script was added in your Powershell profile", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("Sorry, we can't find Powershell 7 in PATH enviroment variables", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void UpdateScripts() { DialogResult dialogResult = MessageBox.Show("Do you want to update the PowerShell scripts?", "Clang Power Tools", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (dialogResult == DialogResult.Yes) { powerShellService.UpdateScriptsAsync().SafeFireAndForget(); } } #endregion; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/DetectedStyleInfoViewModel.cs ================================================ using System.Collections.ObjectModel; using System.ComponentModel; namespace ClangPowerTools { public class DetectedStyleInfoViewModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; #endregion #region Constructor public DetectedStyleInfoViewModel(string styleInfo) { var styleInfoArray = styleInfo.Split('\n'); foreach (var item in styleInfoArray) FlagsCollection.Add(item); } #endregion #region Properties public string DetectedOptions { get; set; } public ObservableCollection FlagsCollection { get; set; } = new ObservableCollection(); #endregion #region Private Methods private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/EncodingErrorViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Constants; using ClangPowerTools.MVVM.Models; using ClangPowerTools.Properties; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Windows.Input; namespace ClangPowerTools { class EncodingErrorViewModel : INotifyPropertyChanged { #region Public Properties public ICommand CloseCommand { get; set; } public ICommand ConvertCommand { get; set; } public ICommand SearchCommand { get; set; } public Action CloseAction { get; set; } public ObservableCollection FilesNotEncodedInUTF8 { get; set; } = new ObservableCollection(); public event PropertyChangedEventHandler PropertyChanged; public string SearchText { get { return searchText; } set { searchText = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SearchText")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FilteredFilesNotEncodedInUTF8")); } } public bool CheckAllItems { get { return checkAllItems; } set { if (checkAllItems == value) { return; } checkAllItems = value; SelectAllTooltipText = value ? ResourceConstants.DeselectAllTooltipText : ResourceConstants.SelectAllTooltipText; foreach (var file in FilesNotEncodedInUTF8) { file.IsChecked = value; } PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CheckAllItems")); } } public string SelectAllTooltipText { get { return selectAllTooltipText; } set { if (selectAllTooltipText == value) { return; } selectAllTooltipText = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectAllTooltipText")); } } public IEnumerable FilteredFilesNotEncodedInUTF8 { get { if (SearchText == null) { return FilesNotEncodedInUTF8; } return FilesNotEncodedInUTF8.Where(x => x.FileName.ToUpper().Contains(SearchText.ToUpper())); } } #endregion #region Private Properties private string searchText; private readonly List fileNames = new List(); private string selectAllTooltipText = ResourceConstants.DeselectAllTooltipText; private bool checkAllItems = true; #endregion #region Constructor public EncodingErrorViewModel(List selectedDocuments) { fileNames = selectedDocuments; CloseCommand = new RelayCommand(CloseCommandExecute); ConvertCommand = new RelayCommand(ConvertCommandExecute); SearchCommand = new RelayCommand(SearchCommandExecute); } #endregion #region Public Methods public void LoadData() { foreach (var file in fileNames) { var encodingFile = GetEncoding(file); if (encodingFile.EncodingName != Encoding.UTF8.EncodingName && !file.EndsWith(".vcxproj") && !file.EndsWith(".sln")) { FilesNotEncodedInUTF8.Add(new FileModel { FileName = file, IsChecked = true }); } } } #endregion #region Private Methods private void SearchCommandExecute() { if (false == string.IsNullOrWhiteSpace(SearchText)) { SearchText = string.Empty; } } private void CloseCommandExecute() { CloseAction?.Invoke(); } private void ConvertCommandExecute() { var checkedFiles = FilesNotEncodedInUTF8.Where(f => f.IsChecked); if (!checkedFiles.Any()) { return; } foreach (var file in checkedFiles) { ConvertFileToUTF8(file.FileName); } CloseCommandExecute(); } private void ConvertFileToUTF8(string file) { StreamReader streamReader = new StreamReader(file); string fileContent = streamReader.ReadToEnd(); streamReader.Close(); File.WriteAllText(file, fileContent, Encoding.UTF8); } private Encoding GetEncoding(string fileName) { using (var reader = new StreamReader(fileName, Encoding.Default, true)) { if (reader.Peek() >= 0) { reader.Read(); } return reader.CurrentEncoding; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/FeedbackViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using System.Diagnostics; using System.Windows.Input; namespace ClangPowerTools { public class FeedbackViewModel { #region Members private ICommand githubCommand; private ICommand websiteCommand; #endregion #region Properties public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand GithubCommand { get => githubCommand ??= new RelayCommand(() => OpenGitHubFeedback(), () => CanExecute); } public ICommand WebsiteCommand { get => websiteCommand ??= new RelayCommand(() => OpenWebsiteFeedback(), () => CanExecute); } #endregion #region Methods private void OpenGitHubFeedback() { Process.Start(new ProcessStartInfo("https://github.com/Caphyon/clang-power-tools/issues/new")); } private void OpenWebsiteFeedback() { Process.Start(new ProcessStartInfo("https://clangpowertools.com/contact.html")); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/FindToolWindowViewModel.cs ================================================ using ClangPowerTools; using ClangPowerTools.Commands; using ClangPowerTools.Views; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.AutoCompleteHistory; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Controllers; using ClangPowerToolsShared.MVVM.Interfaces; using ClangPowerToolsShared.MVVM.Models.ToolWindowModels; using ClangPowerToolsShared.MVVM.Provider; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Windows.Controls; namespace ClangPowerToolsShared.MVVM.ViewModels { public class FindToolWindowViewModel : FindController { public event PropertyChangedEventHandler PropertyChanged; private ObservableCollection astMatchersList = new(); private List astMatchersSearchOptions = new(); public List ViewMatchers { get { return FindToolWindowModel.ViewMatchers; } } //search in ast consts public List ASTMatchersSearchOptions { get { return astMatchersSearchOptions; } set { astMatchersSearchOptions = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ASTMatchersSearchOptions")); } } //display list public ObservableCollection ASTMatchersList { get { return astMatchersList; } set { astMatchersList = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ASTMatchersList")); } } public FindToolWindowViewModel(FindToolWindowView findToolWindowView) { AutoCompleteBehavior.OnListUpdate += OnListChange; astMatchersList = new ObservableCollection(GetASTMatchersWithHistory()); astMatchersSearchOptions = new List(GetASTMatchersWithHistory()); FindToolWindowModel = findToolWindowModel; this.findToolWindowView = findToolWindowView; } public void AddPinOnRightPlace(AutoCompleteHistoryModel autoCompleteHistoryModel) { int itemIndex = astMatchersList.IndexOf(autoCompleteHistoryModel); if (autoCompleteHistoryModel.RememberAsFavorit) { if (itemIndex != -1 && astMatchersList.Count >= itemIndex) { astMatchersList.Remove(autoCompleteHistoryModel); astMatchersList.Insert(0, autoCompleteHistoryModel); } } else { int lastFindIndex = astMatchersList.ToList().FindLastIndex(a => a.RememberAsFavorit == true && a.Id != autoCompleteHistoryModel.Id); if (itemIndex != -1 && lastFindIndex != -1 && astMatchersList.Count >= itemIndex && astMatchersList.Count >= lastFindIndex && itemIndex - lastFindIndex != 1) Swap(astMatchersList, lastFindIndex, itemIndex); } } public void OnListChange(object sender, TextChangedEventArgs e) { var tempMatchersList = astMatchersList.Where(a => a.Visibility == UIElementsConstants.Visibile).ToList(); astMatchersList.Clear(); foreach (var item in AutoCompleteBehavior.AutocompleteResult) { var tempItem = tempMatchersList.Where(a => item.Id == a.Id).FirstOrDefault(); if (tempItem != null) { tempItem.Value = item.Value; if (tempItem.RememberAsFavorit && tempItem.Visibility == UIElementsConstants.Visibile) astMatchersList.Insert(0, tempItem); else astMatchersList.Add(tempItem); } else { if (item.RememberAsFavorit && item.Visibility == UIElementsConstants.Visibile) astMatchersList.Insert(0, item); else astMatchersList.Add(item); } } ASTMatchersList = astMatchersList; } public void OpenToolWindow() { } public void RunQuery() { if (!RunController.StopCommandActivated) { SelectCommandToRun(findToolWindowModel.CurrentViewMatcher); RunPowershellQuery(); } AfterCommand(); } public void SelectCommandToRun(IViewMatcher viewMatcher) { findToolWindowModel.UpdateUiToSelectedModel(viewMatcher); FindToolWindowModel = findToolWindowModel; } public void RunCommandFromView() { BeforeCommand(); LaunchCommand(); //add in history AddMatcherInHistory(); CommandControllerInstance.CommandController.LaunchCommandAsync(CommandIds.kClangFindRun, CommandUILocation.ContextMenu); } private List GetASTMatchersWithHistory() { List astResult = ASTMatchers.AutoCompleteMatchers.Select(a => new AutoCompleteHistoryModel() { RememberAsFavorit = false, Value = a }).ToList(); if (FindToolWindowProvider.AutoCompleteHistory is null) return astResult; List jsonResult = FindToolWindowProvider.AutoCompleteHistory .Select(a => new AutoCompleteHistoryModel(a)).OrderBy(u => u.RememberAsFavorit ? 0 : 1).ToList(); return jsonResult.Concat(astResult).ToList(); } private void Swap(IList list, int indexA, int indexB) { T tmp = list[indexA]; list[indexA] = list[indexB]; list[indexB] = tmp; } private void AddMatcherInHistory() { if (findToolWindowModel.CurrentViewMatcher.Id == 2) { var matcher = findToolWindowModel.CurrentViewMatcher as CustomMatchesModel; if (ASTMatchersSearchOptions.Find(a => a.Value == matcher.Matchers) is null) { AutoCompleteHistoryViewModel autoCompleteHistoryViewModel = new AutoCompleteHistoryViewModel { Id = Guid.NewGuid().ToString(), RememberAsFavorit = false, Value = matcher.Matchers }; int indexSearchOptions = astMatchersSearchOptions.ToList().FindLastIndex(a => a.RememberAsFavorit == true); //add matchers in existing displayed list if (indexSearchOptions > 0) { astMatchersSearchOptions.Insert(indexSearchOptions + 1, new AutoCompleteHistoryModel(true) { RememberAsFavorit = false, Value = matcher.Matchers, Id = autoCompleteHistoryViewModel.Id }); } else { astMatchersSearchOptions.Insert(0, new AutoCompleteHistoryModel(true) { RememberAsFavorit = false, Value = matcher.Matchers, Id = autoCompleteHistoryViewModel.Id }); } int indexMatchersList = astMatchersList.ToList().FindLastIndex(a => a.RememberAsFavorit == true); if (indexMatchersList > 0) { astMatchersList.Insert(indexMatchersList + 1, new AutoCompleteHistoryModel(autoCompleteHistoryViewModel, true)); } else { astMatchersList.Insert(0, new AutoCompleteHistoryModel(autoCompleteHistoryViewModel, true)); } //save matchers displayed list ASTMatchersList = astMatchersList; ASTMatchersSearchOptions = astMatchersSearchOptions; //save matchers on json history file FindToolWindowProvider.AddAutoCompleteHistory(autoCompleteHistoryViewModel); FindToolWindowHandler findToolWindowHandler = new FindToolWindowHandler(); findToolWindowHandler.SaveMatchersHistoryData(); } } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/FolderExplorerViewModel.cs ================================================ using ClangPowerTools; using ClangPowerTools.MVVM.Command; using ClangPowerTools.MVVM.Views; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Windows.Forms; using System.Windows.Input; namespace ClangPowerToolsShared.MVVM.ViewModels { public class FolderExplorerViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private FolderExplorerView folderExplorerView; private string pathFolder = string.Empty; private PreinstalledLlvm preinstalledLlvm; private readonly List llvms; private ObservableCollection installedLlvms; private ICommand findFolderPathCommand; private ICommand downloadLLVMCommand; #endregion public FolderExplorerViewModel(FolderExplorerView folderExplorerView, List llvms, ObservableCollection installedLlvms) { this.llvms = llvms; this.installedLlvms = installedLlvms; this.folderExplorerView = folderExplorerView; } #region Properties public string PathFolder { get => pathFolder; set { pathFolder = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PathFolder")); } } public bool CanExecute => true; #endregion #region Commands public ICommand FindFolderPathCommand { get => findFolderPathCommand ?? (findFolderPathCommand = new RelayCommand(() => GetFolderPath(), () => CanExecute)); } public ICommand SetLLVMCommand { get => downloadLLVMCommand ?? (downloadLLVMCommand = new RelayCommand(() => SetLLVM(), () => CanExecute)); } public string VersionUsed { get { return SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion; } set { SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VersionUsed")); } } #endregion #region Public Methods public void SetLLVM() { if (string.IsNullOrWhiteSpace(PathFolder)) { MessageBox.Show("LLVM version can't be detected", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var clangPath = Path.Combine(PathFolder, "clang.exe"); if (!File.Exists(clangPath)) { clangPath = Path.Combine(PathFolder, "bin", "clang.exe"); if (!File.Exists(clangPath)) { MessageBox.Show("LLVM version can't be detected", "Clang Power Tools", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } pathFolder = Path.Combine(PathFolder, "bin"); } var versionInfo = FileVersionInfo.GetVersionInfo(clangPath); string version = versionInfo.FileVersion.Split()[0]; preinstalledLlvm = new PreinstalledLlvm(llvms, installedLlvms); preinstalledLlvm.SetPreinstalledLlvm(PathFolder, version); VersionUsed = version; folderExplorerView.Close(); } public void GetFolderPath() { var llvmBinDirectoryPath = BrowseForFolderFiles(); PathFolder = llvmBinDirectoryPath; if (string.IsNullOrWhiteSpace(llvmBinDirectoryPath)) return; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/FormatSettingsViewModel.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM; using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Views; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Input; namespace ClangPowerTools { public class FormatSettingsViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private FormatSettingsModel formatModel; private ICommand fileExtensionsAddDataCommand; private ICommand filesToIgnoreAddDataCommand; private ICommand assumeFilenameAddDataCommand; private ICommand customExecutableBrowseCommand; private ICommand openClangFormatEditorCommand; #endregion #region Constructor public FormatSettingsViewModel() { formatModel = SettingsProvider.FormatSettingsModel; } #endregion #region Properties public FormatSettingsModel FormatModel { get { return formatModel; } set { formatModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatModel")); } } public bool CanExecute { get { return true; } } public IEnumerable StyleItems { get { return Enum.GetValues(typeof(ClangFormatStyle)).Cast(); } } public IEnumerable FallBackStyleItems { get { return Enum.GetValues(typeof(ClangFormatFallbackStyle)).Cast(); } } public SettingsTooltips Tooltip { get; } = new SettingsTooltips(); #endregion #region Commands public ICommand FileExtensionsAddDataCommand { get => fileExtensionsAddDataCommand ??= new RelayCommand(() => UpdateFileExtensions(), () => CanExecute); } public ICommand FilesToIgnoreAddDataCommand { get => filesToIgnoreAddDataCommand ??= new RelayCommand(() => UpdateFilesToIgnore(), () => CanExecute); } public ICommand AssumeFilenameAddDataCommand { get => assumeFilenameAddDataCommand ??= new RelayCommand(() => UpdateAssumeFilename(), () => CanExecute); } public ICommand CustomExecutableBrowseCommand { get => customExecutableBrowseCommand ??= new RelayCommand(() => UpdateCustomExecutable(), () => CanExecute); } public ICommand OpenClangFormatEditorCommand { get => openClangFormatEditorCommand ??= new RelayCommand(() => OpenClangFormatEditor(), () => CanExecute); } #endregion #region Methods private void OpenClangFormatEditor() { if (FormatEditorUtility.FrameworkInstalled()) { SettingsProvider.SettingsView.Close(); var formatEditorController = new FormatEditorController(); formatEditorController.InstallClangFormatEditorSilent(); formatEditorController.OpenEditor(); } else { var formatEditorWarning = new FormatEditorWarning(); formatEditorWarning.ShowDialog(); } } private void UpdateFileExtensions() { formatModel.FileExtensions = OpenContentDialog(formatModel.FileExtensions); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatModel")); } private void UpdateFilesToIgnore() { formatModel.FilesToIgnore = OpenContentDialog(formatModel.FilesToIgnore, true, true); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatModel")); } private void UpdateAssumeFilename() { formatModel.AssumeFilename = OpenContentDialog(formatModel.AssumeFilename); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatModel")); } private void UpdateCustomExecutable() { formatModel.CustomExecutable = OpenFile(string.Empty, ".exe", "Executable files|*.exe"); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FormatModel")); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/InputDataViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Models; using ClangPowerTools.Views; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Windows.Forms; using System.Windows.Input; namespace ClangPowerTools { public class InputDataViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private string inputToAdd; private InputDataView inputDataView; private ICommand addCommand; private bool showFilePicker; private ICommand pickFilesCommand; private bool showFolderPicker; private ICommand pickFolderCommand; #endregion #region Constructor public InputDataViewModel(string content, bool showFilesPicker = false, bool showFolderPicker = false) { CreateInputsCollection(content); ShowFilesPicker = showFilesPicker; ShowFolderPicker = showFolderPicker; } public InputDataViewModel() { } #endregion #region Properties public string InputToAdd { get { return inputToAdd; } set { inputToAdd = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(InputToAdd))); } } public ObservableCollection Inputs { get; set; } = new ObservableCollection(); public bool ShowFilesPicker { get { return showFilePicker; } set { showFilePicker = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowFilesPicker))); } } public bool ShowFolderPicker { get { return showFolderPicker; } set { showFolderPicker = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowFolderPicker))); } } public ICommand AddCommand { get => addCommand ??= new RelayCommand(AddInput, () => CanExecute); } public bool CanExecute { get => true; } public ICommand PickFilesCommand { get => pickFilesCommand ??= new RelayCommand(PickFile, () => CanPickFilesExecute); } public bool CanPickFilesExecute { get => ShowFilesPicker; } public ICommand PickFolderCommand { get => pickFolderCommand ??= new RelayCommand(PickFolder, () => CanPickFolderExecute); } public bool CanPickFolderExecute { get => ShowFolderPicker; } #endregion #region Methods public void ShowViewDialog() { inputDataView = new InputDataView(this); inputDataView.ShowDialog(); } private void PickFile() { var filesToAdd = OpenFiles(string.Empty, "*.h;*.cpp", "Header and Source files|*.h;*.cpp|Header files|*.h|Source files|*.cpp"); if (filesToAdd == null) return; // no file selected foreach (var file in filesToAdd) { InputToAdd = file; AddInput(); // automatically add selected file } } private void PickFolder() { InputToAdd = BrowseForFolderFiles(); AddInput(); // automatically add selected folder } public void DeleteInput(int index) { if (index < 0 || index >= Inputs.Count) return; Inputs.RemoveAt(index); } private void AddInput() { if (string.IsNullOrWhiteSpace(inputToAdd)) return; if (IsDuplicate(inputToAdd)) { MessageBox.Show($"Ignored to add duplicate: {InputToAdd}", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); InputToAdd = string.Empty; return; } if(!File.Exists(inputToAdd) && !Directory.Exists(inputToAdd)) { MessageBox.Show($"The file or folder does not exist: {InputToAdd}", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if(File.Exists(inputToAdd)) { DirectoryInfo filePath = new DirectoryInfo(inputToAdd); inputToAdd = filePath.Name; } AddNewElement(inputToAdd); InputToAdd = string.Empty; } private bool IsDuplicate(string element) => Inputs.FirstOrDefault(model => model.InputData == element) != null; private void CreateInputsCollection(string content) { if (string.IsNullOrWhiteSpace(content)) return; var splitContent = content.Split(';').ToList(); foreach (var splitItem in splitContent) AddNewElement(splitItem); } private void AddNewElement(string newElement) { var model = new InputDataModel(newElement); Inputs.Add(model); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/InputMultipleDataViewModel.cs ================================================ namespace ClangPowerTools { public class InputMultipleDataViewModel { #region Properties public string Input { get; set; } #endregion #region Constructor public InputMultipleDataViewModel(string input) { Input = input; } // Empty constructor for XAML intelisense public InputMultipleDataViewModel() { } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/LicenseViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Controllers; using ClangPowerTools.MVVM.LicenseValidation; using ClangPowerTools.MVVM.Views; using System.Diagnostics; using System.Windows.Input; namespace ClangPowerTools { public class LicenseViewModel { #region Members private ICommand commercialLicenseCommand; private ICommand personalLicenseCommand; private ICommand trialLicenseCommand; private ICommand signInCommand; private readonly LicenseView licenseView; #endregion #region Constructor public LicenseViewModel() { } public LicenseViewModel(LicenseView view) { licenseView = view; } #endregion #region Properties public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand CommercialLicense { get => commercialLicenseCommand ?? (commercialLicenseCommand = new RelayCommand(() => CommercialLicenceExecute(), () => CanExecute)); } public ICommand PersonalLicense { get => personalLicenseCommand ?? (personalLicenseCommand = new RelayCommand(() => PersonalLicenceExecute(), () => CanExecute)); } public ICommand TrialLicense { get => trialLicenseCommand ?? (trialLicenseCommand = new RelayCommand(() => TrialLicenceExecute(), () => CanExecute)); } public ICommand SignIn { get => signInCommand ?? (signInCommand = new RelayCommand(() => PersonalLicenceExecute(), () => CanExecute)); } #endregion #region Methods public void CommercialLicenceExecute() { Process.Start(new ProcessStartInfo("https://clangpowertools.com/download.html#pricing")); ShowLoginView(); } public void PersonalLicenceExecute() { ShowLoginView(); } public void TrialLicenceExecute() { var freeTrialController = new FreeTrialController(); freeTrialController.Start(); SettingsProvider.AccountModel.LicenseType = LicenseType.Trial; SettingsProvider.AccountModel.LicenseExpirationDate = new SettingsHandler().GetTrialLicenseExpirationDate(); licenseView.Close(); } #endregion #region Private Methods public void ShowLoginView() { licenseView.Close(); LoginView loginView = new LoginView(); loginView.ShowDialog(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/LlvmSettingsViewModel.cs ================================================ using ClangPowerTools.Handlers; using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Controllers; using ClangPowerTools.MVVM.Views; using ClangPowerTools.Views; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Net; using System.Windows.Input; namespace ClangPowerTools { public class LlvmSettingsViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; public CancelEventHandler WindowClosed; private readonly LlvmController llvmController = new LlvmController(); private List llvms = new List(); private PreinstalledLlvm preinstalledLlvm; private const string uninstall = "Uninstall"; private ICommand browseForLlvmCommand; private LlvmSettingsView view; #endregion #region Constructor public LlvmSettingsViewModel(LlvmSettingsView view) { this.view = view; llvmController.InstallFinished = InstallFinished; llvmController.UninstallFinished = UninstallFinished; llvmController.OnOperationCanceldEvent += OperationCanceled; WindowClosed += llvmController.SettingsWindowClosed; IntitializeView(); } #endregion #region Properties public List Llvms { get { return llvms; } set { llvms = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Llvms")); } } public ObservableCollection InstalledLlvms { get; set; } = new ObservableCollection(); public string VersionUsed { get { return SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion; } set { SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VersionUsed")); } } public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand BrowseForLLVMCommand { get => browseForLlvmCommand ??= new RelayCommand(() => BrowseForLLVM(), () => CanExecute); } #endregion #region Public Methods public void DownloadCommand(int elementIndex) { DisableButtons(elementIndex); llvmController.llvmModel = llvms[elementIndex]; llvmController.llvmModel.IsDownloading = true; llvmController.Download(llvmController.llvmModel.Version, DownloadProgressChanged); } public void CancelCommand() { ResetButtonsState(); llvmController.llvmModel.DownloadProgress = 0; llvmController.llvmModel.IsDownloading = false; llvmController.downloadCancellationToken.Cancel(); } public void UninstallCommand(int elementIndex) { DisableButtons(elementIndex); llvmController.llvmModel = llvms[elementIndex]; llvmController.Uninstall(llvmController.llvmModel.Version); } public void BrowseForLLVM() { FolderExplorerView folderExplorerview = new FolderExplorerView(Llvms, InstalledLlvms); folderExplorerview.ShowDialog(); VersionUsed = SettingsProvider.LlvmSettingsModel.LlvmSelectedVersion; } #endregion #region Private Methods private void InstallFinished(object sender, EventArgs e) { ResetButtonsState(); VersionUsed = llvmController.llvmModel.Version; UIUpdater.InvokeAsync(InsertVersionToInstalledLlvms).SafeFireAndForget(); } private void UninstallFinished(object sender, EventArgs e) { ResetVersionUsedIfRequired(); ResetButtonsState(); UIUpdater.InvokeAsync(new Action(() => { InstalledLlvms.Remove(llvmController.llvmModel.Version); if (InstalledLlvms.Count > 0 && InstalledLlvms.Contains(VersionUsed) == false) { VersionUsed = InstalledLlvms[0]; } })).SafeFireAndForget(); } private void OperationCanceled() { ResetButtonsState(); } private void IntitializeView() { foreach (var version in LlvmVersions.Versions) { var llvmModel = new LlvmModel() { Version = version, IsInstalled = llvmController.IsVersionExeOnDisk(version, uninstall), }; if (llvmModel.IsInstalled) { InstalledLlvms.Add(llvmModel.Version); } llvms.Add(llvmModel); } preinstalledLlvm = new PreinstalledLlvm(Llvms, InstalledLlvms); preinstalledLlvm.SetPreinstalledLlvm(); SetSelectedVersionIfEmpty(); ResetVersionUsedIfRequired(); } private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { llvmController.llvmModel.DownloadProgress = e.ProgressPercentage; } private void SetSelectedVersionIfEmpty() { if (string.IsNullOrWhiteSpace(VersionUsed)) { if (InstalledLlvms.Count > 0) VersionUsed = InstalledLlvms[0]; } } private void ResetVersionUsedIfRequired() { if (InstalledLlvms.Count == 0) { VersionUsed = string.Empty; } } private void InsertVersionToInstalledLlvms() { for (int i = 0; i < InstalledLlvms.Count; i++) { if (string.CompareOrdinal(llvmController.llvmModel.Version, InstalledLlvms[i]) > 0) { InstalledLlvms.Insert(i, llvmController.llvmModel.Version); return; } } InstalledLlvms.Add(llvmController.llvmModel.Version); } private void DisableButtons(int elementIndex) { for (int i = 0; i < llvms.Count; i++) { if (i != elementIndex) llvms[i].CanExecuteCommand = false; } } private void ResetButtonsState() { foreach (var item in llvms) item.CanExecuteCommand = true; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/LoginViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Controllers; using ClangPowerTools.MVVM.Views; using ClangPowerTools.MVVM.WebApi; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Media; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools { public class LoginViewModel : INotifyPropertyChanged, IDataErrorInfo { #region Members public event PropertyChangedEventHandler PropertyChanged; private readonly AccountController accountController = new AccountController(); private UserModel userModel = new UserModel(); private LoginView loginView; private ICommand forgotPasswordCommand; private ICommand signUpCommand; private ICommand logInCommand; // Validation messages private readonly string invalidEmail = "The email that you have entered is not valid."; private readonly string invalidEmailOrPassword = "The email or password that you have entered is not valid."; // Login button colors private readonly string colorBackgroundEnabled = "#FFBF31"; private readonly string colorForegroundEnabled = "#000000"; private readonly string colorBackgroundDisabled = "#BBB6C4"; private readonly string colorForegroundDisabled = "#707079"; #endregion #region Properties public string Email { get { return userModel.email; } set { userModel.email = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Email")); } } public string Password { get { return userModel.password; } set { userModel.password = value; } } public bool IsInputValid { get; set; } = false; public bool CanExecute { get { return true; } } #endregion #region Constructor public LoginViewModel() { } public LoginViewModel(LoginView view) { loginView = view; } #endregion #region Commands public ICommand ForgotPassword { get => forgotPasswordCommand ?? (forgotPasswordCommand = new RelayCommand(() => ForgotPasswordAction(), () => CanExecute)); } public ICommand SignUp { get => signUpCommand ?? (signUpCommand = new RelayCommand(() => SignUpAction(), () => CanExecute)); } public ICommand LogIn { get => logInCommand ?? (logInCommand = new RelayCommand(() => SignInActionAsync().SafeFireAndForget(), () => CanExecute)); } #endregion #region IDataErrorInfo Interface public string Error => null; public string this[string name] { get { string result = null; switch (name) { case "Email": IsInputValid = IsEmailAddressValid(out string errorMessage); result = errorMessage; OnEmailValidation(); break; } return result; } } #endregion #region Public Methods public void ForgotPasswordAction() { Process.Start(new ProcessStartInfo(WebApiUrl.forgotPasswordUrl)); } public void SignUpAction() { Process.Start(new ProcessStartInfo(WebApiUrl.signUpUrl)); } public async Task SignInActionAsync() { if (string.IsNullOrWhiteSpace(Email) || IsInputValid == false) { loginView.InvalidUserTextBlock.Text = invalidEmailOrPassword; loginView.InvalidUserTextBlock.Visibility = Visibility.Visible; return; } SetLoginButtonState(false, colorBackgroundDisabled, colorForegroundDisabled); UserModel userModel = new UserModel(Email, Password); loginView.InvalidUserTextBlock.Text = invalidEmailOrPassword; loginView.InvalidUserTextBlock.Visibility = Visibility.Hidden; bool isAccountActive = await accountController.LoginAsync(userModel); if (isAccountActive) { loginView.Close(); FreeTrialController freeTrialController = new FreeTrialController(); freeTrialController.MarkAsExpired(); SettingsHandler settingsHandler = new SettingsHandler(); await settingsHandler.LicenseInfoUpdateAsync(); await settingsHandler.UserProfileInfoUpdateAsync(); } else { SetLoginButtonState(true, colorBackgroundEnabled, colorForegroundEnabled); loginView.InvalidUserTextBlock.Text = invalidEmailOrPassword; loginView.InvalidUserTextBlock.Visibility = Visibility.Visible; } } #endregion #region Private Methods private bool IsEmailAddressValid(out string errorMessage) { errorMessage = null; var validEmailAddress = new EmailAddressAttribute().IsValid(Email); if (validEmailAddress == false) { errorMessage = "Email address is required"; return false; } return true; } private void SetLoginButtonState(bool isEnabled, string background, string foreground) { Color colorBackground = (Color)ColorConverter.ConvertFromString(background); Color colorForeground = (Color)ColorConverter.ConvertFromString(foreground); loginView.LoginButton.IsEnabled = isEnabled; loginView.LoginButton.Background = new SolidColorBrush(colorBackground); loginView.LoginButton.Foreground = new SolidColorBrush(colorForeground); } private void OnEmailValidation() { if (IsInputValid) { loginView.InvalidUserTextBlock.Visibility = Visibility.Hidden; } else { loginView.InvalidUserTextBlock.Text = invalidEmail; loginView.InvalidUserTextBlock.Visibility = Visibility.Visible; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/ReleaseNotesViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Views; using System.Diagnostics; using System.Windows.Input; namespace ClangPowerTools { public class ReleaseNotesViewModel { #region Members private ICommand upgradeCommand; private ICommand openBlogCommand; private readonly ReleaseNotesView releaseNotesView; #endregion #region Constructor public ReleaseNotesViewModel(ReleaseNotesView release) { releaseNotesView = release; } #endregion #region Properties public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand LogIn { get => upgradeCommand ?? (upgradeCommand = new RelayCommand(() => LogInAction(), () => CanExecute)); } public ICommand OpenBlog { get => openBlogCommand ?? (openBlogCommand = new RelayCommand(() => OpenBlogAction(), () => CanExecute)); } #endregion #region Private Methods private void LogInAction() { releaseNotesView.Close(); LoginView loginView = new LoginView(); loginView.ShowDialog(); } private void OpenBlogAction() { Process.Start(new ProcessStartInfo("https://clangpowertools.com/blog/future-of-clang-power-tools.html")); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/SettingsViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Views; using ClangPowerTools.Views; using System; using System.Windows.Input; namespace ClangPowerTools { public class SettingsViewModel { #region Members private ICommand upgradeCommand; private readonly SettingsHandler settingsHandler = new(); private readonly SettingsView settingsView; private const int PERSONAL_LICENSE_HEIGTH = 575; private const int NO_ACCOUNT_HEIGTH = 640; #endregion #region Constructors public SettingsViewModel(SettingsView settingsView, bool showFooter) { this.settingsView = settingsView; settingsView.Closed += OnClosed; ShowFooter = showFooter; Heigth = ShowFooter ? PERSONAL_LICENSE_HEIGTH : NO_ACCOUNT_HEIGTH; } #endregion #region Properties public bool ShowFooter { get; private set; } public int Heigth { get; set; } public bool CanExecute { get { return true; } } #endregion #region Public Methods public void OnClosed(object sender, EventArgs e) { settingsHandler.SaveSettings(); settingsView.Closed -= OnClosed; SettingsHandler.RefreshSettingsView = null; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/TidyChecksViewModel.cs ================================================ using ClangPowerTools.Events; using ClangPowerTools.MVVM; using ClangPowerTools.MVVM.Commands; using ClangPowerTools.Views; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Input; namespace ClangPowerTools { public class TidyChecksViewModel : INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private string checkSearch = string.Empty; private TidySettingsModel tidyModel; private TidyChecksView tidyChecksView; private TidyCheckModel selectedCheck = new(); private List tidyChecksList = new(); private ICommand resetSearchCommand; #endregion #region Constructor public TidyChecksViewModel(TidyChecksView view) { tidyModel = SettingsProvider.TidySettingsModel; tidyChecksView = view; tidyChecksView.Closed += OnClosed; // Click event is used because the Check value is changed many time from the code // In this way we don't need to make more checks to see from where the Check event was triggered tidyChecksView.EnableDisableAll.Click += (object sender, RoutedEventArgs e) => { // Check event is triggered before Click event. // IsChecked property will already have the new value when the Click event will happend EnableDisableAllChecks(tidyChecksView.EnableDisableAll.IsChecked == true ? true : false); }; tidyChecksView.EnableDisableDefaults.Click += (object sender, RoutedEventArgs e) => { // Check event is triggered before Click event. // IsChecked property will already have the new value when the Click event will happend SetDefaultsToggle(tidyChecksView.EnableDisableDefaults.IsChecked == true ? true : false); }; InitializeChecks(); } #endregion #region Properties public TidyChecksView TidyChecksView { get { return tidyChecksView; } set { InitializeChecks(); tidyChecksView = value; } } public List TidyChecksList { get { List checks = string.IsNullOrEmpty(checkSearch) ? tidyChecksList : tidyChecksList.Where(e => e.Name.Contains(checkSearch, StringComparison.OrdinalIgnoreCase)).ToList(); // Always keep the current list of checks under surveillance CollectionElementsCounter.Initialize(checks); CollectionElementsCounter.StateEvent += SetStateForEnableDisableAllButton; SetInitialStateEnableAllToggle(checks); return checks; } } public string CheckSearch { get { return checkSearch; } set { checkSearch = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CheckSearch")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyChecksList")); } } public TidyCheckModel SelectedCheck { get { return selectedCheck; } set { selectedCheck = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedCheck")); } } public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand ResetSearchCommand { get => resetSearchCommand ??= new RelayCommand(() => ResetSearchField(), () => CanExecute); } #endregion #region Methods public void MultipleStateChange(bool checkValue) { if (tidyChecksView.TidyChecksListBox.SelectedItems.Count <= 1) return; foreach (object item in tidyChecksView.TidyChecksListBox.SelectedItems) { TidyCheckModel model = (TidyCheckModel)item; if (model.IsChecked != checkValue) { model.IsChecked = checkValue; } } } public void DeactivateDefaultsToggle() { if (tidyChecksView.EnableDisableDefaults.IsChecked.Value) { tidyChecksView.EnableDisableDefaults.IsChecked = false; } } public void OpenBrowser(string tidyCheckName) { string uri = CreateFlagUri(tidyCheckName); Process.Start(uri); } private string CreateFlagUri(string tidyCheckName) { StringBuilder sb = new(); string checkName = string.Empty; if (tidyCheckName.Contains("clang-analyzer-")) { checkName = tidyCheckName.Replace("clang-analyzer-", "clang-analyzer/"); } else if (tidyCheckName.IndexOf('-') != -1) { var listTidyCheckName = tidyCheckName.ToCharArray(); listTidyCheckName[tidyCheckName.IndexOf('-')] = '/'; checkName = new string(listTidyCheckName); } sb.Append(TidyConstants.FlagsUri).Append(checkName).Append(".html"); return sb.ToString(); } private void LoadChecks() { string input = SettingsProvider.TidySettingsModel.PredefinedChecks; if (string.IsNullOrWhiteSpace(input)) { return; } input = Regex.Replace(input, @"\s+", ""); input = input.Remove(input.Length - 1, 1); List checkNames = input.Split(';').ToList(); foreach (string check in checkNames) { foreach (TidyCheckModel tidyModel in tidyChecksList) { if (string.Equals(check, tidyModel.Name, StringComparison.OrdinalIgnoreCase)) { tidyModel.IsChecked = true; } } } } private void InitializeChecks() { tidyChecksList = new TidyChecks().Checks; LoadChecks(); SetInitialStateEnableAllToggle(tidyChecksList); SetInitialStateDefaultsToggle(); } private void SetDefaultsToggle(bool value) { if (value) { SetDefaultChecks(); tidyChecksView.EnableDisableDefaults.IsChecked = true; } else { EnableDisableAllChecks(false); tidyChecksView.EnableDisableDefaults.IsChecked = false; } } private void SetInitialStateDefaultsToggle() { int count = tidyChecksList.Where(e => e.IsChecked).Count(); if (count == 0 || count != TidyChecksDefault.Checks.Count) { tidyChecksView.EnableDisableDefaults.IsChecked = false; return; } foreach (TidyCheckModel check in tidyChecksList) { if (check.IsChecked == false && TidyChecksDefault.Checks.Contains(check.Name)) { tidyChecksView.EnableDisableDefaults.IsChecked = false; return; } } tidyChecksView.EnableDisableDefaults.IsChecked = true; } /// /// Enable or disable all the tidy checks from the current tidy checks list /// /// True to enable all tidy checks. False to disable all tidy checks private void EnableDisableAllChecks(bool value) { // get all checks from current view considering the search filter var checks = string.IsNullOrEmpty(checkSearch) ? tidyChecksList : tidyChecksList.Where(e => e.Name.Contains(checkSearch, StringComparison.OrdinalIgnoreCase)).ToList(); // set just the current collection of checks for (int i = 0; i < checks.Count; ++i) checks[i].IsChecked = value; } /// /// Set the state for Enable/Disable All toggle button /// /// Tidy checks collection private void SetInitialStateEnableAllToggle(IEnumerable checks) { // to avoid enter in the second condition the first one must be split in two if statements // uncheck the Enable All toggle button if the retured list of checks has 0 elements if (checks.Count() == 0) { if (tidyChecksView.EnableDisableAll.IsChecked == true) tidyChecksView.EnableDisableAll.IsChecked = false; } // check the Enable All toggle button if all the checks from the current view are enabled else if (tidyChecksView.EnableDisableAll.IsChecked == false && !checks.Any(c => c.IsChecked == false)) { tidyChecksView.EnableDisableAll.IsChecked = true; } // uncheck the Enable All toggle button if any check from the list is disabled else if (tidyChecksView.EnableDisableAll.IsChecked == true && checks.Any(c => c.IsChecked == false)) { tidyChecksView.EnableDisableAll.IsChecked = false; } } /// /// Set the state for Enable/Disable All toggle button /// /// Value is NULL. Event is triggered from a static object which has no this value. /// Contains the state of the toggle button private void SetStateForEnableDisableAllButton(object sender, BoolEventArgs e) { tidyChecksView.EnableDisableAll.IsChecked = e.Value; } private void OnClosed(object sender, EventArgs e) { tidyModel.PredefinedChecks = GetSelectedChecks(); tidyChecksView.Closed -= OnClosed; CollectionElementsCounter.StateEvent -= SetStateForEnableDisableAllButton; } private string GetSelectedChecks() { StringBuilder checks = new(); foreach (TidyCheckModel item in tidyChecksList) { if (item.IsChecked) { checks.Append(item.Name).Append(";"); } } return checks.ToString(); } private void ResetSearchField() { CheckSearch = string.Empty; } private void SetDefaultChecks() { foreach (TidyCheckModel check in tidyChecksList) { check.IsChecked = TidyChecksDefault.Checks.Contains(check.Name); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/TidySettingsViewModel.cs ================================================ using ClangPowerTools.MVVM; using ClangPowerTools.MVVM.Commands; using ClangPowerTools.Views; using ClangPowerToolsShared.MVVM.Constants; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Forms; using System.Windows.Input; namespace ClangPowerTools { public class TidySettingsViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private TidySettingsModel tidyModel; private string headerFilter = string.Empty; private string displayWarning = string.Empty; private ICommand headerFilterAddDataCommand; private ICommand customExecutableBrowseCommand; private ICommand compilationDatabaseBrowseCommand; private ICommand predefinedChecksSelectCommand; private ICommand customChecksAddDataCommand; private ICommand exportTidyConfigCommand; #endregion #region Constructor public TidySettingsViewModel() { tidyModel = SettingsProvider.TidySettingsModel; HeaderFilters = new List() { tidyModel.HeaderFilter, ComboBoxConstants.kCorrespondingHeaderName }; headerFilter = tidyModel.HeaderFilter; UpdateWarningVisibility(); } #endregion #region Properties public TidySettingsModel TidyModel { get { UpdateWarningVisibility(); return tidyModel; } set { tidyModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); } } public string DisplayWarning { get { return displayWarning; } set { displayWarning = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayWarning")); } } public List HeaderFilters { get; set; } public string HeaderFilter { get { return headerFilter; } set { headerFilter = value; if (headerFilter == ComboBoxConstants.kCorrespondingHeaderName) { tidyModel.HeaderFilter = ComboBoxConstants.kCorrespondingHeaderValue; } else { tidyModel.HeaderFilter = value; } } } public bool CanExecute { get { return true; } } public IEnumerable UseChecksFromItems { get { return Enum.GetValues(typeof(ClangTidyUseChecksFrom)).Cast(); } } public SettingsTooltips Tooltip { get; } = new SettingsTooltips(); #endregion #region Commands public ICommand HeaderFilterAddDataCommand { get => headerFilterAddDataCommand ?? (headerFilterAddDataCommand = new RelayCommand(() => UpdateHeaderFilter(), () => CanExecute)); } public ICommand CustomExecutableBrowseCommand { get => customExecutableBrowseCommand ?? (customExecutableBrowseCommand = new RelayCommand(() => UpdateCustomExecutable(), () => CanExecute)); } public ICommand CompilationDatabaseBrowseCommand { get => compilationDatabaseBrowseCommand ?? (compilationDatabaseBrowseCommand = new RelayCommand(() => UpdateCompilationDatabase(), () => CanExecute)); } public ICommand PredefinedChecksSelectCommand { get => predefinedChecksSelectCommand ?? (predefinedChecksSelectCommand = new RelayCommand(() => UpdatePredefinedChecks(), () => CanExecute)); } public ICommand CustomChecksAddDataCommand { get => customChecksAddDataCommand ?? (customChecksAddDataCommand = new RelayCommand(() => UpdateCustomChecks(), () => CanExecute)); } public ICommand ExportTidyConfigCommand { get => exportTidyConfigCommand ?? (exportTidyConfigCommand = new RelayCommand(() => ExportTidyConfig(), () => CanExecute)); } #endregion #region Methods private void UpdateWarningVisibility() { var tidySettings = SettingsProvider.TidySettingsModel; if (tidySettings.ApplyTidyFix) displayWarning = UIElementsConstants.Visibile; else displayWarning = UIElementsConstants.Hidden; DisplayWarning = displayWarning; } private void UpdateHeaderFilter() { tidyModel.HeaderFilter = OpenContentDialog(tidyModel.HeaderFilter); HeaderFilter = tidyModel.HeaderFilter; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HeaderFilter")); } private void UpdateCustomChecks() { tidyModel.CustomChecks = OpenContentDialog(tidyModel.CustomChecks); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); } private void UpdateCustomExecutable() { tidyModel.CustomExecutable = OpenFile(string.Empty, ".exe", "Executable files|*.exe"); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); } private void UpdateCompilationDatabase() { string path = OpenFile(string.Empty, ".json", "Compilation database (*.json)|*.json"); if (string.IsNullOrEmpty(path) == false) { tidyModel.CompilationDatabase = path; } PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); } private void UpdatePredefinedChecks() { OpenChecksWindow(); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyModel")); } private void ExportTidyConfig() { var tidyConfigFile = new TidyConfigFile(); string fileName = ".clang-tidy"; string defaultExt = ".clang-tidy"; string filter = "Configuration files (.clang-tidy)|*.clang-tidy"; string path = SaveFile(fileName, defaultExt, filter); if (string.IsNullOrEmpty(path) == false) { WriteContentToFile(path, tidyConfigFile.CreateOutput().ToString()); MessageBox.Show(".clang-tidy file exported at the selected location.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void OpenChecksWindow() { var tidyChecksView = new TidyChecksView(); tidyChecksView.ShowDialog(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/TidyToolWindowViewModel.cs ================================================ using ClangPowerTools; using ClangPowerTools.MVVM.Command; using ClangPowerTools.MVVM.Models; using ClangPowerTools.Views; using ClangPowerToolsShared.MVVM.Constants; using ClangPowerToolsShared.MVVM.Controllers; using ClangPowerToolsShared.MVVM.Models; using ClangPowerToolsShared.MVVM.Models.TidyToolWindowModels; using Microsoft.VisualStudio.PlatformUI; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Windows.Data; using System.Windows.Input; using Task = System.Threading.Tasks.Task; namespace ClangPowerToolsShared.MVVM.ViewModels { public class TidyToolWindowViewModel : CommonSettingsFunctionality, INotifyPropertyChanged { #region Members public event PropertyChangedEventHandler PropertyChanged; private TidyToolWindowView tidyToolWindowView; private MessageModel messageModel; private string listVisibility = UIElementsConstants.Visibile; private TidyToolWindowController TidyController; //To not refresh files value every time (with the same files), and to not refresh check box value bool wasMadeTidyOnFiles = false; private ICommand tidyAllCommand; private ICommand fixAllCommand; private ICommand discardAllCommand; private ICommand removeAllCommand; public ObservableCollection Files { get { return TidyController.files; } set { TidyController.files = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Files")); } } #endregion #region Properties public TidyToolWindowModel TidyToolWindowModel { get { return TidyController.tidyToolWindowModel; } set { TidyController.tidyToolWindowModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TidyToolWindowModel")); } } public MessageModel MessageModel { get { return messageModel; } set { messageModel = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MessageModel")); } } public string ListVisibility { get { return listVisibility; } set { listVisibility = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ListVisibility")); } } public bool CanExecute { get { return true; } } #endregion #region Commands public ICommand TidyAllCommand { get => tidyAllCommand ?? (tidyAllCommand = new RelayCommand(() => TidyAllFilesAsync().SafeFireAndForget(), () => CanExecute)); } public ICommand FixAllCommand { get => fixAllCommand ?? (fixAllCommand = new RelayCommand(() => FixAllFilesAsync().SafeFireAndForget(), () => CanExecute)); } public ICommand DiscardAllCommand { get => discardAllCommand ?? (discardAllCommand = new RelayCommand(() => DiscardAllFiles(), () => CanExecute)); } public ICommand RemoveAllCommand { get => removeAllCommand ?? (removeAllCommand = new RelayCommand(() => RemoveAllFiles(), () => CanExecute)); } #endregion #region Constructos public TidyToolWindowViewModel(TidyToolWindowView tidyToolWindowView) { VSColorTheme.ThemeChanged += ThemeChangeEvent; this.tidyToolWindowView = tidyToolWindowView; //init TidyController = new TidyToolWindowController(); messageModel = new MessageModel(); TidyController.tidyToolWindowModel.ButtonVisibility = UIElementsConstants.Visibile; TidyController.tidyToolWindowModel.ProgressBarVisibility = UIElementsConstants.Hidden; //Create groups CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(Files); PropertyGroupDescription groupDescription = new PropertyGroupDescription("FilesType"); view.GroupDescriptions.Add(groupDescription); } #endregion #region Public Methods public void OpenTidyToolWindow(List filesPath) { RefreshOnWindowUpdate(); TidyController.InitTidyToolWindow(filesPath); wasMadeTidyOnFiles = true; } public void UpdateViewModel(List filesPath) { //if tidy fix was made add headers if (!wasMadeTidyOnFiles) { TidyController.AddHeadersInFilesList(filesPath); } if (Files.Count == 0) { TidyController.AddFilesInFilesList(filesPath); } if (!Directory.Exists(TidyConstants.TempsFolderPath)) Directory.CreateDirectory(TidyConstants.TempsFolderPath); } private async Task TidyAllFilesAsync(List paths = null) { wasMadeTidyOnFiles = true; TidyController.TidyFilesAsync(paths); } public void CheckOrUncheckAll() { TidyController.CheckOrUncheckAll(); } public async Task FixAllFilesAsync(FileModel file = null) { TidyController.FixAllFilesAsync(file); wasMadeTidyOnFiles = false; } /// /// Update checked numer on check and uncheck action /// /// public void UpdateCheckedNumber(FileModel file) { TidyController.UpdateCheckedNumber(file); TidyToolWindowModel = TidyController.tidyToolWindowModel; } public void DiffFile(FileModel file) { TidyController.DiffBetweenCopyAndCurrent(file); } #endregion #region Private Method private void RemoveAllFiles() { TidyController.BeforeCommand(); TidyController.RemoveFiles(); //Display a message if no file is in list if (Files.Count == 0) { listVisibility = UIElementsConstants.Hidden; ListVisibility = ListVisibility; messageModel.Visibility = UIElementsConstants.Visibile; messageModel.TextMessage = "Files on which you run Tidy will be shown here"; MessageModel = messageModel; } TidyController.AfterCommand(); } private void DiscardAllFiles() { if (TidyToolWindowModel.CountFilesModel.TotalCheckedFixedFiles != 0) { TidyController.BeforeCommand(); var checkedFiles = TidyController.files.Where(f => f.IsChecked).ToList(); foreach (var file in checkedFiles) { if (file.IsChecked) { TidyController.DiscardFile(file); //If is a header remove from file list if (file.FilesType == FileType.Header) { TidyController.RemoveFiles(file); } } } TidyController.AfterCommand(); } } public void ThemeChangeEvent(ThemeChangedEventArgs e) { TidyController.tidyToolWindowModel.ChangeIconsTheme(); foreach (var file in TidyController.files) { file.ChangeIconsTheme(); } } /// /// Make list visible after tidy from toolbar or contextMenu /// private void RefreshOnWindowUpdate() { listVisibility = UIElementsConstants.Visibile; messageModel.Visibility = UIElementsConstants.Hidden; ListVisibility = listVisibility; MessageModel = messageModel; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/ToggleMultipleDataViewModel.cs ================================================ using ClangPowerTools.MVVM.Models; using System; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools { public class ToggleMultipleDataViewModel { public List Input { get; set; } = new List(); #region Properties public IEnumerable BooleanComboboxValues { get { return Enum.GetValues(typeof(ToggleValues)).Cast(); } } #endregion #region Constructor public ToggleMultipleDataViewModel(List input) { Input = input; } // Empty constructor for public ToggleMultipleDataViewModel() { } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/ViewModels/TrialExpiredViewModel.cs ================================================ using ClangPowerTools.MVVM.Commands; using ClangPowerTools.MVVM.Views; using System.Diagnostics; using System.Windows.Input; namespace ClangPowerTools { public class TrialExpiredViewModel { #region Members private ICommand commercialLicenseCommand; private ICommand personalLicenseCommand; private ICommand signInCommand; private readonly TrialExpiredView trialExpiredView; #endregion #region Properties public bool CanExecute { get { return true; } } #region Constructor public TrialExpiredViewModel() { } public TrialExpiredViewModel(TrialExpiredView view) { trialExpiredView = view; } #endregion #endregion #region Commands public ICommand CommercialLicense { get => commercialLicenseCommand ?? (commercialLicenseCommand = new RelayCommand(() => CommercialLicenceExecute(), () => CanExecute)); } public ICommand PersonalLicense { get => personalLicenseCommand ?? (personalLicenseCommand = new RelayCommand(() => PersonalLicenceExecute(), () => CanExecute)); } public ICommand SignIn { get => signInCommand ?? (signInCommand = new RelayCommand(() => PersonalLicenceExecute(), () => CanExecute)); } #endregion #region Methods public void CommercialLicenceExecute() { Process.Start(new ProcessStartInfo("https://clangpowertools.com/download.html#pricing")); ShowLoginView(); } public void PersonalLicenceExecute() { ShowLoginView(); } #endregion #region Private Methods public void ShowLoginView() { trialExpiredView.Close(); LoginView loginView = new LoginView(); loginView.ShowDialog(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/AboutSettingsView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/InputList.xaml.cs ================================================ using ClangPowerTools.MVVM.Models; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace ClangPowerTools.MVVM.Views.Components { /// /// Interaction logic for InputList.xaml /// public partial class InputList : UserControl { #region Constructor public InputList() { InitializeComponent(); } #endregion #region Properties public string InputToAdd { get { return (string)GetValue(InputToAddProperty); } set { SetValue(InputToAddProperty, value); } } public static readonly DependencyProperty InputToAddProperty = DependencyProperty.Register("InputToAdd", typeof(string), typeof(InputList), new PropertyMetadata(null)); public ICommand AddCommand { get { return (ICommand)GetValue(AddCommandProperty); } set { SetValue(AddCommandProperty, value); } } public static readonly DependencyProperty AddCommandProperty = DependencyProperty.Register("AddCommand", typeof(ICommand), typeof(InputList), new PropertyMetadata(null)); public ICommand PickFilesCommand { get { return (ICommand)GetValue(PickFilesCommandProperty); } set { SetValue(PickFilesCommandProperty, value); } } public static readonly DependencyProperty PickFilesCommandProperty = DependencyProperty.Register("PickFilesCommand", typeof(ICommand), typeof(InputList), new PropertyMetadata(null)); public ICommand PickFolderCommand { get { return (ICommand)GetValue(PickFolderCommandProperty); } set { SetValue(PickFolderCommandProperty, value); } } public static readonly DependencyProperty PickFolderCommandProperty = DependencyProperty.Register("PickFolderCommand", typeof(ICommand), typeof(InputList), new PropertyMetadata(null)); public ObservableCollection Collection { get { return (ObservableCollection)GetValue(CollectionProperty); } set { SetValue(CollectionProperty, value); } } public static readonly DependencyProperty CollectionProperty = DependencyProperty.Register("Collection", typeof(ObservableCollection), typeof(InputList), null); #endregion //#region Routed Events //public static readonly RoutedEvent DeleteButtonClickEvent = EventManager.RegisterRoutedEvent( // "DeleteButtonClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(InputList)); //public event RoutedEventHandler DeleteButtonClick //{ // add { AddHandler(DeleteButtonClickEvent, value); } // remove { RemoveHandler(DeleteButtonClickEvent, value); } //} //private void DeleteButton_Click(object sender, RoutedEventArgs e) //{ // var newEventArgs = new RoutedEventArgs(DeleteButtonClickEvent); // RaiseEvent(newEventArgs); //} //#endregion #region Methods private void DeleteButton_Click(object sender, RoutedEventArgs e) { var elementIndex = GetElementIndex(sender as FrameworkElement); ((InputDataViewModel)DataContext).DeleteInput(elementIndex); } private int GetElementIndex(FrameworkElement frameworkElement) { var element = frameworkElement.DataContext; return CollectionItems.Items.IndexOf(element); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/MessageBanner.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/MessageBanner.xaml.cs ================================================ using System.Windows; using System.Windows.Controls; namespace ClangPowerTools.MVVM.Views.Components { /// /// Interaction logic for MessageBanner.xaml /// public partial class MessageBanner : UserControl { public MessageBanner() { InitializeComponent(); } public string Banner { get { return (string)GetValue(BannerProperty); } set { SetValue(BannerProperty, value); } } public static readonly DependencyProperty BannerProperty = DependencyProperty.Register("Banner", typeof(string), typeof(MessageBanner), new PropertyMetadata(null)); public string Icon { get { return (string)GetValue(IconProperty); } set { SetValue(IconProperty, value); } } public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(string), typeof(MessageBanner), new PropertyMetadata(null)); public string Type { get { return (string)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(string), typeof(MessageBanner), new PropertyMetadata(null)); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/ThreePieceButton.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/ThreePieceButton.xaml.cs ================================================ using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace ClangPowerTools.MVVM.Views.Components { /// /// Interaction logic for ThreePieceButton.xaml /// public partial class ThreePieceButton : UserControl { public ThreePieceButton() { InitializeComponent(); } #region Component public string BackgroundValue { get { return (string)GetValue(BackgroundValueProperty); } set { SetValue(BackgroundValueProperty, value); } } public static readonly DependencyProperty BackgroundValueProperty = DependencyProperty.Register("BackgroundValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string OpacityValue { get { return (string)GetValue(OpacityValueProperty); } set { SetValue(OpacityValueProperty, value); } } public static readonly DependencyProperty OpacityValueProperty = DependencyProperty.Register("OpacityValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string WidthValue { get { return (string)GetValue(WidthValueProperty); } set { SetValue(WidthValueProperty, value); } } public static readonly DependencyProperty WidthValueProperty = DependencyProperty.Register("WidthValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string HeightValue { get { return (string)GetValue(HeightValueProperty); } set { SetValue(HeightValueProperty, value); } } public static readonly DependencyProperty HeightValueProperty = DependencyProperty.Register("HeightValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); #endregion #region ImageComponent public string Image { get { return (string)GetValue(ImageProperty); } set { SetValue(ImageProperty, value); } } public static readonly DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string ImageWidthValue { get { return (string)GetValue(ImageWidthValueProperty); } set { SetValue(ImageWidthValueProperty, value); } } public static readonly DependencyProperty ImageWidthValueProperty = DependencyProperty.Register("ImageWidthValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string ImageHeightValue { get { return (string)GetValue(ImageHeightValueProperty); } set { SetValue(ImageHeightValueProperty, value); } } public static readonly DependencyProperty ImageHeightValueProperty = DependencyProperty.Register("ImageHeightValue", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); #endregion #region TitleComponent public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string TitleFontSize { get { return (string)GetValue(TitleFontSizeProperty); } set { SetValue(TitleFontSizeProperty, value); } } public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register("TitleFontSize", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string TitleForeground { get { return (string)GetValue(TitleForegroundProperty); } set { SetValue(TitleForegroundProperty, value); } } public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register("TitleForeground", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); #endregion #region DescriptionComponent public string Description { get { return (string)GetValue(DescriptionProperty); } set { SetValue(DescriptionProperty, value); } } public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string DescriptionFontSize { get { return (string)GetValue(DescriptionFontSizeProperty); } set { SetValue(DescriptionFontSizeProperty, value); } } public static readonly DependencyProperty DescriptionFontSizeProperty = DependencyProperty.Register("DescriptionFontSize", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); public string DescriptionForeground { get { return (string)GetValue(DescriptionForegroundProperty); } set { SetValue(DescriptionForegroundProperty, value); } } public static readonly DependencyProperty DescriptionForegroundProperty = DependencyProperty.Register("DescriptionForeground", typeof(string), typeof(ThreePieceButton), new PropertyMetadata(null)); #endregion #region Commands public ICommand ButtonCommand { get { return (ICommand)GetValue(ButtonCommandProperty); } set { SetValue(ButtonCommandProperty, value); } } public static readonly DependencyProperty ButtonCommandProperty = DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(ThreePieceButton), new PropertyMetadata(null)); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/ThreePieceComponent.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Components/ThreePieceComponent.xaml.cs ================================================ using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace ClangPowerTools.MVVM.Views.Components { /// /// Interaction logic for ThreePieceComponent.xaml /// public partial class ThreePieceComponent : UserControl { public ThreePieceComponent() { InitializeComponent(); } #region Component public string BackgroundValue { get { return (string)GetValue(BackgroundValueProperty); } set { SetValue(BackgroundValueProperty, value); } } public static readonly DependencyProperty BackgroundValueProperty = DependencyProperty.Register("BackgroundValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string OpacityValue { get { return (string)GetValue(OpacityValueProperty); } set { SetValue(OpacityValueProperty, value); } } public static readonly DependencyProperty OpacityValueProperty = DependencyProperty.Register("OpacityValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string WidthValue { get { return (string)GetValue(WidthValueProperty); } set { SetValue(WidthValueProperty, value); } } public static readonly DependencyProperty WidthValueProperty = DependencyProperty.Register("WidthValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string HeightValue { get { return (string)GetValue(HeightValueProperty); } set { SetValue(HeightValueProperty, value); } } public static readonly DependencyProperty HeightValueProperty = DependencyProperty.Register("HeightValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); #endregion #region ImageComponent public string Image { get { return (string)GetValue(ImageProperty); } set { SetValue(ImageProperty, value); } } public static readonly DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string ImageWidthValue { get { return (string)GetValue(ImageWidthValueProperty); } set { SetValue(ImageWidthValueProperty, value); } } public static readonly DependencyProperty ImageWidthValueProperty = DependencyProperty.Register("ImageWidthValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string ImageHeightValue { get { return (string)GetValue(ImageHeightValueProperty); } set { SetValue(ImageHeightValueProperty, value); } } public static readonly DependencyProperty ImageHeightValueProperty = DependencyProperty.Register("ImageHeightValue", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); #endregion #region TitleComponent public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string TitleFontSize { get { return (string)GetValue(TitleFontSizeProperty); } set { SetValue(TitleFontSizeProperty, value); } } public static readonly DependencyProperty TitleFontSizeProperty = DependencyProperty.Register("TitleFontSize", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string TitleForeground { get { return (string)GetValue(TitleForegroundProperty); } set { SetValue(TitleForegroundProperty, value); } } public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register("TitleForeground", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); #endregion #region DescriptionComponent public string Description { get { return (string)GetValue(DescriptionProperty); } set { SetValue(DescriptionProperty, value); } } public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string DescriptionFontSize { get { return (string)GetValue(DescriptionFontSizeProperty); } set { SetValue(DescriptionFontSizeProperty, value); } } public static readonly DependencyProperty DescriptionFontSizeProperty = DependencyProperty.Register("DescriptionFontSize", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); public string DescriptionForeground { get { return (string)GetValue(DescriptionForegroundProperty); } set { SetValue(DescriptionForegroundProperty, value); } } public static readonly DependencyProperty DescriptionForegroundProperty = DependencyProperty.Register("DescriptionForeground", typeof(string), typeof(ThreePieceComponent), new PropertyMetadata(null)); #endregion #region Commands public ICommand ButtonCommand { get { return (ICommand)GetValue(ButtonCommandProperty); } set { SetValue(ButtonCommandProperty, value); } } public static readonly DependencyProperty ButtonCommandProperty = DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(ThreePieceComponent), new PropertyMetadata(null)); #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/DialogWindow.cs ================================================ namespace ClangPowerTools.MVVM.Views { public class DialogWindow : Microsoft.VisualStudio.PlatformUI.DialogWindow { public DialogWindow() : this(string.Empty) { } public DialogWindow(string helpTopic) : base(helpTopic) { KeyUp += new System.Windows.Input.KeyEventHandler(DialogWindow_KeyUp); } private void DialogWindow_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) { if (e.Key == System.Windows.Input.Key.Escape) { DialogResult = false; Close(); } } protected override void InvokeDialogHelp() { } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/EncodingErrorView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/LoginView.xaml.cs ================================================ using System.Windows; using System.Windows.Controls; namespace ClangPowerTools.MVVM.Views { /// /// Interaction logic for UserControl1.xaml /// public partial class LoginView : Window { #region Members private readonly LoginViewModel loginViewModel; #endregion #region Methods public LoginView() { InitializeComponent(); loginViewModel = new LoginViewModel(this); DataContext = loginViewModel; ApiUtility.InitializeApiClient(); } private void OnPasswordChanged(object sender, RoutedEventArgs e) { PasswordTextBox.Tag = string.IsNullOrWhiteSpace(PasswordTextBox.Password) ? "False" : "True"; if (DataContext != null) { loginViewModel.Password = ((PasswordBox)sender).Password; } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/ReleaseNotesView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/ReleaseNotesView.xaml.cs ================================================ using System.Diagnostics; using System.Windows; namespace ClangPowerTools.MVVM.Views { /// /// Interaction logic for ReleaseNotesView.xaml /// public partial class ReleaseNotesView : Window { public static bool WasShown { get; set; } = true; public ReleaseNotesView(bool wasShown) { WasShown = wasShown; InitializeComponent(); DataContext = new ReleaseNotesViewModel(this); } private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) { Process.Start(new ProcessStartInfo("https://releases.llvm.org/14.0.0/tools/clang/docs/ReleaseNotes.html#windows-support")); e.Handled = true; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/SearchBoxView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/SearchBoxView.xaml.cs ================================================ using System.Windows.Controls; namespace ClangPowerTools.Views { /// /// Interaction logic for SearchBoxView.xaml /// public partial class SearchBoxView : UserControl { #region Cosntructor /// /// Default constructor /// public SearchBoxView() { InitializeComponent(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/SettingsView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/SettingsView.xaml.cs ================================================ using ClangPowerTools.Commands.BackgroundTidy; using ClangPowerTools.MVVM.Views; using System.Windows; namespace ClangPowerTools.Views { /// /// Interaction logic for SettingsView.xaml /// public partial class SettingsView : DialogWindow { public SettingsView(bool showFooter) { var settingsHandler = new SettingsHandler(); settingsHandler.LoadSettings(); InitializeComponent(); DataContext = new SettingsViewModel(this, showFooter); SettingsProvider.SettingsView = this; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/AppResources.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/HyperlinkStyle.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/ImageResources.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/SettingsButtonStyle.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/SettingsComboBoxStyle.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/ToggleStyle.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/Styles/YellowButtonStyle.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TidyChecksView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TidyChecksView.xaml.cs ================================================ using System; using System.Linq; using System.Text; using System.Windows; namespace ClangPowerTools.Views { /// /// Interaction logic for TidyChecksView.xaml /// public partial class TidyChecksView : Window { private readonly TidyChecksViewModel viewModel; public TidyChecksView() { InitializeComponent(); viewModel = new TidyChecksViewModel(this); DataContext = viewModel; Owner = SettingsProvider.SettingsView; } private void ToggleButton_Checked(object sender, RoutedEventArgs e) { viewModel.MultipleStateChange(true); viewModel.DeactivateDefaultsToggle(); } private void ToggleButton_Unchecked(object sender, RoutedEventArgs e) { viewModel.MultipleStateChange(false); viewModel.DeactivateDefaultsToggle(); } private void OpenDescription(object sender, RoutedEventArgs e) { var elementIndex = GetElementIndex(sender as FrameworkElement); var tidyCheckModel = viewModel.TidyChecksList.ElementAt(elementIndex); viewModel.OpenBrowser(tidyCheckModel.Name); } private int GetElementIndex(FrameworkElement frameworkElement) { var element = frameworkElement.DataContext; return TidyChecksListBox.Items.IndexOf(element); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TidySettingsView.xaml ================================================  ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TidyToolWindowView.xaml.cs ================================================ using ClangPowerTools.MVVM.Models; using ClangPowerToolsShared.MVVM.Commands; using ClangPowerToolsShared.MVVM.ViewModels; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace ClangPowerTools.Views { /// /// Interaction logic for CompilerSettingsView.xaml /// public partial class TidyToolWindowView : UserControl { private TidyToolWindowViewModel tidyToolWindowViewModel; public TidyToolWindowView() { tidyToolWindowViewModel = new TidyToolWindowViewModel(this); DataContext = tidyToolWindowViewModel; InitializeComponent(); } public void UpdateView(List filesPath) { tidyToolWindowViewModel.UpdateViewModel(filesPath); } public void OpenTidyToolWindow(List filesPath) { tidyToolWindowViewModel.OpenTidyToolWindow(filesPath); } private void DiffButton(object sender, RoutedEventArgs e) { var elementIndex = sender as FrameworkElement; var element = elementIndex.DataContext as FileModel; if (element != null) { tidyToolWindowViewModel.DiffFile(element); } } private void FixButton(object sender, RoutedEventArgs e) { var elementIndex = sender as FrameworkElement; var element = elementIndex.DataContext as FileModel; if (element != null) { tidyToolWindowViewModel.FixAllFilesAsync(element).SafeFireAndForget(); } } private void CheckAll(object sender, RoutedEventArgs e) { tidyToolWindowViewModel.CheckOrUncheckAll(); } private void CheckBox_Click(object sender, RoutedEventArgs e) { var elementIndex = sender as FrameworkElement; var element = elementIndex.DataContext as FileModel; if (element != null) { tidyToolWindowViewModel.UpdateCheckedNumber(element); } } private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e) { var item = sender as ListViewItem; var file = item.Content as FileModel; if (item != null && item.IsSelected) { FileCommand.TidyFixDiff(file); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/ToolWindows/FindToolWindow.cs ================================================ using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; namespace ClangPowerToolsShared.MVVM.Views.ToolWindows { [Guid(WindowGuidString)] public class FindToolWindow : ToolWindowPane { #region Members public const string WindowGuidString = "b6c99e5a-0649-4973-922a-a1a2a4057aeb"; public const string Title = "Clang Power Tools - Find"; private object findToolWindowView; private Type mObjType; #endregion #region Constructors public FindToolWindow() : base() { Caption = Title; BitmapImageMoniker = KnownMonikers.ImageIcon; var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault( asm => asm.GetName().FullName.Contains("ClangPowerToolsLib")); mObjType = assembly.GetType("ClangPowerTools.Views.FindToolWindowView"); findToolWindowView = Activator.CreateInstance(mObjType); Content = findToolWindowView; } public void OpenFindToolWindow(List filesPath) { MethodInfo method = mObjType.GetMethod("OpenFindToolWindow"); method.Invoke(findToolWindowView, null); } public void RunQuery() { MethodInfo method = mObjType.GetMethod("RunQuery"); method.Invoke(findToolWindowView, null); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/ToolWindows/TidyToolWindow.cs ================================================  using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Shell; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; namespace ClangPowerToolsShared.MVVM.Views.ToolWindows { [Guid(WindowGuidString)] public class TidyToolWindow : ToolWindowPane { #region Members public const string WindowGuidString = "e4e2ba26-a455-4c53-adb3-8225fb696f9b"; public const string Title = "Clang Power Tools - Tidy"; private object tidyToolWindowView; private Type mObjType; #endregion #region Constructors public TidyToolWindow() : base() { Caption = Title; BitmapImageMoniker = KnownMonikers.ImageIcon; var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault( asm => asm.GetName().FullName.Contains("ClangPowerToolsLib")); mObjType = assembly.GetType("ClangPowerTools.Views.TidyToolWindowView"); tidyToolWindowView = Activator.CreateInstance(mObjType); Content = tidyToolWindowView; } #endregion public void UpdateToolWindow(List filesPath) { MethodInfo method = mObjType.GetMethod("UpdateView"); method.Invoke(tidyToolWindowView, new object[] { filesPath }); } public void OpenTidyToolWindow(List filesPath) { MethodInfo method = mObjType.GetMethod("OpenTidyToolWindow"); method.Invoke(tidyToolWindowView, new object[] { filesPath }); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TrialExpiredView.xaml ================================================  Already registered? Sign In ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/Views/TrialExpiredView.xaml.cs ================================================ using System.Windows; namespace ClangPowerTools.MVVM.Views { /// /// Interaction logic for License.xaml /// public partial class TrialExpiredView : Window { public TrialExpiredView() { InitializeComponent(); DataContext = new TrialExpiredViewModel(this); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/WebApi/WebApiUrl.cs ================================================ namespace ClangPowerTools.MVVM.WebApi { public static class WebApiUrl { private static readonly string appId = "5d011c6a375f6b5ed9716629"; private static readonly string url = @"https://account.clangpowertools.com"; public static readonly string loginUrl = string.Concat(url, "/api/", appId, "/user/", "login"); public static readonly string licenseUrl = string.Concat(url, "/api/", appId, "/license"); public static readonly string forgotPasswordUrl = string.Concat(url, "/api/", appId, "/user/", "forgot-password"); public static readonly string signUpUrl = string.Concat(url, "/api/", appId, "/user/", "register"); public static readonly string userProfile = string.Concat(url, "/api/", appId, "/user/", "profile"); public static readonly string settingsConfig = string.Concat(url, "/api/", appId, "/config"); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/MVVM/XmlSerializer.cs ================================================ using System.IO; using NetSerializer = System.Xml.Serialization.XmlSerializer; namespace ClangPowerTools { public class XmlSerializer { private static readonly object mMutex = new object(); public void SerializeToFile(string aFilePath, object obj) { lock (mMutex) { NetSerializer xmlSerializer = new NetSerializer(obj.GetType()); using (FileStream fs = new FileStream(aFilePath, FileMode.Create)) { using (StreamWriter sw = new StreamWriter(fs)) { xmlSerializer.Serialize(sw, obj); } } } } public T DeserializeFromFile(string aFilePath) { lock (mMutex) { NetSerializer serializer = new NetSerializer(typeof(T)); using (FileStream fs = new FileStream(aFilePath, FileMode.Open)) { return (T)serializer.Deserialize(fs); } } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputContentModel.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.Output { public class OutputContentModel { #region Properties public HashSet Errors { get; set; } = new HashSet(); public List Buffer { get; set; } = new List(); public string Text { get; set; } public bool MissingLLVM { get; set; } public bool HasEncodingError { get; set; } public string JsonFilePath { get; set; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputProcessor.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Error; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using static System.Net.Mime.MediaTypeNames; namespace ClangPowerTools.Output { public class OutputProcessor { #region Members private ErrorDetector mErrorDetector = new ErrorDetector(); private readonly int kBufferSize = 5; #endregion #region Methods #region Public methods public int ProcessData(string aMessage, IVsHierarchy aHierarchy, OutputContentModel aOutputContent) { aOutputContent.Buffer.Add(aMessage); var text = String.Join("\n", aOutputContent.Buffer.ToList()) + "\n"; if (mErrorDetector.Detect(text, ErrorParserConstants.kJsonCompilationDbFilePathRegex, out Match matchResult)) { aOutputContent.JsonFilePath = GetJsonFilePath(matchResult); return VSConstants.S_OK; } if (mErrorDetector.HasEncodingError(aMessage)) { aOutputContent.HasEncodingError = true; } if (CommandControllerInstance.CommandController.GetCurrentCommandId() == CommandIds.kClangFindRun && mErrorDetector.Detect(text, ErrorParserConstants.kMatchMessageRegex, out Match aMatchResultt)) { GetOutputAndErrors(text, aHierarchy, out string outputText, out List aDetectedErrors, ErrorParserConstants.kMatchMessageRegex); aOutputContent.Text = outputText; aOutputContent.Errors.UnionWith(aDetectedErrors); aOutputContent.Buffer.Clear(); return VSConstants.S_OK; } else if (CommandControllerInstance.CommandController.GetCurrentCommandId() != CommandIds.kClangFindRun && mErrorDetector.Detect(text, ErrorParserConstants.kErrorMessageRegex, out Match aMatchResult)) { GetOutputAndErrors(text, aHierarchy, out string outputText, out List aDetectedErrors, ErrorParserConstants.kErrorMessageRegex); aOutputContent.Text = outputText; aOutputContent.Errors.UnionWith(aDetectedErrors); aOutputContent.Buffer.Clear(); return VSConstants.S_OK; } else if (kBufferSize <= aOutputContent.Buffer.Count) { aOutputContent.Text = aOutputContent.Buffer[0]; aOutputContent.Buffer.RemoveAt(0); return VSConstants.S_OK; } return VSConstants.S_FALSE; } public bool FindMatchFinishKeyword(string text) { return mErrorDetector.Detect(text, ErrorParserConstants.kNumberMatchesRegex, out Match aMatchResult); ; } #endregion #region Private Methods private void GetOutputAndErrors(string aText, IVsHierarchy aHierarchy, out string aOutputText, out List aDetectedErrors, string parser) { var aOutputBuilder = new StringBuilder(); aDetectedErrors = new List(); while (mErrorDetector.Detect(aText, parser, out Match aMatchResult)) { var detectedError = GetDetectedError(aHierarchy, aMatchResult); if (detectedError != null) aDetectedErrors.Add(detectedError); aOutputBuilder.Append(GetOutput(ref aText, aDetectedErrors.Count == 0 ? "" : aDetectedErrors.Last().FullMessage)); } aOutputText = aOutputBuilder.ToString(); } private TaskErrorModel GetDetectedError(IVsHierarchy aHierarchy, Match aMarchResult) { IBuilder errorBuilder = new TaskErrorModelBuilder(aHierarchy, aMarchResult); errorBuilder.Build(); return errorBuilder.GetResult(); } private string GetOutput(ref string aText, string aSearchedSubstring) { var errorFormatter = new ErrorFormatter(); aText = errorFormatter.Format(aText, aSearchedSubstring); var substringBefore = aText.SubstringBefore(aSearchedSubstring); var substringAfter = aText.SubstringAfter(aSearchedSubstring); aText = substringAfter; return substringBefore + aSearchedSubstring; } private string GetJsonFilePath(Match match) => match.Groups[1].Value; #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputWindowBuilder.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Services; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; namespace ClangPowerTools.Output { public class OutputWindowBuilder : IBuilder { #region Private Members /// /// Output window model instance /// private OutputWindowModel mOutputWindowModel = new OutputWindowModel(); /// /// Output window model instance /// private AsyncPackage mAsyncPackage; #endregion #region Constructor /// /// Instance constructor /// /// public OutputWindowBuilder(AsyncPackage aPackage, IVsOutputWindow aVsOutputWindow) { mOutputWindowModel.VsOutputWindow = aVsOutputWindow; mAsyncPackage = aPackage; } #endregion #region IAsyncBuilder Implementation public void Build() { // Get the VS Output Window if (null == mOutputWindowModel.VsOutputWindow) { if (VsServiceProvider.TryGetService(typeof(SVsOutputWindow), out object vsOutputWindow)) mOutputWindowModel.VsOutputWindow = vsOutputWindow as IVsOutputWindow; } if (null == mOutputWindowModel.Pane) { // Get the Pane object Guid generalPaneGuid = mOutputWindowModel.PaneGuid; mOutputWindowModel.VsOutputWindow.GetPane(ref generalPaneGuid, out IVsOutputWindowPane pane); // If pane does not exists, create it if (null == pane) { mOutputWindowModel.VsOutputWindow.CreatePane(ref generalPaneGuid, OutputWindowConstants.paneName, 0, 1); mOutputWindowModel.VsOutputWindow.GetPane(ref generalPaneGuid, out pane); } mOutputWindowModel.Pane = pane; } } public OutputWindowModel GetResult() => mOutputWindowModel; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputWindowConstants.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public static class OutputWindowConstants { #region Constants public const string paneName = "Clang Power Tools"; public const string start = "Start"; public const string done = "Done"; public static readonly Dictionary commandName = new Dictionary { {CommandIds.kFindViewMenuId, "Clang Power Tools opens Find Tool Window"}, {CommandIds.kCompileId, "Clang Compile"}, {CommandIds.kCompileToolbarId, "Clang Compile"}, {CommandIds.kTidyId, "Clang Tidy"}, {CommandIds.kOptimizeIncludesId, "Clang Optimize Includes"}, {CommandIds.kTidyToolWindowId, "Clang Tidy"}, {CommandIds.kTidyToolbarId, "Clang Tidy"}, {CommandIds.kTidyFixId, "Clang Tidy-Fix"}, {CommandIds.kTidyFixToolbarId, "Clang Tidy-Fix"}, {CommandIds.kDocumentationHtmlId, "Clang Generate Documentation Html"}, {CommandIds.kDocumentationYamlId, "Clang Generate Documentation Yaml"}, {CommandIds.kDocumentationMdId, "Clang Generate Documentation Md"}, {CommandIds.kClangFormat, "Clang Format"}, {CommandIds.kClangFind, "Clang Power Tools opens Find Tool Window"}, {CommandIds.kClangFindRun, "Clang Find"}, {CommandIds.kClangFormatToolbarId, "Clang Format"}, {CommandIds.kJsonCompilationDatabase, "JSON Compilation Database"} }; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputWindowController.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Commands; using ClangPowerTools.Error; using ClangPowerTools.Events; using ClangPowerTools.Handlers; using ClangPowerTools.Helpers; using ClangPowerTools.Services; using ClangPowerToolsShared.Commands; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; namespace ClangPowerTools.Output { public class OutputWindowController { #region Members private readonly OutputProcessor outputProcessor = new OutputProcessor(); private IBuilder outputWindowBuilder; private OutputContentModel outputContent = new OutputContentModel(); public event EventHandler ErrorDetectedEvent; public event EventHandler CloseDataConnectionEvent; public event EventHandler HasEncodingErrorEvent; public event EventHandler JsonCompilationDbFilePathEvent; #endregion #region Properties private static Mutex mutex = new Mutex(); public List Buffer => outputContent.Buffer; public bool IsBufferEmpty => 0 == outputContent.Buffer.Count; public HashSet Errors => outputContent.Errors; public bool HasErrors => 0 != outputContent.Errors.Count; private IVsHierarchy Hierarchy { get; set; } private int machesNr = 0; private HashSet paths; private List tempPaths; #endregion public OutputWindowController() { paths = new HashSet(); tempPaths = new List(); } #region Methods #region Output window operations private Package package; public void Initialize(AsyncPackage aPackage, IVsOutputWindow aVsOutputWindow) { if (null == outputWindowBuilder) outputWindowBuilder = new OutputWindowBuilder(aPackage, aVsOutputWindow); outputWindowBuilder.Build(); package = aPackage; } public void ClearPanel(object sender, ClearEventArgs e) => Clear(); public void Clear() { outputContent = new OutputContentModel(); var outputWindow = outputWindowBuilder.GetResult(); UIUpdater.InvokeAsync(() => { outputWindow.Pane.Clear(); }).SafeFireAndForget(); } public void Show() { if (!SettingsProvider.CompilerSettingsModel.ShowOutputWindow) return; var outputWindow = outputWindowBuilder.GetResult(); UIUpdater.InvokeAsync(() => { outputWindow.Pane.Activate(); if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) { (dte as DTE2).ExecuteCommand("View.Output", string.Empty); } VsWindowController.Activate(VsWindowController.PreviousWindow); }).SafeFireAndForget(); } public void Write(string aMessage) { if (string.IsNullOrWhiteSpace(aMessage)) return; mutex.WaitOne(); var outputWindow = outputWindowBuilder.GetResult(); outputWindow.Pane.OutputStringThreadSafe(aMessage + "\n"); mutex.ReleaseMutex(); } public void Write(object sender, ClangCommandMessageEventArgs e) { if (e.ClearFlag) { Clear(); } Show(); Write(e.Message); } protected virtual void OnFileHierarchyChanged(object sender, VsHierarchyDetectedEventArgs e) { if (null == e.Hierarchy) return; Hierarchy = e.Hierarchy; } #endregion #region Data Handlers public void GetFilesFromOutput(string output) { if (output == null) return; Regex regex = new Regex(ErrorParserConstants.kMatchTidyFileRegex); Match match = regex.Match(output); while (match.Success) { paths.Add(match.Groups[1].Value.Trim()); match = match.NextMatch(); } } public void OutputDataReceived(object sender, DataReceivedEventArgs e) { var id = CommandControllerInstance.CommandController.GetCurrentCommandId(); if (null == e.Data) return; if (id == CommandIds.kTidyId || id == CommandIds.kTidyToolbarId || id == CommandIds.kTidyToolWindowId || id == CommandIds.kTidyFixId || id == CommandIds.kTidyFixToolbarId) { GetFilesFromOutput(e.Data.ToString()); } mutex.WaitOne(); var result = outputProcessor.ProcessData(e.Data, Hierarchy, outputContent); mutex.ReleaseMutex(); if (VSConstants.S_FALSE == result && !(id == CommandIds.kClangFindRun || id == CommandIds.kClangFind)) return; if (!string.IsNullOrWhiteSpace(outputContent.JsonFilePath)) JsonCompilationDbFilePathEvent?.Invoke(this, new JsonFilePathArgs(outputContent.JsonFilePath)); //invoke show error event when match keyword was found, //this will be applied on clang-query interactive mode (active document) if ((id == CommandIds.kClangFindRun || id == CommandIds.kClangFind) && (LookInMenuController.GetSelectedMenuItem().LookInMenu == LookInMenu.CurrentActiveDocument) && outputProcessor.FindMatchFinishKeyword(e.Data)) { CloseDataConnectionEvent?.Invoke(this, new CloseDataConnectionEventArgs()); OnErrorDetected(this, e); } // 1 - verbose if (SettingsProvider.CompilerSettingsModel.VerbosityLevel != "1" && (id == CommandIds.kClangFindRun || id == CommandIds.kClangFind)) return; //show full text when find command is running //otherwise show just matched text if (id == CommandIds.kClangFindRun || id == CommandIds.kClangFind) Write(e.Data); else Write(outputContent.Text); } public void OutputDataErrorReceived(object sender, DataReceivedEventArgs e) { if (null == e.Data) return; mutex.WaitOne(); var result = outputProcessor.ProcessData(e.Data, Hierarchy, outputContent); mutex.ReleaseMutex(); var id = CommandControllerInstance.CommandController.GetCurrentCommandId(); if (VSConstants.S_FALSE == result && !(id == CommandIds.kClangFindRun || id == CommandIds.kClangFind)) return; if (!string.IsNullOrWhiteSpace(outputContent.JsonFilePath)) JsonCompilationDbFilePathEvent?.Invoke(this, new JsonFilePathArgs(outputContent.JsonFilePath)); // 1 - verbose if (SettingsProvider.CompilerSettingsModel.VerbosityLevel != "1" && (id == CommandIds.kClangFindRun || id == CommandIds.kClangFind)) return; Write(outputContent.Text); } public void ClosedDataConnection(object sender, EventArgs e) { mutex.WaitOne(); string outputResult = String.Empty; var id = CommandControllerInstance.CommandController.GetCurrentCommandId(); tempPaths.Clear(); outputResult = String.Join("\n", Buffer); if(!(id == CommandIds.kClangFindRun || id == CommandIds.kClangFind)) Write(outputResult); if (Buffer.Count != 0) { if (id == CommandIds.kClangFindRun) { Regex regex = new Regex(ErrorParserConstants.kNumberMatchesRegex); var matchResult = regex.Match(outputResult); if (matchResult != null && matchResult.Groups[0] != null && matchResult.Groups[0].Value != null && matchResult.Groups[0].Value.ToString() != string.Empty) { machesNr += Int32.Parse(matchResult.Groups[1].Value); } } } CloseDataConnectionEvent?.Invoke(this, new CloseDataConnectionEventArgs()); OnErrorDetected(this, e); //open tidy tool window and pass paths var tidySettings = SettingsProvider.TidySettingsModel; if (id == CommandIds.kTidyToolWindowId || (id == CommandIds.kTidyFixId && !tidySettings.ApplyTidyFix)) { foreach (var path in paths) { tempPaths.Add(path); } CommandControllerInstance.CommandController.LaunchCommandAsync (CommandIds.kTidyToolWindowFilesId, CommandUILocation.ContextMenu, tempPaths); paths.Clear(); } mutex.ReleaseMutex(); } public void OnFileHierarchyDetected(object sender, VsHierarchyDetectedEventArgs e) { Hierarchy = e.Hierarchy; } #endregion public void OnErrorDetected(object sender, EventArgs e) { mutex.WaitOne(); if (Errors.Count > 0) { TaskErrorViewModel.Errors = Errors.ToList(); TaskErrorViewModel.FileErrorsPair = new Dictionary>(); foreach (var error in TaskErrorViewModel.Errors) { if (TaskErrorViewModel.FileErrorsPair.ContainsKey(error.Document)) { TaskErrorViewModel.FileErrorsPair[error.Document].Add(error); } else { TaskErrorViewModel.FileErrorsPair.Add(error.Document, new List() { error }); } } ErrorDetectedEvent?.Invoke(this, new ErrorDetectedEventArgs(Errors)); } mutex.ReleaseMutex(); } public void WriteMatchesNr() { Write($"🔎 We found {machesNr.ToString()} matches"); } public void ResetMatchesNr() { machesNr = 0; } public void OnEncodingErrorDetected(object sender, EventArgs e) { HasEncodingErrorEvent?.Invoke(this, new HasEncodingErrorEventArgs(outputContent)); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Output/OutputWindowModel.cs ================================================ using Microsoft.VisualStudio.Shell.Interop; using System; namespace ClangPowerTools.Output { /// /// Contains all the necessary VS Output Window elements /// public class OutputWindowModel { /// /// Output window instance /// public IVsOutputWindow VsOutputWindow { get; set; } /// /// The output window pane to display messages /// public IVsOutputWindowPane Pane { get; set; } /// /// Standard guid for the output window pane /// public Guid PaneGuid { get; } = new Guid("AB9F45E4-2001-4197-BAF5-4B165222AF29"); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Resources/LICENSE.txt ================================================ ============================================================================== Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/ClangTidyModeParametersFactory.cs ================================================ namespace ClangPowerTools.Script { public class ClangTidyModeParametersFactory { #region Methods #region Public Methods /// /// Create the clang tidy parameters depending on the tidy mode /// /// The searched tidy mode /// Will be set to True if the clang tidy config file will be used. Will be set to False otherwise /// Clang tidy parameters public string Create(string aTidyMode, ref bool aUseClangTidyFileFlag) { if (0 == string.Compare(ComboBoxConstants.kTidyFile, aTidyMode)) return UseClangConfigFile(ref aUseClangTidyFileFlag); else if (0 == string.Compare(ComboBoxConstants.kCustomChecks, aTidyMode)) return GetChecks(); return string.Empty; } #endregion #region Private Methods /// /// Get the use clang config file tag /// /// The use clang config file tag private string UseClangConfigFile(ref bool aUseClangTidyFileFlag) { aUseClangTidyFileFlag = true; return ScriptConstants.kTidyFile; } /// /// Get the clang tidy parameters from the Custom Checks option page /// /// private string GetChecks() { string tidyChecks = SettingsProvider.TidySettingsModel.PredefinedChecks; return !string.IsNullOrWhiteSpace(tidyChecks) ? $",{tidyChecks.Replace(';', ',')}" : string.Empty; } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/GenericScriptBuilder.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Convertors; using ClangPowerTools.Services; using EnvDTE80; using System; using System.IO; using System.Linq; using System.Text; namespace ClangPowerTools.Script { /// /// Contains all the script creation logic and parameters checking for the generic parameters components(environment and settings) /// The result will be a string which represents the way how the power shell script will be called /// public class GenericScriptBuilder : IBuilder { #region Members /// /// The final result after the build method /// private string mScript = string.Empty; private string mVsEdition; private string mVsVersion; private int mCommandId; private bool jsonCompilationDbActive; #endregion #region Constructor /// /// Instance constructor /// public GenericScriptBuilder(string aVsEdition, string aVsVersion, int aCommandId, bool jsonCompilation = false) { mVsEdition = aVsEdition; mVsVersion = aVsVersion; mCommandId = aCommandId; jsonCompilationDbActive = jsonCompilation; } #endregion #region Methods #region Public Methods #region IBuilder Implementation /// /// Create the generic script by gathering all the generic parameters from the environment and settings components /// public void Build() { // Append the General parameters and Tidy parameters from option pages mScript = $"{GetGeneralParameters()} {(CommandIds.kTidyId == mCommandId || CommandIds.kTidyFixId == mCommandId ? GetTidyParameters() : ScriptConstants.kParallel)}"; var formatSettings = SettingsProvider.FormatSettingsModel; var tidySettings = SettingsProvider.TidySettingsModel; // Append the clang-format style if (null != formatSettings && null != tidySettings && CommandIds.kTidyFixId == mCommandId && tidySettings.FormatAfterTidy) mScript += $" {ScriptConstants.kClangFormatStyle} {formatSettings.Style}"; // Append the Visual Studio Version and Edition mScript += $" {ScriptConstants.kVsVersion} {mVsVersion}"; // Append the solution path if (VsServiceProvider.TryGetService(typeof(DTE2), out object dte)) mScript += $" {ScriptConstants.kDirectory} '{(dte as DTE2).Solution.FullName}' "; } /// /// Get the script after the build process /// /// The script which will contain the generic parameters public string GetResult() => mScript; #endregion #endregion #region Private Methods /// /// Get the parameters from the General option page /// /// /// The parameters from General option page private string GetGeneralParameters() { var compilerSettings = SettingsProvider.CompilerSettingsModel; var parameters = new StringBuilder(); // Get the Clang Flags list if (!string.IsNullOrWhiteSpace(compilerSettings.CompileFlags)) parameters.Append(GetClangFlagsOption()); // Get the continue when errors are detected flag if (compilerSettings.ContinueOnError) parameters.Append($" {ScriptConstants.kContinue}"); // Get the verbose level flags VerbosityScriptBuilder verbosityScriptBuilder = new VerbosityScriptBuilder(compilerSettings.VerbosityLevel); verbosityScriptBuilder.Build(); parameters.Append(verbosityScriptBuilder.GetResult()); // Get the projects to ignore list if (!string.IsNullOrWhiteSpace(compilerSettings.ProjectsToIgnore)) parameters.Append($" {ScriptConstants.kProjectsToIgnore} ('{TransformInPowerShellArray(compilerSettings.ProjectsToIgnore)}')"); // Get the files to ignore list if (!string.IsNullOrWhiteSpace(compilerSettings.FilesToIgnore)) parameters.Append($" {ScriptConstants.kFilesToIgnore} ('{TransformInPowerShellArray(compilerSettings.FilesToIgnore)}')"); // Get the selected Additional Includes type if (0 == string.Compare(ClangGeneralAdditionalIncludesConvertor.ToString(compilerSettings.AdditionalIncludes), ComboBoxConstants.kSystemIncludeDirectories)) parameters.Append($" {ScriptConstants.kSystemIncludeDirectories}"); if (jsonCompilationDbActive) parameters.Append($" {ScriptConstants.kJsonCompilationDb}"); return parameters.ToString(); } /// /// Get the clang flags in the power shell script format /// /// The clang flags private string GetClangFlagsOption() { var compilerSettings = SettingsProvider.CompilerSettingsModel; return string.Format("{0} {1}", ScriptConstants.kClangFlags, compilerSettings.WarningsAsErrors ? $" ('{ScriptConstants.kTreatWarningsAsErrors}','{TransformInPowerShellArray(compilerSettings.CompileFlags)}')" : $" ('{TransformInPowerShellArray(compilerSettings.CompileFlags)}')"); } /// /// Transform the UI parameters list in an power shell array /// /// The list of UI parameters /// The power shell array containing the UI parameters private string TransformInPowerShellArray(string aParametersList) => string.Join("','", aParametersList.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); /// /// Get the parameters from the Tidy related option page /// /// private string GetTidyParameters() { var tidySettings = SettingsProvider.TidySettingsModel; // Get the clang tidy parameters depending on the tidy mode var parameters = GetTidyChecks(tidySettings); // Append the clang tidy type(tidy / tidy-fix) with / without clang tidy config file option attached if (!string.IsNullOrWhiteSpace(parameters)) { if (tidySettings.UseChecksFrom != ClangTidyUseChecksFrom.TidyFile) { if (parameters.Count() == 3) parameters = parameters.Remove(2, 1); var filePath = Path.Combine(Path.GetTempPath(), ".clang-tidy"); var text = $"Checks: '{parameters}'"; using FileStream fs = new FileStream(filePath, FileMode.Create); using StreamWriter sw = new StreamWriter(fs); sw.Write(text); parameters = AppendClangTidyTypeOption(filePath); } else { parameters = AppendClangTidyTypeOption(parameters); } } // Get the header filter option if (!string.IsNullOrWhiteSpace(tidySettings.HeaderFilter)) parameters += $" {GetHeaderFiltersOption()}"; // Get the compilation database option if (!string.IsNullOrWhiteSpace(tidySettings.CompilationDatabase)) parameters += $" {GetCompilationDatabaseOption(tidySettings.CompilationDatabase)}"; parameters += $" {ScriptConstants.kParallel}"; return parameters; } /// /// Append the clang tidy type(tidy / tidy-fix) with/ without tidy config file option attached /// /// /// The <"aParameters"> value with the clang tidy type with / without the clang tidy config file option attached private string AppendClangTidyTypeOption(string aParameters) { return string.Format("{0} '{1}'", (CommandIds.kTidyFixId == mCommandId ? ScriptConstants.kTidyFix : ScriptConstants.kTidy), aParameters); } /// /// Get the header filter option from the Clang Tidy Option page /// /// Header filter option private string GetHeaderFiltersOption() { var tidySettings = SettingsProvider.TidySettingsModel; return string.Format("{0} '{1}'", ScriptConstants.kHeaderFilter, string.IsNullOrWhiteSpace(ClangTidyHeaderFiltersConvertor.ScriptEncode(tidySettings.HeaderFilter)) ? tidySettings.HeaderFilter : ClangTidyHeaderFiltersConvertor.ScriptEncode(tidySettings.HeaderFilter)); } private string GetTidyChecks(TidySettingsModel tidyModel) { ClangTidyUseChecksFrom useChecksFrom = tidyModel.UseChecksFrom; if (useChecksFrom == ClangTidyUseChecksFrom.CustomChecks) { return ScriptConstants.kTidyCheckFirstElement + tidyModel.CustomChecks.Replace(';', ',').TrimEnd(','); } else if (useChecksFrom == ClangTidyUseChecksFrom.PredefinedChecks) { return ScriptConstants.kTidyCheckFirstElement + tidyModel.PredefinedChecks.Replace(';', ',').TrimEnd(','); } else { return ScriptConstants.kTidyFile; } } /// /// Get the compilation database file option from the Clang Tidy Option page /// /// Compilation database file option private string GetCompilationDatabaseOption(string compilationDatabase) { DirectoryInfo dbPath = new DirectoryInfo(compilationDatabase); return string.Format("{0} '{1}'", ScriptConstants.kCompilationDatabaseDir, dbPath.Parent.FullName); } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/ItemRelatedScriptBuilder.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Helpers; using EnvDTE; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools.Script { public class ItemRelatedScriptBuilder : IBuilder { #region Members /// /// The resulted script after the build method /// private string mScript = string.Empty; /// /// The current item for which the script will be build /// private readonly IItem mItem; private readonly List items; private readonly bool jsonCompilationDbActive; #endregion #region Constructor /// /// Instance constructor /// /// The current item for which the script will be build /// The path of the VS solution public ItemRelatedScriptBuilder(IItem aItem) => mItem = aItem; public ItemRelatedScriptBuilder(IItem aItem, bool jsonCompilationDb) : this(aItem) { jsonCompilationDbActive = jsonCompilationDb; } public ItemRelatedScriptBuilder(List itemsCollection, bool jsonCompilationDb) { items = itemsCollection; jsonCompilationDbActive = jsonCompilationDb; } #endregion #region Methods #region IBuilder Implementation /// /// Get the item related script component /// /// Item related script component public string GetResult() => mScript; /// /// Create the script by gathering all the item related parameters from the environment and settings components /// CAKE /// public void Build() { if (SolutionInfo.OpenFolderModeActive) { CreateScriptForOpenFolderProjectItem(); } else { // Create script for single file / project if (mItem != null) { CreateScriptForSingleFile(); } else if (items != null && items.Count > 0) { CreateScriptForFilesCollection(); } } } private void CreateScriptForSingleFile() { if (mItem is CurrentProjectItem) { CreateScriptForProjectItem(); } else if (mItem is CurrentProject) { CreateScriptForProject(); } } private void CreateScriptForFilesCollection() { if (items[0] is CurrentProjectItem) { CreateScriptForProjectItemCollection(); } else if (items[0] is CurrentProject) { CreateScriptForProject(); } } private void CreateScriptForOpenFolderProjectItem() { var document = DocumentHandler.GetActiveDocument(); mScript = $"{mScript} " + $"{ScriptConstants.kFile} '{document.FullName}' "; } private void CreateScriptForProjectItem() { ProjectItem projectItem = mItem.GetObject() as ProjectItem; string containingProject = projectItem.ContainingProject.FullName; var filePath = projectItem.Properties.Item("FullPath").Value; var configuration = ProjectConfigurationHandler.GetConfiguration(projectItem.ContainingProject); var platform = ProjectConfigurationHandler.GetPlatform(projectItem.ContainingProject); var projectData = jsonCompilationDbActive ? string.Empty : $"{ScriptConstants.kProject} '{containingProject}' "; mScript = $"{mScript} {projectData}" + $"{ScriptConstants.kFile} '{filePath}' {ScriptConstants.kActiveConfiguration} " + $"'{configuration}|{platform}'"; } private void CreateScriptForProjectItemCollection() { ProjectItem projectItem = items[0].GetObject() as ProjectItem; string containingProject = projectItem.ContainingProject.FullName; var filesPath = string.Join("','", items.Select(projItem => ((ProjectItem)projItem.GetObject()).Properties.Item("FullPath").Value)); var configuration = ProjectConfigurationHandler.GetConfiguration(projectItem.ContainingProject); var platform = ProjectConfigurationHandler.GetPlatform(projectItem.ContainingProject); var projectData = jsonCompilationDbActive ? string.Empty : $"{ScriptConstants.kProject} '{containingProject}' "; mScript = $"{mScript} {projectData}" + $"{ScriptConstants.kFile} ('{filesPath}') {ScriptConstants.kActiveConfiguration} " + $"'{configuration}|{platform}'"; } private void CreateScriptForProject() { Project project = mItem.GetObject() as Project; mScript = $"{mScript} {ScriptConstants.kProject} '{project.FullName}' {ScriptConstants.kActiveConfiguration} " + $"'{ProjectConfigurationHandler.GetConfiguration(project)}|{ProjectConfigurationHandler.GetPlatform(project)}'"; } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/PowerShellWrapper.cs ================================================ using ClangPowerTools.Output; using ClangPowerToolsShared.Commands; using ClangPowerToolsShared.MVVM.Constants; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Process = System.Diagnostics.Process; namespace ClangPowerTools { public static class PowerShellWrapper { #region Properties public static DataReceivedEventHandler DataErrorHandler { get; set; } public static DataReceivedEventHandler DataHandler { get; set; } public static EventHandler ExitedHandler { get; set; } public static OutputWindowController mOutputWindowController; public static string InteractivCommands { get; set; } = string.Empty; private static bool mInteractiveMode = false; private static Process mInteractiveProcess; #endregion #region Public Methods public static bool StartProcess(string aScript, string aExecutablePath = "", bool aRunAsPwsh = false) { Process process = new Process(); try { process.StartInfo = new ProcessStartInfo() { FileName = aExecutablePath, RedirectStandardError = true, RedirectStandardOutput = true, CreateNoWindow = true, UseShellExecute = false, /* When we are dealing with file paths that contain single quotes, we are running into trouble because whey are messing up our script invocation text. The situation is further complicated by the fact that this invocation is imbricated (invoke inside invoke). Explanation: we are invoking powershell.exe and telling it using -command what to invoke itself, which would be our very own clang-buils.ps1 script. All this script invocation command is enveloped in single quotes. One, quick to mind solution would be to use double quotes. However, this is not practical because it would lead to further issues down the road since those strings are interpolated (and the $ sign is valid in a Windows file path). We have to keep using single quotes, but make sure that we double escape them when we find them. IMPORTANT: there are single quotes which we should not escape. In order to precisely match the quotes that we need, we are exploiting the following detail: file paths containing single quotes will never have spaces to the left or right of them, but the ones we are not interested in will have space either to the left or the right. */ Arguments = Regex.Replace(aScript, @"([\w|\\])'([\w|\\])", "$1''$2") }; //Update process.StartInfo.Filename (exe to run) with aExecutablePath depending on //running platform, pwsh or windows powershell. //For pwsh need to add "-Command" when running a command (all this for cpt Alias command) if (string.IsNullOrEmpty(aExecutablePath)) { process.StartInfo.FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}"; //Update arguments and FileName path for Cpt alias added from pwsh if (SettingsProvider.CompilerSettingsModel.Powershell7) { process.StartInfo.FileName = File.Exists(GetFilePathFromEnviromentVar(ScriptConstants.kPwsh)) ? GetFilePathFromEnviromentVar(ScriptConstants.kPwsh) : $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}"; if (aRunAsPwsh) { process.StartInfo.Arguments = "-Command \"" + process.StartInfo.Arguments + "\""; } } } //download include what you use tool and add to PATH string iwyuTool = string.Empty; if (CommandControllerInstance.CommandController.GetCurrentCommandId() == CommandIds.kOptimizeIncludesId) { iwyuTool = DownloadTool(ScriptConstants.kIwyu) + "\\"; } process.StartInfo.EnvironmentVariables["Path"] = CreatePathEnvironmentVariable(iwyuTool); process.StartInfo.EnvironmentVariables["CPT_CPULIMIT"] = GetNumberOfProcessors().ToString(); var customTidyExecutable = GetCustomTidyPath(); if (string.IsNullOrWhiteSpace(customTidyExecutable) == false) process.StartInfo.EnvironmentVariables[ScriptConstants.kEnvrionmentTidyPath] = customTidyExecutable; process.EnableRaisingEvents = true; process.ErrorDataReceived += DataErrorHandler; process.OutputDataReceived += DataHandler; process.Exited += ExitedHandler; process.Disposed += ExitedHandler; RunController.runningProcesses.Add(process); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); } catch (Exception e) { process.EnableRaisingEvents = false; process.ErrorDataReceived -= DataErrorHandler; process.OutputDataReceived -= DataHandler; process.Exited -= ExitedHandler; process.Disposed -= ExitedHandler; process.Close(); throw e; } finally { RunController.runningProcesses.Remove(process); } return true; } public static bool Invoke(string aScript, bool aRunAsPwsh = false) { if (SettingsProvider.CompilerSettingsModel.Powershell7 && string.IsNullOrEmpty(GetFilePathFromEnviromentVar(ScriptConstants.kPwsh))) { SettingsHandler settingsHandler = new SettingsHandler(); SettingsProvider.CompilerSettingsModel.Powershell7 = false; settingsHandler.SaveSettings(); mOutputWindowController.Write("Can't find PowerShell 7 in PATH"); return false; } return StartProcess(aScript, aRunAsPwsh: aRunAsPwsh); } public static void EndInteractiveMode() { if (mInteractiveProcess == null) return; RunController.runningProcesses.Kill(mInteractiveProcess); { mOutputWindowController.Write("❎ Interactive mode deactivated on document"); } if (mInteractiveProcess.HasExited || mInteractiveProcess.Responding == false) mInteractiveProcess = null; mInteractiveMode = false; } public static void InvokeInteractiveMode(KeyValuePair aKeyValuePair) { if (SettingsProvider.CompilerSettingsModel.Powershell7 && string.IsNullOrEmpty(GetFilePathFromEnviromentVar(ScriptConstants.kPwsh))) { mOutputWindowController.Write("Can't find PowerShell 7 in PATH"); SettingsHandler settingsHandler = new SettingsHandler(); SettingsProvider.CompilerSettingsModel.Powershell7 = false; settingsHandler.SaveSettings(); return; } mOutputWindowController.Write("✅ Interactive mode activated on document: " + aKeyValuePair.Key); if (mInteractiveProcess == null) mInteractiveProcess = new Process(); if (mInteractiveMode) { mInteractiveProcess.StandardInput.WriteLine(InteractivCommands); } else try { if (RunController.StopCommandActivated) { return; } mInteractiveProcess.StartInfo = new ProcessStartInfo() { FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}", RedirectStandardError = true, RedirectStandardOutput = true, RedirectStandardInput = true, CreateNoWindow = true, UseShellExecute = false, Arguments = Regex.Replace(aKeyValuePair.Value, @"([\w|\\])'([\w|\\])", "$1''$2") }; mInteractiveProcess.StartInfo.EnvironmentVariables["Path"] = CreatePathEnvironmentVariable(); mInteractiveProcess.StartInfo.EnvironmentVariables["CPT_CPULIMIT"] = GetNumberOfProcessors().ToString(); var customTidyExecutable = GetCustomTidyPath(); if (string.IsNullOrWhiteSpace(customTidyExecutable) == false) mInteractiveProcess.StartInfo.EnvironmentVariables[ScriptConstants.kEnvrionmentTidyPath] = customTidyExecutable; mInteractiveProcess.EnableRaisingEvents = true; mInteractiveProcess.ErrorDataReceived += DataErrorHandler; mInteractiveProcess.OutputDataReceived += DataHandler; mInteractiveProcess.Exited += ExitedHandler; mInteractiveProcess.Disposed += ExitedHandler; mInteractiveProcess.Start(); mInteractiveProcess.BeginErrorReadLine(); mInteractiveProcess.BeginOutputReadLine(); mInteractiveProcess.StandardInput.WriteLine(MatchConstants.SetOutpuDump); mInteractiveProcess.StandardInput.WriteLine(InteractivCommands); mInteractiveMode = true; } catch (Exception e) { mInteractiveProcess.EnableRaisingEvents = false; mInteractiveProcess.ErrorDataReceived -= DataErrorHandler; mInteractiveProcess.OutputDataReceived -= DataHandler; mInteractiveProcess.Exited -= ExitedHandler; mInteractiveProcess.Disposed -= ExitedHandler; mInteractiveProcess.Close(); throw e; } } public static void InvokePassSequentialCommands(Dictionary aPathCommandPair) { if (SettingsProvider.CompilerSettingsModel.Powershell7 && string.IsNullOrEmpty(GetFilePathFromEnviromentVar(ScriptConstants.kPwsh))) { mOutputWindowController.Write("Can't find PowerShell 7 in PATH"); SettingsHandler settingsHandler = new SettingsHandler(); SettingsProvider.CompilerSettingsModel.Powershell7 = false; settingsHandler.SaveSettings(); return; } var id = CommandControllerInstance.CommandController.GetCurrentCommandId(); int count = 0; mOutputWindowController.Write("Will process " + aPathCommandPair.Count + " files"); mOutputWindowController.ResetMatchesNr(); List tasks = new List(); Parallel.ForEach(aPathCommandPair, pathCommand => { Process process = new Process(); try { if (RunController.StopCommandActivated) { return; } process.StartInfo = new ProcessStartInfo() { FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}", RedirectStandardError = true, RedirectStandardOutput = true, RedirectStandardInput = true, CreateNoWindow = true, UseShellExecute = false, Arguments = Regex.Replace(pathCommand.Value, @"([\w|\\])'([\w|\\])", "$1''$2") }; process.StartInfo.EnvironmentVariables["Path"] = CreatePathEnvironmentVariable(); process.StartInfo.EnvironmentVariables["CPT_CPULIMIT"] = GetNumberOfProcessors().ToString(); var customTidyExecutable = GetCustomTidyPath(); if (string.IsNullOrWhiteSpace(customTidyExecutable) == false) process.StartInfo.EnvironmentVariables[ScriptConstants.kEnvrionmentTidyPath] = customTidyExecutable; process.EnableRaisingEvents = true; process.ErrorDataReceived += DataErrorHandler; process.OutputDataReceived += DataHandler; process.Exited += ExitedHandler; process.Disposed += ExitedHandler; Interlocked.Increment(ref count); mOutputWindowController.Write($"{count}: {pathCommand.Key}"); //Display pathCommand value, if is in verbose mode // 1 - verbose if (int.Parse(SettingsProvider.CompilerSettingsModel.VerbosityLevel) <= 1) { mOutputWindowController.Write($"{count}: {pathCommand.Value}"); } RunController.runningProcesses.Add(process); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); process.WaitForExit(); } catch (Exception e) { process.EnableRaisingEvents = false; process.ErrorDataReceived -= DataErrorHandler; process.OutputDataReceived -= DataHandler; process.Exited -= ExitedHandler; process.Disposed -= ExitedHandler; process.Close(); throw e; } }); mOutputWindowController.WriteMatchesNr(); } /// /// Get the number of processors that a process will run on /// depend on environment var, NUMBER_OF_PROCESSORS and /// percentage of CPU Limit choosed by user /// /// public static int GetNumberOfProcessors() { int processorsNumber = int.Parse(Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS")); int cpuLimit = SettingsProvider.CompilerSettingsModel.CpuLimit; return (cpuLimit * processorsNumber) / 100; } public static string CreatePathEnvironmentVariable(string aEnvPath = "") { var path = Environment.GetEnvironmentVariable("Path"); var llvmModel = SettingsProvider.LlvmSettingsModel; if (string.IsNullOrEmpty(llvmModel.LlvmSelectedVersion)) return path; var llvmVersions = llvmModel.LlvmSelectedVersion.Split('.'); // for parallel execution llvm need to be >= 13.0.1 if ((Int16.Parse(llvmVersions[0]) >= 13)) { if ((Int16.Parse(llvmVersions[0]) == 13) && (Int16.Parse(llvmVersions[1]) == 0) && (Int16.Parse(llvmVersions[2]) == 0)) { return path; } } else { CommandControllerInstance.CommandController.DisplayMessage (message: "⚠ Clang Power Tools requires a minimum LLVM version of 13.0.0 or higher."); return path; } var paths = path.Split(';').ToList(); paths.RemoveAt(paths.Count - 1); paths.RemoveAll(ContainsLlvm); if (string.IsNullOrWhiteSpace(llvmModel.PreinstalledLlvmPath) == false && llvmModel.LlvmSelectedVersion == llvmModel.PreinstalledLlvmVersion) { paths.Add(llvmModel.PreinstalledLlvmPath); } else { paths.Add(GetUsedLlvmVersionPath(llvmModel.LlvmSelectedVersion)); } //Add in path include-what-you-use on running optimize includes if (!string.IsNullOrEmpty(aEnvPath)) { paths.Add(aEnvPath); } return String.Join(";", paths); } /// /// Run a process that download a tool (and returns path) if it wasn't found on disk /// /// public static string DownloadTool(string tool) { var getllvmScriptPath = GetLLVMScriptFilePath(); Process process = new Process(); process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.EnvironmentVariables["Path"] = PowerShellWrapper.CreatePathEnvironmentVariable(); process.StartInfo.EnvironmentVariables["CPT_CPULIMIT"] = GetNumberOfProcessors().ToString(); process.StartInfo.FileName = $"{Environment.SystemDirectory}\\{ScriptConstants.kPowerShellPath}"; //Check if powershell 7 is in Path string powershell = string.Empty; if (SettingsProvider.CompilerSettingsModel.Powershell7) { powershell = ScriptConstants.kScriptBeginning; if (string.IsNullOrEmpty(GetFilePathFromEnviromentVar(ScriptConstants.kPwsh))) { mOutputWindowController.Write("Can't find PowerShell 7 in PATH"); SettingsHandler settingsHandler = new SettingsHandler(); SettingsProvider.CompilerSettingsModel.Powershell7 = false; settingsHandler.SaveSettings(); return string.Empty; } } else { powershell = ScriptConstants.kScriptBeginning; } process.StartInfo.Arguments = powershell + $" '{getllvmScriptPath}' {tool} \""; RunController.runningProcesses.Add(process); try { process.Start(); process.WaitForExit(); while (!process.StandardOutput.EndOfStream) { return process.StandardOutput.ReadLine(); } } catch (Exception exception) { throw new Exception( $"Cannot execute {process.StartInfo.FileName}.\n{exception.Message}."); } finally { // Remove the process from the runningProcesses list RunController.runningProcesses.Remove(process); } return string.Empty; } /// /// Return file path, if is found in PATH enviroment variables. /// Returns empty string if path can't be found. /// /// public static string GetFilePathFromEnviromentVar(string aFile) { var path = Environment.GetEnvironmentVariable("Path"); var paths = path.Split(';').ToList(); //Is file in path - first check string filePath = paths.Find(p => p.Contains(ScriptConstants.kPowershell7PathPart))?.ToString(); if (!string.IsNullOrWhiteSpace(filePath)) { //Check if file exists on this path string absoluteFilePath = Path.Combine(filePath, aFile); if (File.Exists(absoluteFilePath)) return absoluteFilePath; } //Search file in all paths - second check var pathResult = paths.Find(p => File.Exists(Path.Combine(p, aFile))); if (!string.IsNullOrEmpty(pathResult)) { string absoluteFilePath = Path.Combine(paths.Find(p => File.Exists(Path.Combine(p, aFile))).ToString(), aFile); if (File.Exists(absoluteFilePath)) return absoluteFilePath; } return string.Empty; } #endregion #region Private Methods private static string GetLLVMScriptFilePath() { var assemblyPath = Assembly.GetExecutingAssembly().Location; var scriptDirectory = assemblyPath.Substring(0, assemblyPath.LastIndexOf('\\')); return Path.Combine(scriptDirectory, "Tooling\\v1\\psClang", ScriptConstants.kGetLLVMScriptName); } private static string GetCustomTidyPath() { var executablePath = SettingsProvider.TidySettingsModel.CustomExecutable; return string.IsNullOrWhiteSpace(executablePath) == false ? executablePath : string.Empty; } public static string GetClangBuildScriptPath() { var assemblyPath = Assembly.GetExecutingAssembly().Location; var scriptDirectory = assemblyPath.Substring(0, assemblyPath.LastIndexOf('\\')); return Path.Combine(scriptDirectory, ScriptConstants.ToolingV1, ScriptConstants.kScriptName); } private static string GetUsedLlvmVersionPath(string llvmVersion) { var settingsPathBuilder = new SettingsPathBuilder(); return settingsPathBuilder.GetLlvmBinPath(llvmVersion); } private static bool ContainsLlvm(string input) { return input.ToLower().Contains("llvm"); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/RunModeScriptBuilder.cs ================================================ using ClangPowerTools.Builder; using System.IO; using System.Reflection; namespace ClangPowerTools.Script { public class RunModeScriptBuilder : IBuilder { #region Members /// /// The resulted script after the build /// private string mScript = string.Empty; #endregion #region Methods #region Public Methods #region IBuilder Implementation /// /// Create the power shell script run mod by setting the execution mode parameters with the main script(clang-build.ps1) file path attached /// public void Build() { mScript = $"{ScriptConstants.kScriptBeginning} '{GetScriptFilePath()}'"; } /// /// Get the power shell script run mode with the main script(clang-build.ps1) file path attached /// /// PowerShell script run mode with the script file attached public string GetResult() => mScript; #endregion #endregion #region Private Methods /// /// Get the power shell main script(clang-build.ps1) file path /// /// Script file path protected string GetScriptFilePath() { var assemblyPath = Assembly.GetExecutingAssembly().Location; var scriptDirectory = assemblyPath.Substring(0, assemblyPath.LastIndexOf('\\')); return Path.Combine(scriptDirectory, ScriptConstants.ToolingV1, ScriptConstants.kScriptName); } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/RunningProcesses.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Management; using System.Threading; namespace ClangPowerTools { public class RunningProcesses { #region Members private readonly static List commandProcesses = new List(); private readonly static List backgroundCommandProcesses = new List(); private readonly bool backgroundProcess = false; private static Mutex mutex = new Mutex(); #endregion #region Constructor public RunningProcesses(bool background = false) { backgroundProcess = background; } #endregion #region Public Methods public void Add(Process aProcess) { mutex.WaitOne(); if (backgroundProcess) backgroundCommandProcesses.Add(aProcess); else commandProcesses.Add(aProcess); mutex.ReleaseMutex(); } public void Add(Process aProcess, bool background = false) { if (background) backgroundCommandProcesses.Add(aProcess); else commandProcesses.Add(aProcess); } public bool Exists(bool backgroundRunners) { return backgroundRunners ? backgroundCommandProcesses.Count != 0 : commandProcesses.Count != 0; } public void Kill(bool background) { mutex.WaitOne(); var processes = GetProcesses(background); foreach (var process in processes) { if (process.HasExited || process.Responding == false) continue; KillProcessAndChildren(process.Id); } Clear(processes); mutex.ReleaseMutex(); } public void Kill(Process process) { mutex.WaitOne(); if (process == null || process.HasExited || process.Responding == false) return; KillProcessAndChildren(process.Id); mutex.ReleaseMutex(); } public void Remove(Process process) { mutex.WaitOne(); commandProcesses.Remove(process); mutex.ReleaseMutex(); } public void KillById(int aId) { var procees = commandProcesses.FirstOrDefault(p => p.Id == aId); if (null == procees) return; procees.Kill(); } #endregion #region Private Methods private List GetProcesses(bool background) { return background ? backgroundCommandProcesses : commandProcesses; } private void Clear(List processes) { processes.ForEach(process => process.Close()); processes.Clear(); } private static void KillProcessAndChildren(int aPid) { // Cannot close 'system idle process' if (aPid == 0) return; Process proc = new Process(); try { ManagementObjectSearcher searcher = new ManagementObjectSearcher ("Select * From Win32_Process Where ParentProcessID=" + aPid); ManagementObjectCollection moc = searcher.Get(); foreach (ManagementObject mo in moc) KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"])); proc.Close(); proc = Process.GetProcessById(aPid); proc.Kill(); } catch (Exception) { // The process has already exited. proc.Close(); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/ScriptConstants.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools { public class ScriptConstants { #region Constants public const string kCppProjectGuid = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; #region Clang Compile/Tidy constants public static readonly List kAcceptedFileExtensionsWithoutHeaders = new List() { ".c", ".cpp", ".cc", ".cxx", ".c++", ".cp", ".tli", ".tlh", ".cu", ".vcxproj", ".ixx" }; public static readonly List kAcceptedFileExtensions = new List { ".c", ".cpp", ".cc", ".cxx", ".c++", ".cp", ".cu", ".h", ".hh", ".hpp", ".hxx", ".tli", ".tlh", ".vcxproj", ".ixx" }; public static readonly List kExtendedAcceptedFileExtensions = new List { ".c", ".cpp", ".cc", ".inl", ".cxx", ".c++", ".cp", ".cu", ".cs", ".h", ".hh", ".hpp", ".hxx", ".tli", ".tlh", ".vcxproj", ".ixx" }; public const string kProjectFileExtension = ".vcxproj"; public const string FileExtensionsSelectFile = "Code files (*.c;*.cpp;*.cxx;*.cc;*.tli;*.tlh;*.h;*.hh;*.hpp;*.hxx;)|*.c;*.cpp;*.cxx;*.cc;*.tli;*.tlh;*.h;*.hh;*.hpp;*.hxx"; public const string kCMakeConfigFile = "cmakelists.txt"; public const string kPowerShellPath = @"WindowsPowerShell\v1.0\powershell.exe"; public const string kScriptBeginning = @"-ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command "" &"; public const string kScriptName = "clang-build.ps1"; public const string kGetLLVMScriptName = "get-llvm.ps1"; public const string ToolingV1 = @"Tooling\v1"; public const string kPowershell7PathPart = "PowerShell\\7"; public const string kPwsh = "pwsh.exe"; public const string kEnvrionmentTidyPath = "CLANG_TIDY_PATH"; public const string kFile = "-file"; public const string kProject = "-proj"; public const string kDirectory = "-dir"; public const string kLiteral = "-literal"; public const string kStringContinue = "'continue'"; public const string kTreatWarningsAsErrors = "-Werror"; public const string kParallel = "-parallel"; public const string kContinue = "-continue"; public const string kErrorMode = "-ErrorAction"; public const string kWaringMode = "-WarningAction"; public const string kInformationMode = "-InformationAction"; public const string kVerboseMode = "-Verbose"; public const string kDebugMode = "-debug"; public const string kSystemIncludeDirectories = "-treat-sai"; public const string kQueryFile = "clang-query.exe"; public const string kTidy = "-tidy"; public const string kTidyFix = "-tidy-fix"; public const string kTidyCheckFirstElement = "-*,"; public const string kClangFlags = "-clang-flags"; public const string kIncludeDirectores = "-include-dirs"; public const string kProjectsToIgnore = "-proj-ignore"; public const string kFilesToIgnore = "-file-ignore"; public const string kVsVersion = "-vs-ver"; public const string kVsEdition = "-vs-sku"; public const string kActiveConfiguration = "-active-config"; public const string kHeaderFilter = "-header-filter"; public const string kTidyFile = ".clang-tidy"; public const string kCompilationDatabaseDir = "-compilation-database-dir"; public const string kClangFormatStyle = "-format-style"; #endregion #region Clang Format constants public const string kClangFormat = "clang-format.exe"; public const string kClangDoc = "clang-doc.exe"; public const string kIwyu = "include-what-you-use.exe"; public const string kIwyuTool = "iwyu_tool.py"; public const string kIwyuFixIncludes = "fix_includes.py"; public const string kClangTidy = "clang-tidy.exe"; public const string kCompilationDBFile = "compile_commands.json"; public const string kAssumeFilename = "-assume-filename"; public const string kFallbackStyle = "-fallback-style"; //public const string kSortIncludes = "-sort-includes"; public const string kStyle = "-style"; #endregion #region JSON Compilation DB public const string kJsonCompilationDb = "-export-jsondb"; #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Script/VerbosityScriptBuilder.cs ================================================ using ClangPowerTools.Builder; using System; namespace ClangPowerTools.Script { public class VerbosityScriptBuilder : IBuilder { string mVerbosity = string.Empty; string mResultScript = string.Empty; public VerbosityScriptBuilder(string aVerbosity) => mVerbosity = Convert.ToString(int.Parse(aVerbosity) + 1); public void Build() { mResultScript = ""; bool finishBuild = false; if (mVerbosity != "1" && !finishBuild) { mResultScript += $" {ScriptConstants.kVerboseMode}"; } else if (mVerbosity == "1") { finishBuild = true; } if (mVerbosity != "2" && !finishBuild) { mResultScript += $" {ScriptConstants.kInformationMode} {ScriptConstants.kStringContinue} " + $"{ScriptConstants.kDebugMode} {ScriptConstants.kWaringMode} {ScriptConstants.kStringContinue}"; } } public string GetResult() { return mResultScript; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Services/PowerShellService.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.MVVM.Constants; using System; using System.IO; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace ClangPowerTools.Services { public class PowerShellService { #region Members public CancellationTokenSource downloadCancellationToken = new(); private readonly SettingsPathBuilder settingsPathBuilder = new(); #endregion #region Public Methods public async Task UpdateScriptsAsync() { string scriptUri = PsUpdaterConstants.GitHubUri + PsUpdaterConstants.ClangBuildScript; await DownloadScriptAsync(scriptUri, PsUpdaterConstants.ClangBuildScript); ReplaceScripts(); } #endregion #region Private Methods private async Task DownloadScriptAsync(string fileUri, string fileName) { string scriptsDirectory = settingsPathBuilder.GetPath(PsUpdaterConstants.PowerShellScriptsFolder); string scriptFullName = Path.Combine(scriptsDirectory, fileName); try { FileSystem.CreateDirectory(scriptsDirectory); using WebClient client = new(); await client.DownloadFileTaskAsync(new Uri(fileUri), scriptFullName); } catch (Exception e) { MessageBox.Show(e.Message, "PowerShell Scripts", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void ReplaceScripts() { string destFolder = Path.GetDirectoryName(settingsPathBuilder.GetAssemblyLocalPath()); destFolder = Path.Combine(destFolder, PsUpdaterConstants.ToolingFolder, PsUpdaterConstants.V1Folder); string sourceFolder = settingsPathBuilder.GetPath(PsUpdaterConstants.PowerShellScriptsFolder); try { //Check if file was downloaded, delete destination folder, all files will be automatically downloaded //If file wasn't download, an exception will throw on MoveFile action FileInfo sourceFile = new FileInfo(Path.Combine(sourceFolder, PsUpdaterConstants.ClangBuildScript)); if (File.Exists(sourceFile.FullName) && sourceFile.Length > 0) { FileSystem.DeleteDirectory(destFolder); } else { MessageBox.Show("The download of clang-build.ps1 cannot be completed due to a potential issue with your internet connection. Please verify your connectivity.", "PowerShell Scripts", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } Directory.CreateDirectory(destFolder); FileSystem.MoveFile(Path.Combine(sourceFolder, PsUpdaterConstants.ClangBuildScript), Path.Combine(destFolder, PsUpdaterConstants.ClangBuildScript)); destFolder = Path.Combine(destFolder, PsUpdaterConstants.PsClangFolder); } catch (Exception e) { MessageBox.Show(e.Message, "PowerShell Scripts", MessageBoxButtons.OK, MessageBoxIcon.Error); } ClearFilesAfterReplace(); MessageBox.Show("PowerShell scripts were updated to the latest version.", "PowerShell Scripts", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void ClearFilesAfterReplace() { string scriptsDirectory = settingsPathBuilder.GetPath(PsUpdaterConstants.PowerShellScriptsFolder); try { FileSystem.DeleteDirectory(scriptsDirectory); } catch (Exception e) { MessageBox.Show(e.Message, "PowerShell Scripts", MessageBoxButtons.OK, MessageBoxIcon.Error); } } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Services/VsServiceProvider.cs ================================================ using System; using System.Collections.Generic; namespace ClangPowerTools.Services { /// /// Contains all the logic of store and get VS services /// public static class VsServiceProvider { #region Members /// /// VS Services collection /// private static Dictionary mServices = new Dictionary(); #endregion #region Public Methods /// /// Store the service /// /// The type of the service /// The service instance public static void Register(Type aType, object aService) => mServices.Add(aType, aService); /// /// Get the VS service. Throws an exception if the required service was not registered before. /// /// The type of the service /// The VS service object public static object GetService(Type aType) => mServices[aType]; /// /// Get the VS service. If the wanted service was not registered before the out parameter will be null. /// /// The type of the service /// The wanted VS service object /// True if the service was registered before. False otherwise public static bool TryGetService(Type aType, out object aService) { return mServices.TryGetValue(aType, out aService); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/SilentFile/SilentFileChangerBuilder.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Services; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Diagnostics; using System.Runtime.InteropServices; using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants; namespace ClangPowerTools.SilentFile { public class SilentFileChangerBuilder : IBuilder { #region Members private SilentFileChangerModel mSilentFileChangerModel; #endregion #region Constructor /// /// Instance constructor /// /// Async package /// The file path of the file for which the changes will be ignored /// True if the file will be reloaded. False otherwise public SilentFileChangerBuilder(string aFileName, bool aReloadDocument) { mSilentFileChangerModel = new SilentFileChangerModel() { DocumentFileName = aFileName, ReloadDocumentFlag = aReloadDocument, IsSuspended = true }; } #endregion #region IBuilder Implementation /// /// Create a new instance of silent file changer model /// public void Build() { var docData = IntPtr.Zero; try { if (!VsServiceProvider.TryGetService(typeof(SVsRunningDocumentTable), out object vsRunningDocTable) || null == vsRunningDocTable as IVsRunningDocumentTable) return; ErrorHandler.ThrowOnFailure((vsRunningDocTable as IVsRunningDocumentTable).FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, mSilentFileChangerModel.DocumentFileName, out IVsHierarchy hierarchy, out uint itemId, out docData, out uint docCookie)); if ((docCookie == (uint)ShellConstants.VSDOCCOOKIE_NIL) || docData == IntPtr.Zero) return; if (!VsServiceProvider.TryGetService(typeof(SVsFileChangeEx), out object vsFileChange) || null == vsFileChange as IVsFileChangeEx) return; ErrorHandler.ThrowOnFailure((vsFileChange as IVsFileChangeEx).IgnoreFile(0, mSilentFileChangerModel.DocumentFileName, 1)); if (docData == IntPtr.Zero) return; var unknown = Marshal.GetObjectForIUnknown(docData); if (!(unknown is IVsPersistDocData)) return; mSilentFileChangerModel.PersistDocData = (IVsPersistDocData)unknown; if (!(mSilentFileChangerModel.PersistDocData is IVsDocDataFileChangeControl)) return; mSilentFileChangerModel.FileChangeControl = mSilentFileChangerModel.PersistDocData as IVsDocDataFileChangeControl; } catch (InvalidCastException e) { Trace.WriteLine("Exception" + e.Message); } finally { if (docData != IntPtr.Zero) Marshal.Release(docData); } } /// /// Get the silent file changer model constructed earlier /// /// Silent file changer model public SilentFileChangerModel GetResult() => mSilentFileChangerModel; #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/SilentFile/SilentFileChangerController.cs ================================================ using ClangPowerTools.Builder; using ClangPowerTools.Services; using EnvDTE; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.IO; namespace ClangPowerTools.SilentFile { /// /// Prevent visual studio to ask you if you want to reload the files /// public class SilentFileChangerController : IDisposable { #region Members /// /// Collection of all silent file changer models necessary when tidy-fix is executed /// private HashSet mSilentFileChangers = new HashSet(new SilentFileChangerEqualityComparer()); #endregion #region Methods #region Public methods /// /// Silent all files from a IEnumerable data collection /// /// Async package instance /// Files path collection for the files for which the changes will be ignored public void SilentFiles(IEnumerable aFilesPath) { foreach (var filePath in aFilesPath) { var silentFile = GetNewSilentFileChanger(filePath); mSilentFileChangers.Add(silentFile); Silent(silentFile); } } /// /// Silent all open files extracted from a DTE documents data collection /// /// Async package instance /// DTE instance to collect all the documents public void SilentFiles(Documents aDocuments) { foreach (Document doc in aDocuments) { var silentFile = GetNewSilentFileChanger(Path.Combine(doc.Path, doc.Name)); mSilentFileChangers.Add(silentFile); Silent(silentFile); } } #region IDisposable Implementation /// /// Stop ignoring the file changes for all stored files /// public void Dispose() { foreach (var silentFileChanger in mSilentFileChangers) Resume(silentFileChanger); } #endregion #endregion #region Private Methods /// /// Create a new silent file changer model object /// /// Async package instance /// The file path of the file for which the changes will be ignored private SilentFileChangerModel GetNewSilentFileChanger(string aFilePath) { IBuilder silentFileChangerBuilder = new SilentFileChangerBuilder(aFilePath, true); silentFileChangerBuilder.Build(); var silentFile = silentFileChangerBuilder.GetResult(); return silentFile; } /// /// Ignore all file changes of a file /// /// private void Silent(SilentFileChangerModel aSilentFileChanger) { if (null != aSilentFileChanger.FileChangeControl) ErrorHandler.ThrowOnFailure(aSilentFileChanger.FileChangeControl.IgnoreFileChanges(1)); } /// /// Stop ignoring the file changes for a certain files /// public void Resume(SilentFileChangerModel aSilentFileChanger) { if (null == aSilentFileChanger) return; if (!aSilentFileChanger.IsSuspended || null == aSilentFileChanger.PersistDocData) return; if (null != aSilentFileChanger.PersistDocData && aSilentFileChanger.ReloadDocumentFlag) aSilentFileChanger.PersistDocData.ReloadDocData(0); if (!VsServiceProvider.TryGetService(typeof(SVsFileChangeEx), out object vsFileChangeService) || null == vsFileChangeService as IVsFileChangeEx) return; var vsFileChange = vsFileChangeService as IVsFileChangeEx; aSilentFileChanger.IsSuspended = false; ErrorHandler.ThrowOnFailure(vsFileChange.SyncFile(aSilentFileChanger.DocumentFileName)); ErrorHandler.ThrowOnFailure(vsFileChange.IgnoreFile(0, aSilentFileChanger.DocumentFileName, 0)); if (aSilentFileChanger.FileChangeControl != null) ErrorHandler.ThrowOnFailure(aSilentFileChanger.FileChangeControl.IgnoreFileChanges(0)); } #endregion #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/SilentFile/SilentFileChangerEqualityComparer.cs ================================================ using ClangPowerTools.SilentFile; using System.Collections.Generic; namespace ClangPowerTools { public class SilentFileChangerEqualityComparer : IEqualityComparer { #region Public methods public bool Equals(SilentFileChangerModel obj1, SilentFileChangerModel obj2) { if (obj2 == null && obj1 == null) return true; else if (obj1 == null | obj2 == null) return false; else if (obj1.DocumentFileName.ToLower() == obj2.DocumentFileName.ToLower()) return true; else return false; } public int GetHashCode(SilentFileChangerModel obj) { return obj.DocumentFileName.GetHashCode(); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/SilentFile/SilentFileChangerModel.cs ================================================ using Microsoft.VisualStudio.Shell.Interop; namespace ClangPowerTools.SilentFile { public class SilentFileChangerModel { #region Members public string DocumentFileName { get; set; } public IVsPersistDocData PersistDocData { get; set; } public IVsDocDataFileChangeControl FileChangeControl { get; set; } public bool IsSuspended { get; set; } public bool ReloadDocumentFlag { get; set; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquiggleErrorTag.cs ================================================ using Microsoft.VisualStudio.Text.Tagging; namespace ClangPowerTools.Squiggle { public class SquiggleErrorTag : ErrorTag { public SquiggleErrorTag(string type, string tooltip) : base(type, tooltip) { } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquiggleErrorTagger.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using ClangPowerTools.Error; using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; namespace ClangPowerTools.Squiggle { /// /// This tagger will provide tags for every word in the buffer that /// matches the word currently under the cursor. /// public class SquiggleErrorTagger : ITagger { #region Members public event EventHandler TagsChanged; private int line; private int column; private readonly string squiggleType = "other error"; private ITextBuffer SourceBuffer { get; set; } private ConcurrentQueue Squiggles { get; set; } = new ConcurrentQueue(); #endregion #region Constructor public SquiggleErrorTagger(ITextBuffer sourceBuffer) { SourceBuffer = sourceBuffer; } #endregion #region ITagger Implementation /// /// Find every instance of CurrentWord in the given span /// /// A read-only span of text to be searched for instances of CurrentWord public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { if (SettingsProvider.CompilerSettingsModel.ShowSquiggles == false) yield break; if (Squiggles == null || Squiggles.Count() == 0) { CreateSquiggles(); yield break; } if (spans.Count == 0) yield break; var tempEvent = TagsChanged; if (tempEvent == null) yield break; foreach (var errorSquiggle in Squiggles) { yield return new TagSpan(errorSquiggle.Snapshout, errorSquiggle.Squiggle); } } #endregion #region Public Methods private void CreateSquiggles() { if (TaskErrorViewModel.FileErrorsPair == null || TaskErrorViewModel.FileErrorsPair.Count == 0) return; var dte = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); var activeDocument = dte.ActiveDocument; if (activeDocument == null) return; if (dte.ActiveWindow.Selection is TextSelection == false) return; TextSelection textSelection = (TextSelection)dte.ActiveWindow.Selection; if (textSelection == null) return; var currentLineNumber = textSelection.CurrentLine; if (TaskErrorViewModel.FileErrorsPair.ContainsKey(activeDocument.FullName) == false) return; foreach (var error in TaskErrorViewModel.FileErrorsPair[activeDocument.FullName]) { var bufferLines = SourceBuffer.CurrentSnapshot.Lines.ToList(); line = error.Line.ForceInRange(0, bufferLines.Count - 1); var currentLine = SourceBuffer.CurrentSnapshot.GetLineFromLineNumber(line); var currentLineText = currentLine.GetText().TrimEnd(); if (string.IsNullOrWhiteSpace(currentLineText)) continue; column = error.Column.ForceInRange(0, currentLineText.Length - 1); if (column - 1 >= 0 && column + 1 < currentLineText.Length) { if (currentLineText[column - 1] == ' ' && currentLineText[column] != ' ' && currentLineText[column + 1] == ' ') { ThreadPool.QueueUserWorkItem((object threadContext) => { var tagSpan = CreateTagSpan(column, 1, error.Text); if(tagSpan != null) Squiggles.Enqueue(tagSpan); }); continue; } } GetSquiggleValues(bufferLines, currentLineText, out int start, out int length); ThreadPool.QueueUserWorkItem((object threadContext) => { var tagSpan = CreateTagSpan(start, length, error.Text); if(tagSpan != null) Squiggles.Enqueue(tagSpan); }); } } #endregion #region Private Methods private SquiggleModel CreateTagSpan(int start, int length, string tooltip) { try { var snapshotSpan = new SnapshotSpan(SourceBuffer.CurrentSnapshot, start, length); var squiggle = new SquiggleErrorTag(squiggleType, tooltip); return new SquiggleModel() { Snapshout = snapshotSpan, Squiggle = squiggle }; } catch (Exception) { return null; } } private int LengthUntilGivenPosition(List lines) { var count = 0; for (var i = 0; i < line; ++i) { count += lines[i].GetText().Length; } return count + column + (line * 2) + 1; } private int FindTheBeginning(string text, int start, int iterationValue, out int stepsBack) { stepsBack = 0; for (int i = iterationValue; i >= 0; --i) { if (text[i] == ' ' || text[i] == '\n' || text[i] == '\r') { break; } ++stepsBack; --start; } return start; } private int FindLength(string text, int start) { var length = 0; for (int i = start; i < text.Length; ++i) { if (text[i] == ' ') break; ++length; } return length; } private void GetSquiggleValues(List lines, string text, out int start, out int length) { start = LengthUntilGivenPosition(lines); start = start.ForceInRange(0, SourceBuffer.CurrentSnapshot.GetText().Length - 1); start = FindTheBeginning(text, start, column, out int stepsBack); length = FindLength(text, column - stepsBack + 1); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquiggleErrorTaggerProvider.cs ================================================ using System.ComponentModel.Composition; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; namespace ClangPowerTools.Squiggle { /// /// Export a /// [Export(typeof(IViewTaggerProvider))] [ContentType("text")] [TagType(typeof(SquiggleErrorTag))] public class SquiggleErrorTaggerProvider : IViewTaggerProvider { #region ITaggerProvider Members [Import] internal ITextStructureNavigatorSelectorService TextStructureNavigatorSelector { get; set; } /// /// This method is called by VS to generate the tagger /// /// /// The text view we are creating a tagger for /// The buffer that the tagger will examine for instances of the current word /// Returns a HighlightWordTagger instance public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag { if (textView.TextBuffer != buffer) return null; return new SquiggleErrorTagger(buffer) as ITagger; } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquiggleModel.cs ================================================ using Microsoft.VisualStudio.Text; namespace ClangPowerTools.Squiggle { public class SquiggleModel { public SnapshotSpan Snapshout { get; set; } public SquiggleErrorTag Squiggle { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquiggleViewModel.cs ================================================ using System.Collections.Generic; namespace ClangPowerTools.Squiggle { public class SquiggleViewModel { public IEnumerable Squiggles { get; set; } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Squiggle/SquigglesFactory.cs ================================================ using ClangPowerTools.Error; using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio.Text; using System.Collections.Generic; using System.Linq; namespace ClangPowerTools.Squiggle { public class SquigglesFactory { #region Members private readonly string squiggleType = "other error"; private ITextBuffer SourceBuffer { get; set; } private int line; private int column; private const int rangeArea = 100; public static List Squiggles { get; set; } = new List(); #endregion #region Constuctor public SquigglesFactory(ITextBuffer sourceBuffer) { SourceBuffer = sourceBuffer; } #endregion #region Public Methods public void Create() { if (TaskErrorViewModel.FileErrorsPair == null || TaskErrorViewModel.FileErrorsPair.Count == 0) return; var dte = (DTE2)VsServiceProvider.GetService(typeof(DTE2)); var activeDocument = dte.ActiveDocument; if (activeDocument == null) return; if (dte.ActiveWindow.Selection is TextSelection == false) return; TextSelection textSelection = (TextSelection) dte.ActiveWindow.Selection; if (textSelection == null) return; var currentLineNumber = textSelection.CurrentLine; if (TaskErrorViewModel.FileErrorsPair.ContainsKey(activeDocument.FullName) == false) return; foreach (var error in TaskErrorViewModel.FileErrorsPair[activeDocument.FullName]) { //var min = currentLineNumber - rangeArea <= 1 ? 1 : currentLineNumber - rangeArea; //var max = currentLineNumber + rangeArea >= SourceBuffer.CurrentSnapshot.GetText().Length ? // SourceBuffer.CurrentSnapshot.GetText().Length - 1 : currentLineNumber + rangeArea; //if (error.Line < min || error.Line > max) // continue; var bufferLines = SourceBuffer.CurrentSnapshot.Lines.ToList(); line = error.Line.ForceInRange(0, bufferLines.Count - 1); var currentLine = SourceBuffer.CurrentSnapshot.GetLineFromLineNumber(line); var currentLineText = currentLine.GetText().TrimEnd(); if (string.IsNullOrWhiteSpace(currentLineText)) continue; column = error.Column.ForceInRange(0, currentLineText.Length - 1); if (column - 1 >= 0 && column + 1 < currentLineText.Length) { if (currentLineText[column - 1] == ' ' && currentLineText[column] != ' ' && currentLineText[column + 1] == ' ') { Squiggles.Add(CreateTagSpan(column, 1, error.Text)); continue; } } GetSquiggleValues(bufferLines, currentLineText, out int start, out int length); Squiggles.Add(CreateTagSpan(start, length, error.Text)); } } #endregion #region Private Methods private SquiggleModel CreateTagSpan(int start, int length, string tooltip) { var snapshotSpan = new SnapshotSpan(SourceBuffer.CurrentSnapshot, start, length); var squiggle = new SquiggleErrorTag(squiggleType, tooltip); return new SquiggleModel() { Snapshout = snapshotSpan, Squiggle = squiggle }; } private int LengthUntilGivenPosition(List lines) { var count = 0; for (var i = 0; i < line; ++i) { count += lines[i].GetText().Length; } return count + column + (line * 2) + 1; } private int FindTheBeginning(string text, int start, int iterationValue, out int stepsBack) { stepsBack = 0; for (int i = iterationValue; i >= 0; --i) { if (text[i] == ' ' || text[i] == '\n' || text[i] == '\r') { break; } ++stepsBack; --start; } return start; } private int FindLength(string text, int start) { var length = 0; for (int i = start; i < text.Length; ++i) { if (text[i] == ' ') break; ++length; } return length; } private void GetSquiggleValues(List lines, string text, out int start, out int length) { start = LengthUntilGivenPosition(lines); start = start.ForceInRange(0, SourceBuffer.CurrentSnapshot.GetText().Length - 1); start = FindTheBeginning(text, start, column, out int stepsBack); length = FindLength(text, column - stepsBack + 1); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/TextOperationsInterfaces/IDetector.cs ================================================ using System.Text.RegularExpressions; namespace ClangPowerTools.TextOperationsInterfaces { public interface IDetector { bool Detect(string aText, string pattern, out Match aMatcheResult); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/TextOperationsInterfaces/ITextFormatter.cs ================================================ namespace ClangPowerTools.TextOperationsInterfaces { public interface ITextFormatter { string Format(string aText, string aReplacement); } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/clang-build.ps1 ================================================ <# .SYNOPSIS Compiles or tidies up code from Visual Studio .vcxproj project files. .DESCRIPTION This PowerShell script scans for all .vcxproj Visual Studio projects inside a source directory. One or more of these projects will be compiled or tidied up (modernized), using Clang. .PARAMETER aSolutionsPath Alias 'dir'. Source directory to find sln files. Projects will be extracted from each sln. Important: You can pass an absolute path to a sln. This way, no file searching will be done, and only the projects from this solution file will be taken into account. .PARAMETER aVcxprojToCompile Alias 'proj'. Array of project(s) to compile. If empty, all projects found in solutions are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*components'). Absolute disk paths to vcxproj files are accepted. Can be passed as comma separated values. .PARAMETER aVcxprojToIgnore Alias 'proj-ignore'. Array of project(s) to ignore, from the matched ones. If empty, all already matched projects are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*components'). Can be passed as comma separated values. .PARAMETER aVcxprojConfigPlatform Alias 'active-config'. Array of configuration-platform pairs, each pair being separated by |, to be used when processing project files. E.g. "Debug|Win32", "Debug|x64". If not specified, the first configuration-platform found in the current project is used. Projects will be processed for each configuration-platform specified, the ones that are missing will be skipped. .PARAMETER aCppToCompile Alias 'file'. What cpp(s) to compile from the found project(s). If empty, all CPPs are compiled. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*table'). Note: If any headers are given then all translation units that include them will be processed. .PARAMETER aCppToIgnore Alias 'file-ignore'. Array of file(s) to ignore, from the matched ones. Regex matching is supported, using the [regex] prefix (e.g. [regex]'.*table'). Can be passed as comma separated values. .PARAMETER aUseParallelCompile Alias 'parallel'. Switch to run in parallel mode, on all logical CPU cores. .PARAMETER aContinueOnError Alias 'continue'. Switch to continue project compilation even when errors occur. .PARAMETER aTreatAdditionalIncludesAsSystemIncludes Alias 'treat-sai'. Switch to treat project additional include directories as system includes. .PARAMETER aClangCompileFlags Alias 'clang-flags'. Flags given to clang++ when compiling project, alongside project-specific defines. .PARAMETER aTidyFlags Alias 'tidy'. If not empty clang-tidy will be called with given flags, instead of clang++. The tidy operation is applied to whole translation units, meaning all directory headers included in the CPP will be tidied up too. Changes will not be applied, only simulated. If aTidyFixFlags is present, it takes precedence over this parameter. If '.clang-tidy' value is given, configuration will be read from .clang-tidy file in the closest parent directory. .PARAMETER aTidyFixFlags Alias 'tidy-fix'. If not empty clang-tidy will be called with given flags, instead of clang++. The tidy operation is applied to whole translation units, meaning all directory headers included in the CPP will be tidied up too. Changes will be applied to the file(s). If present, this parameter takes precedence over aTidyFlags. If '.clang-tidy' value is given, configuration will be read from .clang-tidy file in the closest parent directory. .PARAMETER aAfterTidyFixFormatStyle Alias 'format-style'. Used in combination with 'tidy-fix'. If present, clang-tidy will also format the fixed file(s), using the specified style. Possible values: - not present, no formatting will be done - 'file' Literally 'file', not a placeholder. Uses .clang-format file in the closest parent directory. - 'llvm' - 'google' - 'webkit' - 'mozilla' .PARAMETER aVisualStudioVersion Alias 'vs-ver'. Version of Visual Studio (VC++) installed and that'll be used for standard library include directories. E.g. 2017. Optional. If not given, it will be inferred based on the project toolset version. .PARAMETER aVisualStudioSku Alias 'vs-sku'. Sku of Visual Studio (VC++) installed and that'll be used for standard library include directories. E.g. Professional. If not given, the first detected Visual Studio SKU will be used. .NOTES Control environment variable values: CPT_CACHEREPO = 0 disables project-loading cache mechanism CPT_LOAD_ALL = 1 enables deep loading of property sheets, but slows down loading CPT_CPULIMIT = n will use n logical processors for compile / tidy jobs, if not specified then NUMBER_OF_PROCESSORS will be used. CPT_PCH_LIMIT = 1 create PCH when only one file needs to be compiled, by default this limit is 2 Author: Gabriel Diaconita #> #Requires -Version 5 param( [alias("proj")] [Parameter(Mandatory=$false, HelpMessage="Filter project(s) to compile/tidy")] [System.Object[]] $aVcxprojToCompile = @() , [alias("dir")] [Parameter(Mandatory=$false, HelpMessage="Source directory for finding solutions; projects will be found from each sln")] [string] $aSolutionsPath , [alias("proj-ignore")] [Parameter(Mandatory=$false, HelpMessage="Specify projects to ignore")] [System.Object[]] $aVcxprojToIgnore = @() , [alias("active-config")] [Parameter(Mandatory=$false, HelpMessage="Config/platform to be used, e.g. Debug|Win32")] [string[]] $aVcxprojConfigPlatform = @() , [alias("file")] [Parameter(Mandatory=$false, HelpMessage="Filter file(s) to compile/tidy")] [System.Object[]] $aCppToCompile = @() , [alias("file-ignore")] [Parameter(Mandatory=$false, HelpMessage="Specify file(s) to ignore")] [System.Object[]] $aCppToIgnore = @() , [alias("parallel")] [Parameter(Mandatory=$false, HelpMessage="Compile/tidy/tidy-fix projects in parallel")] [switch] $aUseParallelCompile , [alias("continue")] [Parameter(Mandatory=$false, HelpMessage="Allow CPT to continue immediately after encountering an error")] [switch] $aContinueOnError , [alias("resume")] [Parameter(Mandatory=$false, HelpMessage="Allow CPT to resume the last session (start from last active project / file number).")] [switch] $aResumeAfterError , [alias("treat-sai")] [Parameter(Mandatory=$false, HelpMessage="Treat project additional include directories as system includes")] [switch] $aTreatAdditionalIncludesAsSystemIncludes , [alias("clang-flags")] [Parameter(Mandatory=$false, HelpMessage="Specify compilation flags to CLANG")] [string[]] $aClangCompileFlags = @() , [alias("tidy")] [Parameter(Mandatory=$false, HelpMessage="Specify flags to CLANG TIDY")] [string] $aTidyFlags , [alias("tidy-fix")] [Parameter(Mandatory=$false, HelpMessage="Specify flags to CLANG TIDY & FIX")] [string] $aTidyFixFlags , [alias("header-filter")] [Parameter(Mandatory=$false, HelpMessage="Enable Clang-Tidy to run on header files")] [string] $aTidyHeaderFilter , [alias("compilation-database-dir")] [Parameter(Mandatory=$false, HelpMessage="Specify a path of a directory where compile_commands.json is located.")] [string] $aCompilationDatabaseDir , [alias("format-style")] [Parameter(Mandatory=$false, HelpMessage="Used with 'tidy-fix'; tells CLANG TIDY-FIX to also format the fixed file(s)")] [string] $aAfterTidyFixFormatStyle , [alias("vs-ver")] [Parameter(Mandatory=$false, HelpMessage="Version of Visual Studio toolset to use for loading project")] [string] $aVisualStudioVersion , [alias("vs-sku")] [Parameter(Mandatory=$false, HelpMessage="Edition of Visual Studio toolset to use for loading project")] [string] $aVisualStudioSku , [alias("export-jsondb")] [Parameter(Mandatory=$false, HelpMessage="Switch to generate a JSON compilation database file, in the current working directory")] [switch] $aExportJsonDB ) Set-StrictMode -version latest $ErrorActionPreference = 'Continue' # System Architecture Constants # ------------------------------------------------------------------------------------------------ Set-Variable -name kCptGithubRepoBase -value ` "https://raw.githubusercontent.com/Caphyon/clang-power-tools/master/ClangPowerTools/ClangPowerToolsShared/Tooling/v1/" ` -option Constant Set-Variable -name kPsMajorVersion -value (Get-Host).Version.Major -Option Constant # ------------------------------------------------------------------------------------------------ # Return Value Constants Set-Variable -name kScriptFailsExitCode -value 47 -option Constant # ------------------------------------------------------------------------------------------------ # File System Constants Set-Variable -name kExtensionVcxproj -value ".vcxproj" -option Constant Set-Variable -name kExtensionSolution -value ".sln" -option Constant Set-Variable -name kExtensionSolutionXml -value ".slnx" -option Constant Set-Variable -name kExtensionYaml -value ".yaml" -option Constant Set-Variable -name kExtensionClangPch -value ".clang.pch" -option Constant Set-Variable -name kExtensionC -value ".c" -option Constant # ------------------------------------------------------------------------------------------------ # Envinroment Variables for controlling logic Set-Variable -name kVarEnvClangTidyPath -value "CLANG_TIDY_PATH"-option Constant # ------------------------------------------------------------------------------------------------ # Clang-Related Constants Set-Variable -name kClangFlagSupressLINK -value @("-fsyntax-only") -option Constant Set-Variable -name kClangFlagIncludePch -value "-include-pch" -option Constant Set-Variable -name kClangFlagFasterPch -value "-fpch-instantiate-templates" -option Constant Set-Variable -name kClangFlagMinusO -value "-o" -option Constant Set-Variable -name kClangDefinePrefix -value "-D" -option Constant Set-Variable -name kClangFlagNoUnusedArg -value "-Wno-unused-command-line-argument" ` -option Constant Set-Variable -name kClangFlagNoMsInclude -value "-Wno-microsoft-include" ` -Option Constant Set-Variable -name kClangFlagFileIsCPP -value "-x c++" -option Constant Set-Variable -name kClangFlagFileIsC -value "-x c" -option Constant Set-Variable -name kClangFlagForceInclude -value "-include" -option Constant Set-Variable -name kClangTidyFixExportFixes -value "--export-fixes=" -option Constant Set-Variable -name kClangCompiler -value "clang++.exe" -option Constant Set-Variable -name kQuiet -value '-quiet' -option Constant Set-Variable -name kEndOptionMarker -value "--" -option Constant Set-Variable -name kClangTidyFlagHeaderFilter -value "-header-filter=" -option Constant Set-Variable -name kClangTidyFlagChecks -value "-checks=" -option Constant Set-Variable -name kClangTidyUseFile -value ".clang-tidy" -option Constant Set-Variable -name kClangTidyFormatStyle -value "-format-style=" -option Constant Set-Variable -name kClangTidyCompilationDatabaseDir -value "-p=" -option Constant Set-Variable -name kClangTidyFlagTempFile -value "" Set-Variable -name kCptRegHiveSettings -value "HKCU:SOFTWARE\Caphyon\Clang Power Tools" -option Constant Set-Variable -name kCptVsixSettings -value "${env:APPDATA}\ClangPowerTools\settings.json" -option Constant Set-Variable -name kCptTidyFixReplacementsDir -value "${env:APPDATA}\ClangPowerTools\TidyFixReplacements" -option Constant # ------------------------------------------------------------------------------------------------ Function cpt:getSetting([string] $name) { if ((Test-Path $kCptVsixSettings)) { $settingsJson = ( (Get-Content -Raw -Path $kCptVsixSettings) | ConvertFrom-Json) $settingField = $settingsJson.Where{ $_ | Get-Member $name } if (!$settingField) { return $null } return $settingField.$name } return $null } # We define this separately from the implementation in io.ps1 because that may not yet be present and # in order to download it we need the connection-status greenlight. Function cpt:testInternetConnectivity { $resp = Get-WmiObject -Class Win32_PingStatus -Filter 'Address="github.com" and Timeout=100' | Select-Object ResponseTime [bool] $hasInternetConnectivity = ($resp.ResponseTime -and $resp.ResponseTime -gt 0) return $hasInternetConnectivity } # Include required scripts, or download them from Github, if necessary Function cpt:ensureScriptExists( [Parameter(Mandatory=$true)] [string] $scriptName , [Parameter(Mandatory=$false)][bool] $forceRedownload ) { [string] $scriptFilePath = "$PSScriptRoot/psClang/$scriptName" if ( $forceRedownload -or (! (Test-Path $scriptFilePath)) ) { Write-Verbose "Download required script $scriptName ..." [string] $request = "$kCptGithubRepoBase/psClang/$scriptName" if ( ! (Test-Path "$PSScriptRoot/psClang")) { New-Item "$PSScriptRoot/psClang" -ItemType Directory > $null } # Invoke-WebRequest has an issue when displaying progress on PowerShell 7, it won't go away # and will keep nagging the user, and on PS5 it causes slow transfers => we supress it. $prevPreference = $progressPreference $ProgressPreference = "SilentlyContinue" Invoke-WebRequest -Uri $request -OutFile $scriptFilePath (Get-Content $scriptFilePath -Raw).Replace("`n","`r`n") | Set-Content $scriptFilePath -Force -NoNewline $ProgressPreference = $prevPreference if (! (Test-Path $scriptFilePath)) { Write-Error "Could not download required script file ($scriptName). Aborting..." exit 1 } } return $scriptFilePath } [bool] $shouldRedownloadForcefully = $false [Version] $cptVsixVersion = cpt:getSetting "Version" Write-Verbose "Current Clang Power Tools VSIX version: $cptVsixVersion" $kLogicalCoreCount = 4; if($Env:NUMBER_OF_PROCESSORS -match "^\d+$") { $kLogicalCoreCount = $Env:NUMBER_OF_PROCESSORS if($Env:CPT_CPULIMIT -match "^\d+$") { $kLogicalCoreCount = $Env:CPT_CPULIMIT } #Set-Variable -name kLogicalCoreCount -value $Env:CPT_CPULIMIT -option Constant } # If the main script has been updated meanwhile, we invalidate all other scripts, and force # them to update from github. We need to watch for this because older CPT VS Extensions (before v7.9) # did not updated all helper scripts, but a list of predefined ones; we need to update the new ones as well. if ( ( ![string]::IsNullOrWhiteSpace($cptVsixVersion) -and [Version]::new($cptVsixVersion) -lt [Version]::new(7, 9, 0) ) -and (Test-Path $kCptRegHiveSettings) ) { Write-Verbose "Checking to see if we should redownload script helpers..." $regHive = Get-Item -LiteralPath $kCptRegHiveSettings $currentHash = (Get-FileHash $PSCommandPath -Algorithm "SHA1").Hash $savedHash = $regHive.GetValue('ScriptContentHash'); # we used to rely on timestamps but it's unreliable so make sure to clean up the reg value if ($regHive.GetValue('ScriptTimestamp')) { Remove-ItemProperty -path $kCptRegHiveSettings -name 'ScriptTimestamp' } if (! (cpt:testInternetConnectivity) ) { Write-Verbose "No internet connectivity. Postponing helper scripts update from github..." } [string] $featureDisableValue = '42' if ( (cpt:testInternetConnectivity) -and ($savedHash -ne $currentHash) -and ($savedHash -ne $featureDisableValue) ) { Write-Verbose "Detected changes in main script. Will redownload helper scripts from Github..." Write-Verbose "Current main script SHA1: $currentHash. Saved SHA1: $savedHash" Set-ItemProperty -path $kCptRegHiveSettings -name 'ScriptContentHash' -value $currentHash $shouldRedownloadForcefully = $true } } @( "io.ps1" , "visualstudio-detection.ps1" , "msbuild-expression-eval.ps1" , "msbuild-project-data.ps1" , "msbuild-project-load.ps1" , "msbuild-project-cache-repository.ps1" , "get-header-references.ps1" , "itemdefinition-context.ps1" , "jsondb-export.ps1" , "get-llvm-helper.ps1" ) | ForEach-Object { cpt:ensureScriptExists $_ $shouldRedownloadForcefully } | ForEach-Object { . $_ } Write-InformationTimed "Imported scripts" #------------------------------------------------------------------------------------------------- # do not include in list above because it is an invokable script, dot-sourcing does not work. cpt:ensureScriptExists "get-llvm.ps1" $shouldRedownloadForcefully | Out-Null #------------------------------------------------------------------------------------------------- # we may have a custom path for Clang-Tidy. Use it if that's the case. [string] $customTidyPath = (Get-QuotedPath -path ([Environment]::GetEnvironmentVariable($kVarEnvClangTidyPath))) if (![string]::IsNullOrWhiteSpace($customTidyPath)) { Set-Variable -name kClangTidy -value $customTidyPath -option Constant } else { Set-Variable -name kClangTidy -value "clang-tidy.exe" -option Constant Set-Variable -name kClangApplyReplacements -value "clang-apply-replacements.exe" -option Constant } Set-Variable -name kCacheRepositorySaveIsNeeded -value $false #------------------------------------------------------------------------------------------------- # Custom Types Write-InformationTimed "Before .NET enum types" if ($kPsMajorVersion -lt 5) { Add-Type -TypeDefinition @" public enum WorkloadType { Compile, Tidy, TidyFix } "@ Add-Type -TypeDefinition @" public enum StopReason { Unknown, ConfigurationNotFound } "@ } else { # this is much faster if PowerShell supports enums, we will save some time Invoke-Expression @" enum WorkloadType { Compile Tidy TidyFix } enum StopReason { Unknown ConfigurationNotFound } "@ } Write-InformationTimed "Created .NET enum types" #------------------------------------------------------------------------------------------------- # Global variables # temporary files created during project processing (e.g. PCH files) [System.Collections.ArrayList] $global:FilesToDeleteWhenScriptQuits = @() # filePath-fileData for SLN files located in source directory [System.Collections.Generic.Dictionary[String,String]] $global:slnFiles = @{} # flag to signal when errors are encounteres during project processing [Boolean] $global:FoundErrors = $false # directory path where tidy fix replacement files will be stored [string] $global:tidyFixReplacementDirPath = "" # default ClangPowerTools version of visual studio to use [string] $global:cptDefaultVisualStudioVersion = "2017" [string[]] $global:cptIgnoredFilesPool = @() # holds file items to process and their contextual properties (inherited + locally defined) [System.Collections.Hashtable] $global:cptFilesToProcess = @{} #------------------------------------------------------------------------------------------------- # Global functions Function Exit-Script([Parameter(Mandatory=$false)][int] $code = 0) { Write-Verbose-Array -array $global:FilesToDeleteWhenScriptQuits ` -name "Cleaning up PCH temporaries" # Clean-up foreach ($file in $global:FilesToDeleteWhenScriptQuits) { Remove-Item -LiteralPath $file -ErrorAction SilentlyContinue > $null } if ($aTidyFixFlags) { Write-Verbose "Cleaning up temporaries tidy-fix replacements" Remove-Item -path $global:tidyFixReplacementDirPath -Recurse -ErrorAction SilentlyContinue > $null } # Restore working directory Pop-Location exit $code } Function Fail-Script([parameter(Mandatory=$false)][string] $msg = "Got errors.") { if (![string]::IsNullOrEmpty($msg)) { Write-Err $msg } Exit-Script($kScriptFailsExitCode) } Function Apply-TidyFixReplacements([Parameter(Mandatory=$true) ][WorkloadType] $workloadType) { if ($workloadType -eq [WorkloadType]::TidyFix -and (Test-Path -LiteralPath $global:tidyFixReplacementDirPath)) { Write-Verbose "Apply tidy-fix replacements" [string] $pathToBinary = (Join-Path -path $global:llvmLocation ` -ChildPath $kClangApplyReplacements) if (![string]::IsNullOrEmpty($aAfterTidyFixFormatStyle)) { & $pathToBinary -format -style="$aAfterTidyFixFormatStyle" $global:tidyFixReplacementDirPath } else { & $pathToBinary $global:tidyFixReplacementDirPath } Wait-AndProcessBuildJobs } } Function Get-SourceDirectory() { [bool] $isDirectory = ($(Get-Item -LiteralPath $aSolutionsPath) -is [System.IO.DirectoryInfo]) if ($isDirectory) { return $aSolutionsPath } else { return (Get-FileDirectory -filePath $aSolutionsPath) } } function Load-Solutions() { Write-Verbose "Scanning for solution files" [string] $pathToCheck = $aSolutionsPath Try { # no need of long path prefix for Powershell > 5.0 $slns = @(Get-ChildItem -recurse -LiteralPath $pathToCheck -Filter "*$kExtensionSolution") $slnxs = @(Get-ChildItem -recurse -LiteralPath $pathToCheck -Filter "*$kExtensionSolutionXml") } Catch { # use long path prefix for PowerShell <= 5.0 $pathToCheck = "\\?\$aSolutionsPath" $slns = @(Get-ChildItem -recurse -LiteralPath $pathToCheck -Filter "*$kExtensionSolution") $slnxs = @(Get-ChildItem -recurse -LiteralPath $pathToCheck -Filter "*$kExtensionSolutionXml") } # Combine both .sln and .slnx files [System.Collections.ArrayList] $allSolutions = @() if ($slns) { $allSolutions += $slns } if ($slnxs) { $allSolutions += $slnxs } foreach ($sln in $allSolutions) { Write-Verbose "Caching solution file $sln" $slnPath = $sln.FullName # remove the UNC long path prefix $slnPath = $slnPath.Replace('\\?\', '') $global:slnFiles[$slnPath] = (Get-Content -LiteralPath $slnPath) Write-Verbose "Solution full path: $slnPath" Write-Verbose "Solution data length: $($global:slnFiles[$slnPath].Length)" } Write-Verbose-Array -array $global:slnFiles.Keys -name "Solution file paths" } function Get-SolutionProjects([Parameter(Mandatory=$true)][string] $slnPath) { Write-Verbose "Retrieving project list for solution: $slnPath" # Check if this is a .slnx (XML) or .sln (text) file if ($slnPath.EndsWith($kExtensionSolutionXml)) { # Parse SLNX (XML-based solution file) [string] $slnDirectory = Get-FileDirectory -file $slnPath Write-Verbose "SLNX solution directory: $slnDirectory" try { [xml]$slnxContent = $global:slnFiles[$slnPath] $projectNodes = $slnxContent.SelectNodes("//Project[@Path]") Write-Verbose "Found $($projectNodes.Count) project nodes in SLNX" [string[]] $projectAbsolutePaths = @() foreach ($projectNode in $projectNodes) { [string] $projectPath = $projectNode.GetAttribute("Path") if ([string]::IsNullOrWhiteSpace($projectPath)) { continue } $projExpandedPath = [Environment]::ExpandEnvironmentVariables($projectPath) if (! $projExpandedPath.EndsWith($kExtensionVcxproj)) { continue } $projExpandedPath = Canonize-Path -base $slnDirectory -child $projExpandedPath -ignoreErrors if (![string]::IsNullOrWhiteSpace($projExpandedPath)) { $projectAbsolutePaths += @($projExpandedPath) } } Write-Verbose-Array -array $projectAbsolutePaths -name "Resolved SLNX project paths" return $projectAbsolutePaths } catch { Write-Warning "Failed to parse SLNX file: $slnPath. Error: $($_.Exception.Message)" return @() } } # Parse traditional .sln (text-based solution file) [string] $slnDirectory = Get-FileDirectory -file $slnPath $matches = [regex]::Matches($global:slnFiles[$slnPath], 'Project\([{}\"A-Z0-9\-]+\) = \".*?\",\s\"(.*?)\"') Write-Verbose "Found $($matches.Count) project matches in SLN" [string[]] $projectAbsolutePaths = @() foreach ($projPathMatch in $matches) { [string] $matchValue = $projPathMatch.Groups[1].Value.Replace('"','') if ([string]::IsNullOrWhiteSpace($matchValue)) { continue } $projExpandedPath = [Environment]::ExpandEnvironmentVariables($matchValue) if ( ! $projExpandedPath.EndsWith($kExtensionVcxproj)) { continue } # canonize-path is smart enough to figure out if this is a relative path or not $projExpandedPath = Canonize-Path -base $slnDirectory -child $projExpandedPath -ignoreErrors $projectAbsolutePaths += @($projExpandedPath) } Write-Verbose-Array -array $projectAbsolutePaths -name "Resolved project paths for solution $slnPath" return $projectAbsolutePaths } function Get-ProjectSolution() { foreach ($slnPath in $global:slnFiles.Keys) { [string[]] $solutionProjectPaths = @(Get-SolutionProjects $slnPath) if ($solutionProjectPaths -and $solutionProjectPaths -contains $global:vcxprojPath) { return $slnPath } } return "" } Function Get-Projects() { [string[]] $projects = @() foreach ($slnPath in $global:slnFiles.Keys) { [string[]] $solutionProjects = @(Get-SolutionProjects -slnPath $slnPath) if ($solutionProjects -and $solutionProjects.Count -gt 0) { $projects += $solutionProjects } } return ($projects | Select -Unique); } Function Get-ClangIncludeDirectories( [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories ) { [string[]] $returnDirs = @() foreach ($includeDir in $includeDirectories) { $returnDirs += ("-isystem" + (Get-QuotedPath $includeDir)) } foreach ($includeDir in $additionalIncludeDirectories) { if ($aTreatAdditionalIncludesAsSystemIncludes) { $returnDirs += ("-isystem" + (Get-QuotedPath $includeDir)) } else { $returnDirs += ("-I"+ (Get-QuotedPath $includeDir)) } } return $returnDirs } Function Get-ProjectFileLanguageFlag([Parameter(Mandatory=$true)] [string] $fileFullName) { [bool] $isCpp = $true if ($fileFullName.EndsWith($kExtensionC)) { $isCpp = $false } try { [string] $compileAsVal = (Get-ProjectFileSetting -fileFullName $fileFullName -propertyName "CompileAs") [bool] $isDefault = [string]::IsNullOrWhiteSpace($compileAsVal) -or $compileAsVal -ieq "Default" if ($isDefault) { $isCpp = ! $fileFullName.EndsWith($kExtensionC) } else { $isCpp = $compileAsVal -ine $kCProjectCompile } } catch {} [string] $languageFlag = If ($isCpp) { $kClangFlagFileIsCPP } else { $kClangFlagFileIsC } return $languageFlag } Function Generate-Pch( [Parameter(Mandatory=$true)] [string] $stdafxDir , [Parameter(Mandatory=$true)] [string] $stdafxCpp , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$true)] [string] $stdafxHeaderName , [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions) { [string] $stdafxSource = (Canonize-Path -base $stdafxDir -child $stdafxHeaderName) [string] $stdafx = $stdafxSource + ".hpp" # Clients using Perforce will have their source checked-out as readonly files, so the # PCH copy would be, by-default, readonly as well, which would present problems. Make sure to remove the RO attribute. Copy-Item -LiteralPath $stdafxSource -Destination $stdafx -PassThru | Set-ItemProperty -name isreadonly -Value $false $global:FilesToDeleteWhenScriptQuits.Add($stdafx) > $null [string] $vcxprojShortName = [System.IO.Path]::GetFileNameWithoutExtension($global:vcxprojPath); [string] $stdafxPch = (Join-Path -path (Get-SourceDirectory) ` -ChildPath "$vcxprojShortName$kExtensionClangPch") Remove-Item -LiteralPath "$stdafxPch" -ErrorAction SilentlyContinue > $null $global:FilesToDeleteWhenScriptQuits.Add($stdafxPch) > $null [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $stdafxCpp) [string[]] $compilationFlags = @((Get-QuotedPath $stdafx) ,$kClangFlagMinusO ,(Get-QuotedPath $stdafxPch) ,$languageFlag ,(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) ,$kClangFlagNoUnusedArg ,$preprocessorDefinitions ) if ($kLLVMVersion -ge 11) { # this flag gets around 15% faster PCH compilation times # https://www.phoronix.com/scan.php?page=news_item&px=LLVM-Clang-11-PCH-Instant-Temp $compilationFlags += $kClangFlagFasterPch } $compilationFlags += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories # Remove empty arguments from the list because Start-Process will complain $compilationFlags = $compilationFlags | Where-Object { $_ } | Select -Unique [string] $exeToCallVerbosePath = $kClangCompiler if (![string]::IsNullOrWhiteSpace($global:llvmLocation)) { $exeToCallVerbosePath = "$($global:llvmLocation)\$exeToCallVerbosePath" } Write-Verbose "INVOKE: $exeToCallVerbosePath $compilationFlags" $kClangWorkingDir = "$(Get-SourceDirectory)" -replace '\[', '`[' -replace ']', '`]' # We could skip the WorkingDir parameter as all paths are absolute but # Powershell 3-5 has a bug when calling Start-Process from a directory containing square brackets # in its path. This can be overcome by providing escaped brackets in the WorkingDirectory arg. # Powershell 7 does not have this limitation. [System.Diagnostics.Process] $processInfo = Start-Process -FilePath $kClangCompiler ` -ArgumentList $compilationFlags ` -WorkingDirectory $kClangWorkingDir ` -NoNewWindow ` -Wait ` -PassThru if (($processInfo.ExitCode -ne 0) -and (!$aContinueOnError)) { Fail-Script "Errors encountered during PCH creation" } if (Test-Path -LiteralPath $stdafxPch) { return $stdafxPch } else { return "" } } Function Get-ExeToCall([Parameter(Mandatory=$true)][WorkloadType] $workloadType) { switch ($workloadType) { "Compile" { return $kClangCompiler } "Tidy" { return $kClangTidy } "TidyFix" { return $kClangTidy } } } Function Get-CompileCallArguments( [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$true)][string] $fileToCompile) { [string[]] $projectCompileArgs = @() if (! [string]::IsNullOrEmpty($pchFilePath) -and ! $fileToCompile.EndsWith($kExtensionC)) { $projectCompileArgs += @($kClangFlagIncludePch , (Get-QuotedPath $pchFilePath)) } [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $fileToCompile) $projectCompileArgs += @( $languageFlag , (Get-QuotedPath $fileToCompile) , @(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) , $kClangFlagSupressLINK , $preprocessorDefinitions ) $projectCompileArgs += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories if ($forceIncludeFiles) { $projectCompileArgs += $kClangFlagNoMsInclude; foreach ($file in $forceIncludeFiles) { $projectCompileArgs += "$kClangFlagForceInclude $(Get-QuotedPath $file)" } } return $projectCompileArgs } Function Get-TidyCallArguments( [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$true)][string] $fileToTidy , [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$false)][switch] $fix , [Parameter(Mandatory=$false)][string] $compilationDatabaseDir) { [string[]] $tidyArgs = @() if ($fix) { # Map tidy-fix replacements temprorary file path to original file path if(![string]::IsNullOrEmpty($fileToTidy)) { [string] $tidyFixReplacementYamlPath = Join-Path -Path ($global:tidyFixReplacementDirPath) ` -ChildPath ([guid]::NewGuid().ToString() + $kExtensionYaml) $tidyArgs += $kClangTidyFixExportFixes + @((Get-QuotedPath $tidyFixReplacementYamlPath)) } } $tidyArgs += (Get-QuotedPath $fileToTidy) if (![string]::IsNullOrWhiteSpace($aTidyFlags) -and ($aTidyFlags -ne $kClangTidyUseFile) -and !(Test-Path $aTidyFlags)) { $tidyArgs += "$kClangTidyFlagChecks`"$aTidyFlags`"" } if (![string]::IsNullOrWhiteSpace($aTidyFixFlags) -and ($aTidyFixFlags -ne $kClangTidyUseFile) -and !(Test-Path $aTidyFixFlags)) { $tidyArgs += "$kClangTidyFlagChecks`"$aTidyFixFlags`"" } # The header-filter flag enables clang-tidy to run on headers too. if (![string]::IsNullOrEmpty($aTidyHeaderFilter)) { if ($aTidyHeaderFilter -eq '_') { [string] $fileNameMatch = """$(Get-FileName -path $fileToTidy -noext).*""" $tidyArgs += "$kClangTidyFlagHeaderFilter$fileNameMatch" } else { $tidyArgs += "$kClangTidyFlagHeaderFilter""$aTidyHeaderFilter""" } } $tidyArgs += $kQuiet if (![string]::IsNullOrEmpty($compilationDatabaseDir)) { if ($compilationDatabaseDir -eq '_') { $compilationDatabaseDir = Get-SourceDirectory } # When passed to cmd.exe the quote cannot be preceded by a backslash or it's escaped $tidyArgs += "$kClangTidyCompilationDatabaseDir`"$($compilationDatabaseDir.TrimEnd("\"))`"" # When we use compilation database, we don't need to add further args with # compilation flags return $tidyArgs } $tidyArgs += $kEndOptionMarker $tidyArgs += Get-ClangIncludeDirectories -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories [string] $languageFlag = (Get-ProjectFileLanguageFlag -fileFullName $fileToTidy) # We reuse flags used for compilation and preprocessor definitions. $tidyArgs += @(Get-ClangCompileFlags -isCpp ($languageFlag -ieq $kClangFlagFileIsCPP)) $tidyArgs += $preprocessorDefinitions $tidyArgs += $languageFlag if (! [string]::IsNullOrEmpty($pchFilePath) -and ! $fileToTidy.EndsWith($kExtensionC)) { $tidyArgs += @($kClangFlagIncludePch , (Get-QuotedPath $pchFilePath)) } if ($forceIncludeFiles) { $tidyArgs += $kClangFlagNoMsInclude; foreach ($file in $forceIncludeFiles) { $tidyArgs += "$kClangFlagForceInclude $file" } } return $tidyArgs } Function Get-ExeCallArguments( [Parameter(Mandatory=$false)][string] $pchFilePath , [Parameter(Mandatory=$false)][string[]] $includeDirectories , [Parameter(Mandatory=$false)][string[]] $additionalIncludeDirectories , [Parameter(Mandatory=$false)][string[]] $preprocessorDefinitions , [Parameter(Mandatory=$false)][string[]] $forceIncludeFiles , [Parameter(Mandatory=$true) ][string] $currentFile , [Parameter(Mandatory=$true) ][WorkloadType] $workloadType , [Parameter(Mandatory=$false)][string] $compilationDatabaseDir) { switch ($workloadType) { Compile { return Get-CompileCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToCompile $currentFile } Tidy { return Get-TidyCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToTidy $currentFile ` -compilationDatabaseDir $compilationDatabaseDir} TidyFix { return Get-TidyCallArguments -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -forceIncludeFiles $forceIncludeFiles ` -pchFilePath $pchFilePath ` -fileToTidy $currentFile ` -compilationDatabaseDir $compilationDatabaseDir ` -fix} } } Function Process-ProjectResult($compileResult) { $global:cptCurrentClangJobCounter = $compileResult.JobCounter Write-Debug "Receiving results for clang job $($global:cptCurrentClangJobCounter)" if (!$compileResult.Success) { Write-Err ($compileResult.Output) if (!$aContinueOnError) { # Wait for other workers to finish. They have a lock on the PCH file Get-Job -state Running | Wait-Job | Remove-Job > $null Fail-Script } $global:FoundErrors = $true } else { if ( $compileResult.Output.Length -gt 0) { Write-Output $compileResult.Output } } } Function Wait-AndProcessBuildJobs([switch]$any) { $runningJobs = @(Get-Job -state Running) if ($any) { $runningJobs | Wait-Job -Any > $null } else { $runningJobs | Wait-Job > $null } $jobData = Get-Job -State Completed foreach ($job in $jobData) { $buildResult = Receive-Job $job Process-ProjectResult -compileResult $buildResult } Remove-Job -State Completed } Function Wait-ForWorkerJobSlot() { # We allow as many background workers as we have logical CPU cores $runningJobs = @(Get-Job -State Running) if ($runningJobs.Count -ge $kLogicalCoreCount) { Wait-AndProcessBuildJobs -any } } Function Run-ClangJobs( [Parameter(Mandatory=$true)] $clangJobs , [Parameter(Mandatory=$true)][WorkloadType] $workloadType ) { # Script block (lambda) for logic to be used when running a clang job. $jobWorkToBeDone = ` { param( $job ) Push-Location -LiteralPath $job.WorkingDirectory # This temp file will hold compilation args for clang++ and clang-tidy, not to be # confused with check-flags for clang-tidy. [string] $clangConfigFile = [System.IO.Path]::GetTempFileName() [string] $clangConfigContent = "" if ($job.FilePath -like '*tidy*') { if (!($job.ArgumentList -like "$($job.kClangTidyCompilationDatabaseDir)*")) { # We have to separate Clang args from Tidy args $splitparams = $job.ArgumentList -split " -- " $clangConfigContent = $splitparams[1] # We may have an explicit .clang-tidy check-flag config file to be used if (![string]::IsNullOrWhiteSpace($job.TidyFlagsTempFile) -and (Test-Path -LiteralPath $job.TidyFlagsTempFile)) { $splitparams[0] += " --config-file=""$($job.TidyFlagsTempFile)"" " } $job.ArgumentList = "$($splitparams[0]) -- --config ""$clangConfigFile""" } } else { # Tell Clang to take its compilation args from a config file $clangConfigContent = $job.ArgumentList $job.ArgumentList = "--config ""$clangConfigFile""" } # escape slashes for file paths # make sure escaped double quotes are not messed up $clangConfigContent = $clangConfigContent -replace '\\([^"])', '\\$1' # save compilation arguments to clang config file $clangConfigContent > $clangConfigFile # When PowerShell encounters errors, the first one is handled differently from consecutive ones # To circumvent this, do not execute the job directly, but execute it via cmd.exe # See also https://stackoverflow.com/a/35980675 $callOutput = cmd /c "$($job.FilePath) $($job.ArgumentList) 2>&1" | Out-String $callSuccess = $LASTEXITCODE -eq 0 if (!$callSuccess) { } Remove-Item $clangConfigFile Pop-Location return New-Object PsObject -Prop @{ "File" = $job.File ; "Success" = $callSuccess ; "Output" = $callOutput ; "JobCounter" = $job.JobCounter } } if (!$aResumeAfterError) { $global:cptCurrentClangJobCounter = $clangJobs.Count } else { if (!(VariableExists 'cptCurrentClangJobCounter')) { Write-Warning "Can't resume. Previous state is unreliable. Processing all files..." $global:cptCurrentClangJobCounter = $clangJobs.Count } else { if ($global:cptCurrentClangJobCounter -gt 0) { Write-Output "Resuming from file #$($global:cptCurrentClangJobCounter)" } } } [int] $crtJobCount = $clangJobs.Count foreach ($job in $clangJobs) { if ($global:cptCurrentClangJobCounter -ge 0 -and $crtJobCount -gt $global:cptCurrentClangJobCounter) { $crtJobCount-- continue } $job.JobCounter = $crtJobCount # Check if we must wait for background jobs to complete Wait-ForWorkerJobSlot # Inform console what CPP we are processing next Write-Output "$($crtJobCount): $($job.File)" if ($aUseParallelCompile) { Start-Job -ScriptBlock $jobWorkToBeDone ` -ArgumentList $job ` -ErrorAction Continue > $null } else { $compileResult = Invoke-Command -ScriptBlock $jobWorkToBeDone ` -ArgumentList $job Process-ProjectResult -compileResult $compileResult $global:cptCurrentClangJobCounter = $compileResult.JobCounter } $crtJobCount -= 1 } Wait-AndProcessBuildJobs $global:cptCurrentClangJobCounter = -1 # stop the mechanism after one project } Function Get-ProjectFileSetting( [Parameter(Mandatory=$true)] [string] $fileFullName , [Parameter(Mandatory=$true)] [string] $propertyName , [Parameter(Mandatory=$false)][string] $defaultValue) { if (!$global:cptFilesToProcess.ContainsKey($fileFullName)) { throw "File $aFileFullName is not in processing queue." } if ($global:cptFilesToProcess[$fileFullName].Properties -and $global:cptFilesToProcess[$fileFullName].Properties.ContainsKey($propertyName)) { return $global:cptFilesToProcess[$fileFullName].Properties[$propertyName] } if ($defaultValue -ne $null) { return $defaultValue } throw "Could not find $propertyName for $fileFullName. No default value specified." } Function Process-Project( [Parameter(Mandatory=$true)] [string] $vcxprojPath , [Parameter(Mandatory=$true)] [WorkloadType] $workloadType , [Parameter(Mandatory=$false)][string] $platformConfig ) { #----------------------------------------------------------------------------------------------- $global:cptCurrentConfigPlatform = $platformConfig $projCounter = $global:cptProjectCounter [string] $projectOutputString = ("PROJECT$(if ($projCounter -gt 1) { " #$projCounter" } else { } ): " + $vcxprojPath) [bool] $loadedFromCache = $false try { Set-Variable 'kCacheRepositorySaveIsNeeded' -value $false Write-InformationTimed "Before project load" if (Is-CacheLoadingEnabled) { Write-InformationTimed "Trying to load project from cache" $loadedFromCache = Load-ProjectFromCache $vcxprojPath if (!$loadedFromCache) { LoadProject $vcxprojPath Set-Variable 'kCacheRepositorySaveIsNeeded' -value $true } } else { LoadProject $vcxprojPath } Write-InformationTimed "After project load" Write-Output "$projectOutputString [$($global:cptCurrentConfigPlatform)]" } catch [ProjectConfigurationNotFound] { [string] $configPlatform = ([ProjectConfigurationNotFound]$_.Exception).ConfigPlatform Write-Output "$projectOutputString [$($global:cptCurrentConfigPlatform)]" Write-Output ("Skipped. Configuration not present: " + $configPlatform); Pop-Location return } Write-InformationTimed "Detecting toolset" #----------------------------------------------------------------------------------------------- # DETECT PLATFORM TOOLSET if (! $loadedFromCache) { [string] $global:platformToolset = Get-ProjectPlatformToolset Write-Verbose "Platform toolset: $platformToolset" Add-ToProjectSpecificVariables 'platformToolset' if ( $platformToolset -match "^v\d+(_xp)?$" ) { [int] $toolsetVersion = [int]$platformToolset.Remove(0, 1).Replace("_xp", "") [string] $desiredVisualStudioVer = "" # toolsets attached to specific Visual Studio versions if ($toolsetVersion -le 120) { $desiredVisualStudioVer = "2013" } elseif ($toolsetVersion -eq 140) { $desiredVisualStudioVer = "2015" } elseif ($toolsetVersion -eq 141) { $desiredVisualStudioVer = "2017" } elseif ($toolsetVersion -eq 142) { $desiredVisualStudioVer = "2019"; } elseif ($toolsetVersion -eq 143) { $desiredVisualStudioVer = "2022"; } elseif ($toolsetVersion -eq 145) { $desiredVisualStudioVer = "2026"; } [string] $desiredVisualStudioVerNumber = (Get-VisualStudio-VersionNumber $desiredVisualStudioVer) if ($VisualStudioVersion -ne $desiredVisualStudioVerNumber) { [bool] $shouldReload = $false if ([double]::Parse($VisualStudioVersion) -gt [double]::Parse($desiredVisualStudioVerNumber)) { # in this case we may have a newer Visual Studio with older toolsets installed [string[]] $supportedVsToolsets = Get-VisualStudioToolsets if ($supportedVsToolsets -notcontains $toolsetVersion) { $shouldReload = $true } else { Write-Verbose "[ INFO ] Detected project using older toolset ($toolsetVersion)" Write-Verbose "Loading using Visual Studio $VisualStudioVersion with toolset $toolsetVersion" } } else { # project uses a newer VS version, clearly we should reload using the newer version $shouldReload = $true } if ($shouldReload) { # We need to reload everything and use the VS version we decided upon above Write-Verbose "[ RELOAD ] Project will reload because of toolset requirements change..." Write-Verbose "Current = $VisualStudioVersion. Required = $desiredVisualStudioVerNumber." $global:cptVisualStudioVersion = $desiredVisualStudioVer LoadProject($vcxprojPath) Write-InformationTimed "Project reloaded" } } } Write-InformationTimed "Detected toolset" #----------------------------------------------------------------------------------------------- # FIND FORCE INCLUDES [string[]] $global:forceIncludeFiles = @(Get-ProjectForceIncludes) Write-Verbose-Array -array $forceIncludeFiles -name "Force includes" Add-ToProjectSpecificVariables 'forceIncludeFiles' #----------------------------------------------------------------------------------------------- # DETECT PROJECT PREPROCESSOR DEFINITIONS [string[]] $global:preprocessorDefinitions = @(Get-ProjectPreprocessorDefines) if ([int]$global:cptVisualStudioVersion -ge 2017) { # [HACK] pch generation crashes on VS 15.5 because of STL library, known bug. # Triggered by addition of line directives to improve std::function debugging. # There's a definition that supresses line directives. $preprocessorDefinitions += @('"-D_DEBUG_FUNCTIONAL_MACHINERY"') } Add-ToProjectSpecificVariables 'preprocessorDefinitions' Write-InformationTimed "Detected preprocessor definitions" Write-Verbose-Array -array $preprocessorDefinitions -name "Preprocessor definitions" #----------------------------------------------------------------------------------------------- # DETECT PROJECT ADDITIONAL INCLUDE DIRECTORIES AND CONSTRUCT INCLUDE PATHS [string[]] $global:additionalIncludeDirectories = @(Get-ProjectAdditionalIncludes) Write-Verbose-Array -array $additionalIncludeDirectories -name "Additional include directories" Add-ToProjectSpecificVariables 'additionalIncludeDirectories' [string[]] $includeDirectories = @(Get-ProjectIncludeDirectories) # We use the same mechanism for injecting external include paths $includeDirectories += @(Get-IncludePathsFromAdditionalOptions) $includeDirectories += @(Get-ProjectExternalIncludePaths) Write-Verbose-Array -array $includeDirectories -name "Include directories" Add-ToProjectSpecificVariables 'includeDirectories' Write-InformationTimed "Detected include directories" #----------------------------------------------------------------------------------------------- # FIND LIST OF CPPs TO PROCESS $global:projectAllCpps = @{} foreach ($fileToCompileInfo in (Get-ProjectFilesToCompile)) { if ($fileToCompileInfo.File) { $global:projectAllCpps[$fileToCompileInfo.File] = $fileToCompileInfo } } Add-ToProjectSpecificVariables 'projectAllCpps' Write-InformationTimed "Detected cpps to process" } # past the caching boundary here, we must see what else needs to be computed live $global:cptFilesToProcess = $global:projectAllCpps # reset to full project cpp list #----------------------------------------------------------------------------------------------- # LOCATE STDAFX.H DIRECTORY [string] $stdafxCpp = "" [string] $stdafxDir = "" [string] $stdafxHeader = "" [string] $stdafxHeaderFullPath = "" [int] $minTranslationUnitsForPCH = If (Test-Path env:CPT_PCH_LIMIT) { [int]$env:CPT_PCH_LIMIT } else { 2 } [bool] $kPchIsNeeded = $global:cptFilesToProcess.Keys.Count -ge $minTranslationUnitsForPCH if ($kPchIsNeeded) { # if we have only one rooted file in the script parameters, then we don't need to detect PCH if ($aCppToCompile.Count -eq 1 -and [System.IO.Path]::IsPathRooted($aCppToCompile[0])) { $kPchIsNeeded = $false } } foreach ($projCpp in $global:cptFilesToProcess.Keys) { if ( (Get-ProjectFileSetting -fileFullName $projCpp -propertyName 'PrecompiledHeader') -ieq 'Create') { $stdafxCpp = $projCpp } } if (![string]::IsNullOrEmpty($stdafxCpp)) { Write-Verbose "PCH cpp name: $stdafxCpp" if ($forceIncludeFiles.Count -gt 0) { $stdafxHeader = $forceIncludeFiles[0] } if (!$stdafxHeader) { $stdafxHeader = Get-PchCppIncludeHeader -pchCppFile $stdafxCpp } if (!$stdafxHeader) { try { $stdafxHeader = Get-ProjectFileSetting -fileFullName $stdafxCpp -propertyName 'PrecompiledHeaderFile' } catch {} } Write-Verbose "PCH header name: $stdafxHeader" $stdafxDir = Get-ProjectStdafxDir -pchHeaderName $stdafxHeader ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories } if ([string]::IsNullOrEmpty($stdafxDir)) { Write-Verbose ("No PCH information for this project!") $kPchIsNeeded = $false } else { Write-Verbose ("PCH directory: $stdafxDir") $includeDirectories = @(Remove-PathTrailingSlash -path $stdafxDir) + $includeDirectories $stdafxHeaderFullPath = Canonize-Path -base $stdafxDir -child $stdafxHeader -ignoreErrors if (!$kPchIsNeeded) { Write-Verbose "PCH is disabled for this project. Will not generate." } } Write-InformationTimed "Detected PCH information" #----------------------------------------------------------------------------------------------- # FILTER LIST OF CPPs TO PROCESS if ($global:cptFilesToProcess.Count -gt 0 -and $aCppToIgnore.Count -gt 0) { [System.Collections.Hashtable] $filteredCpps = @{} foreach ($cpp in $global:cptFilesToProcess.Keys) { if ( ! (Should-IgnoreFile -file $cpp) ) { $filteredCpps[$cpp] = $global:cptFilesToProcess[$cpp] } } $global:cptFilesToProcess = $filteredCpps } if ($global:cptFilesToProcess.Count -gt 0 -and $aCppToCompile.Count -gt 0) { [System.Collections.Hashtable] $filteredCpps = @{} [bool] $dirtyStdafx = $false foreach ($cpp in $aCppToCompile) { if ($cpp -ieq $stdafxHeaderFullPath) { # stdafx modified => compile all $dirtyStdafx = $true break } if (![string]::IsNullOrEmpty($cpp)) { if ([System.IO.Path]::IsPathRooted($cpp)) { if ($global:cptFilesToProcess.ContainsKey($cpp)) { # really fast, use cache $filteredCpps[$cpp] = $global:cptFilesToProcess[$cpp] } } else { # take the slow road and check if it matches $global:cptFilesToProcess.Keys | Where-Object { IsFileMatchingName -filePath $_ -matchName $cpp } | ` ForEach-Object { $filteredCpps[$_] = $global:cptFilesToProcess[$_] } } } } if (!$dirtyStdafx) { $global:cptFilesToProcess = $filteredCpps } else { Write-Verbose "PCH header has been targeted as dirty. Building entire project" } } Write-InformationTimed "Filtered out CPPs from bucket" Write-Verbose ("Processing " + $global:cptFilesToProcess.Count + " cpps") #----------------------------------------------------------------------------------------------- # CREATE PCH IF NEED BE, ONLY FOR TWO CPPS OR MORE # # JSON Compilation Database file will outlive this execution run, while the PCH is temporary # so we disable PCH creation for that case as well. if ($kPchIsNeeded -and $global:cptFilesToProcess.Count -lt $minTranslationUnitsForPCH) { $kPchIsNeeded = $false } [string] $pchFilePath = "" if ($kPchIsNeeded -and !$aExportJsonDB) { # COMPILE PCH Write-Verbose "Generating PCH..." $pchFilePath = Generate-Pch -stdafxDir $stdafxDir ` -stdafxCpp $stdafxCpp ` -stdafxHeaderName $stdafxHeader ` -preprocessorDefinitions $preprocessorDefinitions ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories Write-Verbose "PCH: $pchFilePath" if ([string]::IsNullOrEmpty($pchFilePath) -and $aContinueOnError) { Write-Output "Skipping project. Reason: cannot create PCH." return } Write-InformationTimed "Created PCH" } if ($kCacheRepositorySaveIsNeeded) { Write-InformationTimed "Before serializing project" Save-ProjectToCacheRepo Write-InformationTimed "After serializing project" } #----------------------------------------------------------------------------------------------- # PROCESS CPP FILES. CONSTRUCT COMMAND LINE JOBS TO BE INVOKED $clangJobs = @() # Create directory where to store tidy fix replacements if ($aTidyFixFlags) { $global:tidyFixReplacementDirPath = (Join-Path -path $kCptTidyFixReplacementsDir ` -ChildPath (Split-Path (Get-SourceDirectory) -Leaf)) ` + "_" + ([guid]::NewGuid().ToString()) # check if SolutionDir for tidy fix replacements already exists if (Test-Path -LiteralPath $global:tidyFixReplacementDirPath) { Remove-Item $global:tidyFixReplacementDirPath -Recurse New-Item -Path $global:tidyFixReplacementDirPath -ItemType "directory" > $null } else { New-Item -Path $global:tidyFixReplacementDirPath -ItemType "directory" > $null } } foreach ($cpp in $global:cptFilesToProcess.Keys) { [string] $cppPchSetting = Get-ProjectFileSetting -propertyName 'PrecompiledHeader' -fileFullName $cpp -defaultValue 'Use' if ($cppPchSetting -ieq 'Create') { continue # no point in compiling the PCH CPP } [string[]] $cppForceIncludes = Get-FileForceIncludes -fileFullName $cpp [string] $exeToCall = Get-ExeToCall -workloadType $workloadType [string] $finalPchPath = $pchFilePath if ($cppPchSetting -ieq 'NotUsing') { $finalPchPath = "" Write-Verbose "`n[PCH] Will ignore precompiled headers for $cpp`n" } [string] $exeArgs = Get-ExeCallArguments -workloadType $workloadType ` -pchFilePath $finalPchPath ` -preprocessorDefinitions $preprocessorDefinitions ` -forceIncludeFiles $cppForceIncludes ` -currentFile $cpp ` -includeDirectories $includeDirectories ` -additionalIncludeDirectories $additionalIncludeDirectories ` -compilationDatabaseDir $aCompilationDatabaseDir $newJob = New-Object PsObject -Prop @{ 'FilePath' = $exeToCall ; 'WorkingDirectory' = Get-SourceDirectory ; 'ArgumentList' = $exeArgs ; 'File' = $cpp ; 'JobCounter' = 0 <# will be lazy initialized #> ; 'TidyFlagsTempFile' = $kClangTidyFlagTempFile ; 'kClangTidyCompilationDatabaseDir' = $kClangTidyCompilationDatabaseDir } $clangJobs += $newJob } Write-InformationTimed "Created job workers" #----------------------------------------------------------------------------------------------- # PRINT DIAGNOSTICS if ($clangJobs.Count -ge 1) { [string] $exeToCallVerbosePath = $exeToCall if (![string]::IsNullOrWhiteSpace($global:llvmLocation)) { $exeToCallVerbosePath = "$($global:llvmLocation)\$exeToCallVerbosePath" } Write-Verbose "INVOKE: $exeToCallVerbosePath $($clangJobs[0].ArgumentList)" } Write-InformationTimed "Running workers" #----------------------------------------------------------------------------------------------- # RUN CLANG JOBS if ($aExportJsonDB) { foreach ($job in $clangJobs) { [string] $clangToolPath = $job.FilePath if (Exists-Command $clangToolPath) { # see precisely what path the tool has, to prevent ambiguities. $clangToolPath = (Get-Command $job.FilePath).Source } [string] $clangCommand = """$clangToolPath"" $($job.ArgumentList)" JsonDB-Push -directory $job.WorkingDirectory -file $job.File -command $clangCommand } } else { Run-ClangJobs -clangJobs $clangJobs -workloadType $workloadType Apply-TidyFixReplacements -workloadType $workloadType } } #------------------------------------------------------------------------------------------------- # If we didn't get a location to run CPT at, use the current working directory if (!$aSolutionsPath) { $aSolutionsPath = (Get-Location).Path } # ------------------------------------------------------------------------------------------------ # Load param values from configuration file (if exists) Update-ParametersFromConfigFile Write-InformationTimed "Updated script parameters from cpt.config" # ------------------------------------------------------------------------------------------------ # Initialize the Visual Studio version variable $global:cptVisualStudioVersion = If ( $aVisualStudioVersion ) ` { $aVisualStudioVersion } Else ` { $global:cptDefaultVisualStudioVersion } #------------------------------------------------------------------------------------------------- # Print script parameters Print-InvocationArguments Write-InformationTimed "Print args" [WorkloadType] $workloadType = [WorkloadType]::Compile if (![string]::IsNullOrEmpty($aTidyFlags)) { $workloadType = [WorkloadType]::Tidy if (Test-Path -LiteralPath $aTidyFlags) { $kClangTidyFlagTempFile = $aTidyFlags } } if (![string]::IsNullOrEmpty($aTidyFixFlags)) { $workloadType = [WorkloadType]::TidyFix if (Test-Path -LiteralPath $aTidyFixFlags) { $kClangTidyFlagTempFile = $aTidyFixFlags } } #------------------------------------------------------------------------------------------------- # Script entry point Write-Verbose "CPU logical core count: $kLogicalCoreCount" # If LLVM is not in PATH try to detect it automatically [string] $global:llvmLocation = "" $clangToolWeNeed = Get-ExeToCall -workloadType $workloadType $global:llvmLocation = Ensure-LLVMTool-IsPresent $clangToolWeNeed if ($aTidyFixFlags) { Ensure-LLVMTool-IsPresent $kClangApplyReplacements } if (![string]::IsNullOrEmpty($global:llvmLocation)) { $env:Path += ";" + $global:llvmLocation } Set-Variable -name "kLLVMVersion" -value (Get-ClangVersion $clangToolWeNeed) -scope Global # initialize JSON compilation db support, if required if ($aExportJsonDB) { JsonDB-Init } Push-Location -LiteralPath (Get-SourceDirectory) Write-InformationTimed "Searching for solutions" # fetch .sln paths and data Load-Solutions Write-InformationTimed "End solution search" # This PowerShell process may already have completed jobs. Discard them. Remove-Job -State Completed Write-InformationTimed "Discarded already finished jobs" Write-Verbose "Source directory: $(Get-SourceDirectory)" Write-Verbose "Scanning for project files" Write-InformationTimed "Searching for project files" [System.IO.FileInfo[]] $projects = @(Get-Projects) [int] $initialProjectCount = $projects.Count Write-Verbose ("Found $($projects.Count) projects") Write-InformationTimed "End project files search" # ------------------------------------------------------------------------------------------------ # If we get headers in the -file arg we have to detect CPPs that include that header if ($aCppToCompile -and $aCppToCompile.Count -gt 0) { # We've been given particular files to compile. If headers are among them # we'll find all source files that include them and tag them for processing. Write-Progress -Activity "#Include discovery" -Status "Detecting CPPs which include the specified headers..." [string[]] $headerRefs = @(Get-HeaderReferences -files $aCppToCompile) Write-Progress -Activity "#Include discovery" -Completed if ($headerRefs.Count -gt 0) { Write-Verbose-Array -name "Detected referenced source files to process" -array $headerRefs $aCppToCompile += @($headerRefs | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } } if ($aCppToIgnore -and $aCppToIgnore.Count -gt 0) { # We've been given particular files to ignore. If headers are among them # we'll find all source files that include them and tag them to be ignored. Write-Progress -Activity "CPP Ignore Detection" -Status "Detecting CPPs which include the specified ignore-headers..." [string[]] $headerRefs = @(Get-HeaderReferences -files $aCppToIgnore) Write-Progress -Activity "CPP Ignore Detection" -Completed if ($headerRefs.Count -gt 0) { Write-Verbose-Array -name "Detected referenced source files to ignore" -array $headerRefs $global:cptIgnoredFilesPool += @($headerRefs | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } } # ------------------------------------------------------------------------------------------------ Write-InformationTimed "Starting projects" [System.IO.FileInfo[]] $projectsToProcess = @() [System.IO.FileInfo[]] $ignoredProjects = @() if (!$aVcxprojToCompile -and !$aVcxprojToIgnore) { $projectsToProcess = $projects # we process all projects } else { # some filtering has to be done if ($aVcxprojToCompile) { $projects = $projects | Where-Object { Should-CompileProject -vcxprojPath $_.FullName } $projectsToProcess = @($projects) } if ($aVcxprojToIgnore) { $projectsToProcess = @($projects | ` Where-Object { !(Should-IgnoreProject -vcxprojPath $_.FullName ) }) $ignoredProjects = ($projects | Where-Object { $projectsToProcess -notcontains $_ }) } } if ($projectsToProcess.Count -eq 0) { Write-Err "Cannot find given project(s)" } if ($aCppToCompile -and $projectsToProcess.Count -gt 1) { # We've been given particular files to compile, we can narrow down # the projects to be processed (those that include any of the particular files) # For obvious performance reasons, no filtering is done when there's only one project to process. [System.IO.FileInfo[]] $projectsThatIncludeFiles = @(Get-SourceCodeIncludeProjects -projectPool $projectsToProcess ` -files $aCppToCompile) Write-Verbose-Array -name "Detected projects" -array $projectsThatIncludeFiles # some projects include files using wildcards, we won't match anything in them # so when matching nothing we don't do filtering at all if ($projectsThatIncludeFiles) { $projectsToProcess = $projectsThatIncludeFiles } } if ($projectsToProcess.Count -eq $initialProjectCount) { Write-Verbose "PROCESSING ALL PROJECTS" } else { if ($projectsToProcess.Count -gt 1) { Write-Array -name "PROJECTS" -array $projectsToProcess } if ($ignoredProjects) { Write-Array -name "IGNORED PROJECTS" -array $ignoredProjects } } # ------------------------------------------------------------------------------------------------ if (!$aResumeAfterError) { $global:cptProjectCounter = $projectsToProcess.Length } else { if (!(VariableExists 'cptProjectCounter') -or !(VariableExists 'cptProjectsBucket')) { Write-Warning "Can't resume. Previous state is unreliable. Processing all projects..." $global:cptProjectCounter = $projectsToProcess.Length } elseif ((Compare-Object $projectsToProcess $global:cptProjectsBucket)) { Write-Warning "Can't resume. Previous state is unreliable. Processing all projects...`n`nREMINDER: Don't change arguments when adding -resume.`n`n" $global:cptProjectCounter = $projectsToProcess.Length } else { Write-Output "Resuming from project #$($global:cptProjectCounter)" } } [System.IO.FileInfo[]] $global:cptProjectsBucket = $projectsToProcess [int] $localProjectCounter = $projectsToProcess.Length; foreach ($project in $projectsToProcess) { if ($localProjectCounter -gt $global:cptProjectCounter) { $localProjectCounter--; continue } [string] $vcxprojPath = $project.FullName; [string[]] $configPlatforms = $aVcxprojConfigPlatform if ($configPlatforms.Count -eq 0) { $configPlatforms += @("") } foreach ($crtPlatformConfig in $configPlatforms) { Write-InformationTimed "Before project process" Process-Project -vcxprojPath $vcxprojPath -workloadType $workloadType -platformConfig $crtPlatformConfig Write-InformationTimed "After project process" Write-Output "" # empty line separator } $localProjectCounter -= 1 $global:cptProjectCounter = $localProjectCounter } if ($aExportJsonDB) { JsonDB-Finalize } Write-InformationTimed "Goodbye" if ($global:FoundErrors) { Fail-Script } else { Exit-Script } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/get-header-references.ps1 ================================================ # line limit for scanning files for #include [int] $global:cpt_header_include_line_limit = 30 # after the line limit, if any includes are still found we # extend the limit with this value [int] $global:cpt_header_include_line_extension = 10 [string[]] $global:headerExtensions = @('h', 'hh', 'hpp', 'hxx') [string[]] $global:sourceExtensions = @('c', 'cc', 'cpp', 'cxx') Function detail:FindHeaderReferences( [Parameter(Mandatory = $false)] [string[]] $headers , [Parameter(Mandatory = $false)] [System.IO.FileInfo[]] $filePool , [Parameter(Mandatory = $false)] [System.Collections.Hashtable] $alreadyFound = @{} ) { if (!$headers) { return @() } [string] $regexHeaders = @($headers | ForEach-Object { ([System.IO.FileInfo]$_).BaseName } ` | Select-Object -Unique ` | Where-Object { $_ -ine "stdafx" -and $_ -ine "resource" } ` ) -join '|' if ($regexHeaders.Length -eq 0) { return @() } [string] $regex = "[/""]($regexHeaders)\.($($global:headerExtensions -join '|'))""" Write-Debug "Regex for header reference find: $regex`n" [string[]] $returnRefs = @() if (!$filePool) { # initialize pool of files that we look into [string[]] $allFileExts = @(($global:sourceExtensions + ` $global:headerExtensions) | ForEach-Object { "*.$_" }) $filePool = Get-ChildItem -recurse -include $allFileExts } foreach ($file in $filePool) { if ($alreadyFound.ContainsKey($file.FullName)) { continue } [int] $lineCount = 0 [int] $lineLimit = $global:cpt_header_include_line_limit foreach($line in [System.IO.File]::ReadLines($file)) { if ([string]::IsNullOrWhiteSpace($line)) { # skip empty lines continue } if ($line -match $regex) { if ( ! $alreadyFound.ContainsKey($file.FullName)) { $alreadyFound[$file.FullName] = $true $returnRefs += $file.FullName } if ($lineCount -eq $lineLimit) { # we still have includes to scan $lineLimit += $global:cpt_header_include_line_extension } } if ( (++$lineCount) -gt $lineLimit) { break } } } if ($returnRefs.Count -gt 0) { [string[]] $headersLeftToSearch = @($returnRefs | Where-Object ` { FileHasExtension -filePath $_ ` -ext $global:headerExtensions } ) if ($headersLeftToSearch.Count -gt 0) { Write-Debug "[!] Recursive reference detection in progress for: " Write-Debug ($headersLeftToSearch -join "`n") $returnRefs += detail:FindHeaderReferences -headers $headersLeftToSearch ` -filePool $filePool ` -alreadyFound $alreadyFound } } $returnRefs = $returnRefs | Select-Object -Unique Write-Debug "Found header refs (regex $regex)" Write-Debug ($returnRefs -join "`n") return $returnRefs } <# .SYNOPSIS Detects source files that reference given headers. Returns an array with full paths of files that reference the header(s). .DESCRIPTION When modifying a header, all translation units that include that header have to compiled. This function detects those files that include it. .PARAMETER files Header files of which we want references to be found Any files that are not headers will be ignored. #> Function Get-HeaderReferences([Parameter(Mandatory = $false)][string[]] $files) { if ($files.Count -eq 0) { return @() } # we take interest only in files that reference headers $files = @($files | Where-Object { FileHasExtension -filePath $_ ` -ext $global:headerExtensions }) if ($files.Count -eq 0) { return @() } [string[]] $refs = @() if ($files.Count -gt 0) { Write-Verbose-Timed "Headers changed. Detecting which source files to process..." $refs = detail:FindHeaderReferences -headers $files Write-Verbose-Timed "Finished detecting source files." $refs = $refs | Where-Object { ! [string]::IsNullOrWhiteSpace($_) } } return $refs } <# .SYNOPSIS Detects projects that reference given source files (i.e. cpps). Returns an array with full paths of detected projects. .DESCRIPTION When modifying a file, only projects that reference that file should be recompiled. .PARAMETER projectPool Projects in which to look .PARAMETER files Source files to be found in projects. #> Function Get-SourceCodeIncludeProjects([Parameter(Mandatory = $false)][System.IO.FileInfo[]] $projectPool, [Parameter(Mandatory = $false)][string[]] $files) { [System.Collections.Hashtable] $fileCache = @{} foreach ($file in $files) { if ($file) { $fileCache[$file.Trim().ToLower()] = $true } } [System.IO.FileInfo[]] $matchedProjects = @() [string] $clPrefix = '' [string] $endGroupTag = '' foreach ($proj in $projectPool) { [string] $projDir = $proj.Directory.FullName [bool] $inClIncludeSection = $false foreach($line in [System.IO.File]::ReadLines($proj.FullName)) { $line = $line.Trim() if ($line.StartsWith($clPrefix)) { if (!$inClIncludeSection) { $inClIncludeSection = $true } [string] $filePath = $line.Substring($clPrefix.Length, ` $line.Length - $clPrefix.Length - $clSuffix.Length) if (![System.IO.Path]::IsPathRooted($filePath)) { $filePath = Canonize-Path -base $projDir -child $filePath -ignoreErrors } if ([string]::IsNullOrEmpty($filePath)) { continue } [System.IO.FileInfo] $sourceFile = $filePath if ($fileCache.ContainsKey($sourceFile.FullName.Trim().ToLower()) -or ` $fileCache.ContainsKey($sourceFile.Name.Trim().ToLower())) { $matchedProjects += $proj break } } if ($inClIncludeSection -and $line -eq $endGroupTag) { # nothing more to check in this project break } } } return $matchedProjects } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/get-llvm-helper.ps1 ================================================ # This helper makes sure we have the LLVM tool we require present on disk. # If it's not available then we download it from GitHub. # REQUIRES "io.ps1" to be included # ------------------------------------------------------------------------------------------------ # Default install locations of LLVM. If present there, we automatically use it Set-Variable -name kLLVMInstallLocations -value @("${Env:ProgramW6432}\LLVM\bin" ,"${Env:ProgramFiles(x86)}\LLVM\bin" ) -option Constant #Url to assets (clang++ and clang-tidy) from previous release made by Clang Power Tools on github Set-Variable -name kCptGithubLlvm -value "https://github.com/Caphyon/clang-power-tools/releases/download/v2025.8.0" ` -option Constant Set-Variable -name kCptGithubLlvmVersion -value "21.1.6 (LLVM 21.1.6)" -Option Constant # Clang Constants Set-Variable -name kCss -value "clang-doc-default-stylesheet.css" -option Constant Set-Variable -name kClangDoc -value "clang-doc.exe" -option Constant Set-Variable -name kIndex -value "index.js" -option Constant Function Move-Tool-To-LlvmBin([Parameter(Mandatory = $true)][string] $clangToolWeNeed, [Parameter(Mandatory = $true)][string] $llvmLiteBinDir) { $llvmLiteDir = (get-item $llvmLiteBinDir).Parent.FullName if(Test-Path "$llvmLiteDir\$clangToolWeNeed") { Move-Item -Path "$llvmLiteDir\$clangToolWeNeed" -Destination "$llvmLiteBinDir\$clangToolWeNeed" } } Function Ensure-LLVMTool-IsPresent([Parameter(Mandatory = $true)][string] $clangToolWeNeed) { [string] $ret = "" # see if we can reach the tool through PATH if (Exists-Command $clangToolWeNeed ) { [System.IO.FileInfo] $toolPath = (Get-Command $clangToolWeNeed).Source return $toolPath.Directory.FullName } # search in predefined locations foreach ($locationLLVM in $kLLVMInstallLocations) { if (Test-Path -LiteralPath "$locationLLVM\$clangToolWeNeed") { return $locationLLVM } } # download read-to-use binary from github [string] $llvmLiteDirParent = "${env:APPDATA}\ClangPowerTools" [string] $llvmLiteDir = "$llvmLiteDirParent\LLVM_Lite\Bin" [string] $llvmLiteToolPath = "$llvmLiteDir\$clangToolWeNeed" if (Test-Path $llvmLiteToolPath) { $versionPresent = (Get-Item $llvmLiteToolPath).VersionInfo.ProductVersion if ($versionPresent -eq $kCptGithubLlvmVersion) { # we already have downloaded the latest standalone tool, reuse it return $llvmLiteDir } } if (Test-InternetConnectivity) { if ([string]::IsNullOrEmpty($ret)) { if (!(Test-Path $llvmLiteDirParent)) { New-Item -Path $llvmLiteDirParent -ItemType Directory | Out-Null } if (!(Test-Path $llvmLiteDir)) { New-Item -Path $llvmLiteDir -ItemType Directory | Out-Null } # check if tool already exists Llvm_lite folder, to move it in Llvm_lite/bin Move-Tool-To-LlvmBin $clangToolWeNeed $llvmLiteDir # the displayed progress slows downloads considerably, so disable it $prevPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' [string] $clangCompilerWebPath = "$kCptGithubLlvm/$clangToolWeNeed" if (Test-Path $llvmLiteToolPath) { # we have an older version downloaded, remove it first Remove-Item $llvmLiteToolPath -Force } Write-Verbose "Downloading $clangToolWeNeed $kCptGithubLlvmVersion ..." # grab ready-to-use LLVM binaries from Github Invoke-WebRequest -Uri $clangCompilerWebPath -OutFile $llvmLiteToolPath # download css file if needed tool is clang-doc.exe if($clangToolWeNeed -eq $kClangDoc) { [string] $parentDirLite = (get-item $llvmLiteDir ).Parent.FullName [string] $llvmLiteCssFolderPath = "$parentDirLite\share\clang" if (!(Test-Path $llvmLiteCssFolderPath)) { New-Item $llvmLiteCssFolderPath -ItemType Directory | Out-Null } Invoke-WebRequest -Uri "$kCptGithubLlvm/$kCss" -OutFile "$llvmLiteCssFolderPath\$kCss" Invoke-WebRequest -Uri "$kCptGithubLlvm/$kIndex" -OutFile "$llvmLiteCssFolderPath\$kIndex" } $ProgressPreference = $prevPreference $ret = $llvmLiteDir } } return $ret } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/get-llvm.ps1 ================================================ <# .SYNOPSIS Downloads ready-to-use one or more LLVM binaries, if not already available on system. .DESCRIPTION Purpose of this script is to ensure that LLVM binaries are available for use. The strategy used, for each tool, is: * search in PATH * search in Program Files * search in %APPDATA%\ClangPowerTools\LLVM_Lite * if not found, download tool and save in LLVM_Lite location .PARAMETER aTool Alias 'tool'. The LLVM tool(s) to potentially download. .NOTES Author: Gabriel Diaconita, Marina Rusu #> #Requires -Version 3 param( [alias("tool")] [Parameter(Mandatory=$false, HelpMessage="LLVM tool(s) to ensure exist")] [string[]] $aTools = @() ) Set-StrictMode -version latest $ErrorActionPreference = 'Continue' . "$PSScriptRoot\io.ps1" . "$PSScriptRoot\get-llvm-helper.ps1" $ret = @() foreach ($tool in $aTools) { [string] $toolLocation = Ensure-LLVMTool-IsPresent $tool $ret += @($toolLocation) } Write-Output $ret ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/integration-project.tests.ps1 ================================================ BeforeAll { @( "$PSScriptRoot\io.ps1" , "$PSScriptRoot\visualstudio-detection.ps1" , "$PSScriptRoot\msbuild-expression-eval.ps1" , "$PSScriptRoot\msbuild-project-load.ps1" , "$PSScriptRoot\msbuild-project-data.ps1" , "$PSScriptRoot\itemdefinition-context.ps1" ) | ForEach-Object { . $_ } } function LoadIntegrationProject($name) { $slnPath = "$PSScriptRoot\integration-projects\CptIntegrationProjects.sln"; if (! (VariableExists 'slnFiles')) { Set-Variable -name 'slnFiles' -value @{} -scope Global Set-Variable -name 'cptVisualStudioVersion' -value '2017' -scope Global } $global:slnFiles[$slnPath] = (Get-Content $slnPath) [string] $projPath = "$PSScriptRoot\test-projects\$name\test.vcxproj" LoadProject $projPath } Describe "Integration Project Unit Tests" { It "Should correctly load Item Groups" { #LoadIntegrationProject -name 'itemgroups' #$includeDirs = Get-ProjectIncludeDirectories # todo validate includeDirs } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/integration-projects/CptIntegrationProjects.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.421 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "itemgroups", "itemgroups\test.vcxproj", "{558406F5-E257-4B00-B2C5-27A947DBB111}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {558406F5-E257-4B00-B2C5-27A947DBB111}.Debug|x86.ActiveCfg = Debug|Win32 {558406F5-E257-4B00-B2C5-27A947DBB111}.Debug|x86.Build.0 = Debug|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EE1D3380-CA68-4AE8-B0BD-630FEBA1824F} EndGlobalSection EndGlobal ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/integration-projects/itemgroups/test.vcxproj ================================================ Debug Win32 15.0 {558406F5-E257-4B00-B2C5-27A947DBB111} Win32Proj cpttestprojone 10.0.17763.0 itemgroups Application true v141 Unicode true @(CptTest);$(IncludePath) Use Level3 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h Console true Create ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/io.ps1 ================================================ #Console IO # ------------------------------------------------------------------------------------------------ Function Write-Message([parameter(Mandatory = $true)][string] $msg , [Parameter(Mandatory = $true)][System.ConsoleColor] $color) { $foregroundColor = $host.ui.RawUI.ForegroundColor $host.ui.RawUI.ForegroundColor = $color Write-Output $msg $host.ui.RawUI.ForegroundColor = $foregroundColor } function Write-InformationTimed($message) { if ($InformationPreference -eq "SilentlyContinue") { return } [DateTime] $lastTime = [DateTime]::Now [string] $kTimeStampVar = "lastCptTimestamp" if (VariableExists -name $kTimeStampVar) { $lastTime = (Get-Variable -name $kTimeStampVar -scope Global).Value } Set-Variable -name $kTimeStampVar -scope Global -value ([DateTime]::Now) [DateTime] $now = [DateTime]::Now; [System.TimeSpan] $delta = $now - $lastTime Write-Information "$message at $([DateTime]::Now.ToString("mm:ss:fff")). dt = $($delta.TotalMilliseconds)" } # Writes an error without the verbose PowerShell extra-info (script line location, etc.) Function Write-Err([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Message -msg $msg -color Red } Function Write-Success([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Message -msg $msg -color Green } Function Write-Array($array, $name) { Write-Output "$($name):" $array | ForEach-Object { Write-Output " $_" } Write-Output "" # empty line separator } Function Write-Verbose-Array($array, $name) { if ($VerbosePreference -eq "SilentlyContinue") { return } Write-Verbose "$($name):" $array | ForEach-Object { Write-Verbose " $_" } Write-Verbose "" # empty line separator } Function Write-Verbose-Timed([parameter(ValueFromPipeline, Mandatory = $true)][string] $msg) { Write-Verbose "$([DateTime]::Now.ToString("[HH:mm:ss]")) $msg" } Function Print-InvocationArguments() { if ($VerbosePreference -eq "SilentlyContinue") { return } $bParams = $PSCmdlet.MyInvocation.BoundParameters if ($bParams) { [string] $paramStr = "clang-build.ps1 invocation args: `n" foreach ($key in $bParams.Keys) { $paramStr += " $($key) = $($bParams[$key]) `n" } Write-Verbose $paramStr } } Function Print-CommandParameters([Parameter(Mandatory = $true)][string] $command) { $params = @() foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters)) { if (!$param.HelpMessage) { continue } $params += New-Object PsObject -Prop @{ "Option" = "-$($param.Aliases[0])" ; "Description" = $param.HelpMessage } } $params | Sort-Object -Property "Option" | Out-Default } # Function that gets the name of a command argument when it is only known by its alias # For streamlining purposes, it also accepts the name itself. Function Get-CommandParameterName([Parameter(Mandatory = $true)][string] $command ,[Parameter(Mandatory = $true)][string] $nameOrAlias) { foreach ($param in ((Get-Command $command).ParameterSets[0].Parameters)) { if ($param.Name -eq $nameOrAlias -or $param.Aliases -contains $nameOrAlias) { return $param.Name } } return "" } Function VariableExists([Parameter(Mandatory = $true)][string] $name) { if ( ! ( Get-Variable $name -ErrorAction 'Ignore') ) { return $false } return $true } Function VariableExistsAndNotEmpty([Parameter(Mandatory = $true)][string] $name) { if ( ! (VariableExists $name) ) { return $false } if ( [string]::IsNullOrWhiteSpace( (Get-Variable $name).Value ) ) { return $false } return $true } function HasProperty($object, $property) { return ($property -in $object.PSobject.Properties.Name) } # File IO # ------------------------------------------------------------------------------------------------ Function Get-QuotedPath([Parameter(Mandatory = $false)][string] $path) { if ([string]::IsNullOrWhiteSpace($path)) { return $path } [string] $returnPath = $path if (!$path.StartsWith('"')) { $returnPath = """$path""" } return $returnPath } Function Get-UnquotedPath([Parameter(Mandatory = $false)][string] $path) { [string] $retPath = $path if ( ! [string]::IsNullOrWhiteSpace($retPath) -and $retPath.StartsWith('"') ) { $retPath = $retPath.Remove(0, 1); if ( $retPath.EndsWith('"') ) { $retPath = $retPath.Remove($retPath.Length - 1, 1) } else { # if it begins with double quote, should end with double quote... # something else may be going on, return the original path. $retPath = $path } } return $retPath } Function Remove-PathTrailingSlash([Parameter(Mandatory = $true)][string] $path) { return $path -replace '\\$', '' } Function Get-FileDirectory([Parameter(Mandatory = $true)][string] $filePath) { return ([System.IO.Path]::GetDirectoryName($filePath) + "\") } Function Get-FileName( [Parameter(Mandatory = $false)][string] $path , [Parameter(Mandatory = $false)][switch] $noext) { if ($noext) { return ([System.IO.Path]::GetFileNameWithoutExtension($path)) } else { return ([System.IO.Path]::GetFileName($path)) } } Function IsFileMatchingName( [Parameter(Mandatory = $true)][string] $filePath , [Parameter(Mandatory = $true)] $matchName) { [string] $matchString = $matchName.ToString() # works for both strings and regex types if ($matchName -is [string]) { if ([System.IO.Path]::IsPathRooted($matchString)) { if ($matchName.Length -le $filePath.Length -and ($filePath.Substring(0, $matchName.Length) -ieq $matchName)) { return $true } } [string] $fileName = (Get-FileName -path $filePath) if ($fileName -ieq $matchString) { return $true } [string] $fileNameNoExt = (Get-FileName -path $filePath -noext) if ($fileNameNoExt -ieq $matchString) { return $true } if ($filePath.ToLower().EndsWith($matchName.ToLower())) { return $true } while (![string]::IsNullOrWhiteSpace($filePath)) { if ($filePath.ToLower().EndsWith($matchName.ToLower())) { return $true } $filePath = [System.IO.Path]::GetDirectoryName($filePath) } return $false } elseif ($matchName -is [regex]) { return $filePath -match $matchString } else { throw "Unsupported match object type $($matchName.GetType().ToString())" } } Function FileHasExtension( [Parameter(Mandatory = $true)][string] $filePath , [Parameter(Mandatory = $true)][string[]] $ext ) { foreach ($e in $ext) { if ($filePath.EndsWith($e)) { return $true } } return $false } Function Get-RandomString( [Parameter(Mandatory=$false)][int] $aLength = 10) { return (-Join ((65..90) + (97..122) | Get-Random -Count $aLength | % { [char] $_ })) } <# .DESCRIPTION Merges an absolute and a relative file path. .EXAMPLE Having base = C:\Windows\System32 and child = .. we get C:\Windows .EXAMPLE Having base = C:\Windows\System32 and child = ..\..\..\.. we get C:\ (cannot go further up) .PARAMETER base The absolute path from which we start. .PARAMETER child The relative path(s) to be merged into base. If multiple paths are specified, they can be separated semicolon or space. .PARAMETER ignoreErrors If this switch is not present, an error will be triggered if the resulting path is not present on disk (e.g. c:\Windows\System33). If present and the resulting path does not exist, the function returns an empty string. #> Function Canonize-Path( [Parameter(Mandatory = $true)][string] $base , [Parameter(Mandatory = $true)][string] $child , [switch] $ignoreErrors) { [string[]] $children = @() $tokensBySemicolon = $child.Trim().Split(';') foreach ($semicolonTok in $tokensBySemicolon) { if ([string]::IsNullOrWhiteSpace($semicolonTok)) { continue } $tokensBySpace = $semicolonTok.Trim().Split(' ') $currentToken = "" foreach ($tok in $tokensBySpace) { if ($tok -match "[A-Z]:.*") { if ( ! [string]::IsNullOrWhiteSpace($currentToken)) { $children += $currentToken } $currentToken = $tok } else { if ($tok -ne $tokensBySpace[0]) { $currentToken += ' ' } $currentToken += $tok } } $children += $currentToken } Write-Debug "Canonizing for base = $base and children = $children" [string[]] $retPaths = @() [string] $errorAction = If ($ignoreErrors) {"SilentlyContinue"} Else {"Stop"} if (Test-Path -LiteralPath $base) { # Join-Path doesn't support LiteralPath so make sure we sanitize # the base path for unsupported characters $base = $base.Replace('[', '`['); $base = $base.Replace(']', '`]'); } foreach ($childPath in $children) { $childPath = Get-UnquotedPath $childPath $childPath = $childPath -replace "`r", "" $childPath = $childPath -replace "`n", "" if ([System.IO.Path]::IsPathRooted($childPath)) { if ((Test-Path -LiteralPath $childPath)) { $retPaths += @($childPath) } } else { [string[]] $paths = @(Join-Path -Path "$base" -ChildPath "$childPath" -Resolve -ErrorAction $errorAction) $retPaths += $paths } } return $retPaths } function cpt::HasTrailingSlash([Parameter(Mandatory = $true)][string] $str) { return $str.EndsWith('\') -or $str.EndsWith('/') } function EnsureTrailingSlash([Parameter(Mandatory = $true)][string] $str) { [string] $ret = If (cpt::HasTrailingSlash($str)) { $str } else { "$str\" } return $ret } function cpt::Exists([Parameter(Mandatory = $false)][string] $path) { if ([string]::IsNullOrEmpty($path)) { return $false } return Test-Path -LiteralPath $path } function cpt::MakePathRelative( [Parameter(Mandatory = $true)][string] $base , [Parameter(Mandatory = $true)][string] $target ) { Push-Location "$base\" [string] $relativePath = (Resolve-Path -Relative $target) -replace '^\.\\','' Pop-Location if ( (cpt::HasTrailingSlash $target) -or $target.EndsWith('.') ) { $relativePath += '\' } return "$relativePath" } function cpt::GetDirNameOfFileAbove( [Parameter(Mandatory = $true)][string] $startDir , [Parameter(Mandatory = $true)][string] $targetFile ) { if ($targetFile.Contains('$')) { $targetFile = Invoke-Expression $targetFile } if ($startDir.Contains('$')) { $startDir = Invoke-Expression $startDir } [string] $base = $startDir while ([string]::IsNullOrEmpty((Canonize-Path -base $base ` -child $targetFile ` -ignoreErrors))) { $base = [System.IO.Path]::GetDirectoryName($base) if ([string]::IsNullOrEmpty($base)) { return "" } } return $base } function cpt::GetPathOfFileAbove([Parameter(Mandatory = $true)][string] $targetFile, [Parameter(Mandatory = $true)][string] $startDir ) { if ($targetFile.Contains('$')) { $targetFile = Invoke-Expression $targetFile } $base = (cpt::GetDirNameOfFileAbove -targetFile $targetFile -startDir $startDir) if ([string]::IsNullOrWhiteSpace($base)) { return "" } return "$(EnsureTrailingSlash $base)$targetFile" } # Command IO # ------------------------------------------------------------------------------------------------ Function Exists-Command([Parameter(Mandatory = $true)][string] $command) { try { Get-Command -name $command -ErrorAction Stop | out-null return $true } catch { return $false } } Function Get-ClangVersion([Parameter(Mandatory = $true)][string] $toolToCheck) { if (Exists-Command $toolToCheck) { [string] $s = &"$toolToCheck" --version $regexMatch = [regex]::match($s, 'version (\d+).') if ($regexMatch) { return ($regexMatch.Groups[1].Value -as [int]) } } return 0 } Function Test-InternetConnectivity { $resp = Get-WmiObject -Class Win32_PingStatus -Filter 'Address="github.com" and Timeout=100' | Select-Object ResponseTime [bool] $hasInternetConnectivity = ($resp.ResponseTime -and $resp.ResponseTime -gt 0) return $hasInternetConnectivity } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/io.tests.ps1 ================================================ #Clear-Host BeforeAll { @( , "$PSScriptRoot\io.ps1" ) | ForEach-Object { . $_ } } Describe "VariableExists" { It "Should verify VariableExists" { VariableExists 'Foobar_VariableExists' | Should -BeExactly $false $Foobar_VariableExists = 1 VariableExists 'Foobar_VariableExists' | Should -BeExactly $true $Foobar_VariableExists = @() VariableExists 'Foobar_VariableExists' | Should -BeExactly $true Remove-Variable 'Foobar_VariableExists' | Out-Null VariableExistsAndNotEmpty 'Foobar_VariableExists' | Should -BeExactly $false $Foobar_VariableExists = " " VariableExists 'Foobar_VariableExists' | Should -BeExactly $true VariableExistsAndNotEmpty 'Foobar_VariableExists' | Should -BeExactly $false $Foobar_VariableExists = " " VariableExistsAndNotEmpty 'Foobar_VariableExists' | Should -BeExactly $false $Foobar_VariableExists = "1" VariableExistsAndNotEmpty 'Foobar_VariableExists' | Should -BeExactly $true } } Describe "HasProperty" { It "Should verify HasProperty" { [string] $s = "abc" HasProperty $s "Length" | Should -BeExactly $true HasProperty Ss "Lengthh" | SHould -BeExactly $false HasProperty $s "Trim" | Should -BeExactly $false # this is a method } } Describe "File IO" { It "Get-QuotedPath" { Get-QuotedPath '' | Should -BeExactly '' Get-QuotedPath ' ' | Should -BeExactly ' ' Get-QuotedPath ' ' | Should -BeExactly ' ' Get-QuotedPath 'test' | Should -BeExactly '"test"' Get-QuotedPath '"test"' | Should -BeExactly '"test"' Get-QuotedPath 'c:\some file' | Should -BeExactly '"c:\some file"' Get-QuotedPath '"c:\some file"' | Should -BeExactly '"c:\some file"' } It "Remove-PathTrailingSlash" { Remove-PathTrailingSlash "c:\windows\" | Should -BeExactly "c:\windows" Remove-PathTrailingSlash "c:\windows" | Should -BeExactly "c:\windows" Remove-PathTrailingSlash "..\foo\bar\" | Should -BeExactly "..\foo\bar" } It "Get-FileDirectory" { Get-FileDirectory "$env:SystemRoot\explorer.exe" | Should -BeExactly "$env:SystemRoot\" Get-FileDirectory "$env:SystemRoot\explorer.exe" | Should -BeExactly "$env:SystemRoot\" Get-FileDirectory "$env:SystemRoot\foobar.nonexistent" | Should -BeExactly "$env:SystemRoot\" Get-FileDirectory "foo\bar" | Should -BeExactly "foo\" } It "Get-FileName" { Get-FileName "$env:SystemRoot\explorer.exe" | Should -BeExactly "explorer.exe" Get-FileName "$env:SystemRoot\foobar.nonexistent" | Should -BeExactly "foobar.nonexistent" } It "IsFileMatchingName - no regex" { $path = "$env:SystemRoot\notepad.exe" IsFileMatchingName -filePath $path -matchName "notepad" | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName "notepad.exe" | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName "notepad.ex" | Should -BeExactly $false IsFileMatchingName -filePath $path -matchName "note" | Should -BeExactly $false IsFileMatchingName -filePath $path -matchName ".*" | Should -BeExactly $false } It "IsFileMatchingName - with regex" { $path = "$env:SystemRoot\notepad.exe" IsFileMatchingName -filePath $path -matchName ([regex]"notepad") | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName ([regex]"notepad.exe") | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName ([regex]"notepad.ex") | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName ([regex]"note") | Should -BeExactly $true IsFileMatchingName -filePath $path -matchName ([regex]".*") | Should -BeExactly $true } It "FileHasExtension" { FileHasExtension -filePath "c:\foo.bar" -ext 'bar' | Should -BeExactly $true FileHasExtension -filePath "c:\foo.bar" -ext 'bar2' | Should -BeExactly $false FileHasExtension -filePath "c:\foo.bar" -ext @('bar') | Should -BeExactly $true FileHasExtension -filePath "c:\foo.bar" -ext @('bar2') | Should -BeExactly $false FileHasExtension -filePath "c:\foo.bar" -ext @('bar', 'bar2') | Should -BeExactly $true FileHasExtension -filePath "c:\foo.bar" -ext @('bar2', 'bar') | Should -BeExactly $true FileHasExtension -filePath "c:\foo.bar" -ext @('bar2', 'bar2') | Should -BeExactly $false } It "Canonize-Path" { $sysDrive = "$env:SystemDrive\" Canonize-Path -base $sysDrive -child "Windows" | Should -Be $env:SystemRoot { Canonize-Path -base $sysDrive -child "foobar" } | Should -throw { Canonize-Path -base $sysDrive -child "foobar" -ignoreErrors } | Should -not -throw Canonize-Path -base $sysDrive -child "foobar" -ignoreErrors | Should -BeExactly $null [string[]] $files = Canonize-Path -base $sysDrive -child "*" # get all children $files.Count | Should -BeGreaterThan 1 } It "Exists" { [string] $winDir = $env:SystemRoot cpt::Exists $winDir | should -BeExactly $true cpt::Exists "$winDir\notepad.exe" | should -BeExactly $true cpt::Exists "$winDir\foobar_surely_nonextant" | should -BeExactly $false } It "HasTrailingSlash" { cpt::HasTrailingSlash "ab" | should -BeExactly $false cpt::HasTrailingSlash "ab\" | should -BeExactly $true cpt::HasTrailingSlash "ab/" | should -BeExactly $true cpt::HasTrailingSlash "a/b/" | should -BeExactly $true } It "EnsureTrailingSlash" { EnsureTrailingSlash "ab" | should -BeExactly "ab\" EnsureTrailingSlash "ab\" | should -BeExactly "ab\" EnsureTrailingSlash "ab/" | should -BeExactly "ab/" EnsureTrailingSlash "a/b/" | should -BeExactly "a/b/" } } Describe "Command IO" { It "Exists-Command" { Exists-Command "Get-Process" | Should -BeExactly $true Exists-Command "Get-JiggyWithIt" | Should -BeExactly $false } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/itemdefinition-context.ps1 ================================================ # Powershell code for creating item definition group contexts [System.Collections.Hashtable] $global:itemProperties = @{} [string] $global:itemPropertyNamespace = "" function Reset-ProjectItemContext() { $global:itemProperties = @{} $global:itemPropertyNamespace = "" } function Push-ProjectItemContext([Parameter(Mandatory = $true)][string] $name) { [string] $toAdd = "" if ($global:itemPropertyNamespace.Length -gt 0) { $toAdd = "."; } $toAdd += $name $global:itemPropertyNamespace += $toAdd Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Pop-ProjectItemContext() { [int] $dotPos = $global:itemPropertyNamespace.LastIndexOf(".") if ($dotPos -ge 0) { $global:itemPropertyNamespace = $global:itemPropertyNamespace.Substring(0, $dotPos) } else { $global:itemPropertyNamespace = "" } Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Set-ProjectItemContext([Parameter(Mandatory = $true)][AllowEmptyString()][string] $name) { if ( (VariableExists 'itemPropertyNameSpace') -and ($global:itemPropertyNamespace -eq $name) ) { return } $global:itemPropertyNamespace = $name Write-Verbose "[CONTEXT] item namespace = @($global:itemPropertyNamespace)" } function Get-ProjectItemContext() { return $global:itemPropertyNamespace } function Get-ProjectItemProperty([Parameter(Mandatory = $false)][string] $propertyName) { if (! $global:itemProperties.ContainsKey($global:itemPropertyNamespace)) { return $null } [System.Collections.Hashtable] $propMap = $global:itemProperties[$global:itemPropertyNamespace] if (!$propertyName) { return $propMap } if (! $propMap.ContainsKey($propertyName)) { return $null } return $propMap[$propertyName] } function Set-ProjectItemProperty([Parameter(Mandatory = $true)][string] $propertyName, [Parameter(Mandatory = $true)] $value) { if (! $global:itemProperties.ContainsKey($global:itemPropertyNamespace)) { $global:itemProperties.Add($global:itemPropertyNamespace, @{}) $global:ProjectSpecificVariables.Add('itemProperties') | out-null } [System.Collections.Hashtable] $propMap = $global:itemProperties[$global:itemPropertyNamespace] if (! $propMap.ContainsKey($propertyName)) { $propMap.Add($propertyName, $value) } else { $propMap[$propertyName] = $value } Write-Verbose "[CONTEXT] propSet: $propertyName = $value" } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/jsondb-export.ps1 ================================================ function JsonDB-Init() { [string] $outputPath = (EnsureTrailingSlash( Get-SourceDirectory )) $outputPath += "compile_commands.json" Set-Variable -name "kJsonCompilationDbPath" -value $outputPath -option Constant -scope Global Set-Variable -name "kJsonCompilationDbCount" -value 0 -scope Global "[" | Out-File $kJsonCompilationDbPath -Encoding "UTF8" } function JsonDB-Append($text) { $text | Out-File $kJsonCompilationDbPath -append -Encoding "UTF8" } function JsonDB-Finalize() { JsonDB-Append "]" Write-Output "Exported JSON Compilation Database to $kJsonCompilationDbPath" } function JsonDB-Push($directory, $file, $command) { if ($kJsonCompilationDbCount -ge 1) { JsonDB-Append " ," } # use only slashes $command = $command.Replace('\', '/') $file = $file.Replace('\', '/') $directory = $directory.Replace('\', '/') # escape double quotes $command = $command.Replace('"', '\"') # make paths relative to directory $command = $command.Replace("$directory/", "") $file = $file.Replace("$directory/", "") JsonDB-Append " {`r`n ""directory"": ""$directory"",`r`n ""command"": ""$command"",`r`n ""file"": ""$file""`r`n }" Set-Variable -name "kJsonCompilationDbCount" -value ($kJsonCompilationDbCount + 1) -scope Global } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/jsondb-export.tests.ps1 ================================================ Describe "Json Compilation Database Export" { It "WIP" { } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-expression-eval.ps1 ================================================ # REQUIRES io.ps1 to be included [string[]] $buildUtilPaths = @( ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ,"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Build.Utilities.Core.dll" ) foreach ($buildUtilPath in $buildUtilPaths) { if (Test-Path -LiteralPath $buildUtilPath) { Add-Type -path $buildUtilPath Write-Verbose "Loaded assembly $buildUtilPath" break } } Set-Variable -name "kMsbuildExpressionToPsRules" <#-option Constant#> ` -value @( ` <# backticks are control characters in PS, replace them #> ` ('`' , '''' )` <# Temporarily replace $( #> ` , ('\$\s*\(' , '!@#' )` <# Escape $ #> ` , ('\$' , '`$' )` <# Put back $( #> ` , ('!@#' , '$(' )` <# Various operators #> ` , ("([\s\)\'""])!=" , '$1 -ne ' )` , ("([\s\)\'""])<=" , '$1 -le ' )` , ("([\s\)\'""])>=" , '$1 -ge ' )` , ("([\s\)\'""])==" , '$1 -eq ' )` , ("([\s\)\'""])<" , '$1 -lt ' )` , ("([\s\)\'""])>" , '$1 -gt ' )` , ("([\s\)\'""])or" , '$1 -or ' )` , ("([\s\)\'""])and" , '$1 -and ' )` <# Use only double quotes #> ` , ("\'" , '"' )` , ("Exists\((.*?)\)(\s|$)" , '(cpt::Exists($1))$2' )` , ("HasTrailingSlash\((.*?)\)(\s|$)" , '(cpt::HasTrailingSlash($1))$2')` , ("(\`$\()(Registry:)(.*?)(\))" , '$$(GetRegValue("$3"))' )` , ("\[MSBuild\]::GetDirectoryNameOfFileAbove\((.+?),\s*`"?'?((\$.+?\))|(.+?))((|`"|')\))+"` ,'cpt::GetDirNameOfFileAbove -startDir $1 -targetFile ''$2'')' )` , ("\(\[MSBuild\]::GetPathOfFileAbove\(`"?(.+?)`"?,\s*((`"(.+)`"\)+)|((\$\(.+?\))\)*))"` ,'(cpt::GetPathOfFileAbove -startDir "$4$6" -targetFile ''$1'')' )` , ("\[MSBuild\]::MakeRelative\((.+?),\s*""?'?((\$.+?\))|(.+?))((|""|')\)\))+"` ,'cpt::MakePathRelative -base $1 -target "$2")' )` , ('SearchOption\.', '[System.IO.SearchOption]::' )` , ("@\((.*?)\)", '$(Get-Project-Item("$1"))' )` , ("%\((.*?)\)", '$(Get-ProjectItemProperty("$1"))' )` , ('\$\(HOME\)', '$(CPT_SHIM_HOME)' )` <# Rules for making sure the $ sign is put on correctly in expressions #> ` , ('\$\(([a-zA-Z_][a-zA-Z0-9_\-]+)\)', '$${$1}' )` , ('\(([a-zA-Z_][a-zA-Z0-9_\-]+\.)', '($$$1' )` ) function GetRegValue([Parameter(Mandatory = $true)][string] $regPath) { Write-Debug "REG_READ $regPath" [int] $separatorIndex = $regPath.IndexOf('@') [string] $valueName = "" if ($separatorIndex -gt 0) { [string] $valueName = $regPath.Substring($separatorIndex + 1) $regPath = $regPath.Substring(0, $separatorIndex) } if ([string]::IsNullOrEmpty($valueName)) { throw "Cannot retrieve an empty registry value" } $regPath = $regPath -replace "HKEY_LOCAL_MACHINE\\", "HKLM:\" if (Test-Path $regPath) { return (Get-Item $regPath).GetValue($valueName) } else { return "" } } function Initialize-ExpressionVariables([string] $expression) { # expressions that call member functions of unintialized variables will throw # unless we initialize those variables $regexMatches = [regex]::matches($expression, '\$(\w+)\.') if ($regexMatches.Count -gt 0) { foreach ($regexMatch in $regexMatches) { $varName = $regexMatch.Groups[1].Value if (! ( Get-Variable $varName -ErrorAction 'Ignore') ) { Write-Debug "Initializing expression variable $varName to empty value" Set-Var -name $varName -value "" } } } } function Evaluate-MSBuildExpression([string] $expression, [switch] $isCondition) { # A lot of MSBuild expressions refer uninitialized variables Set-StrictMode -Off Write-Debug "Start evaluate MSBuild expression $expression" foreach ($rule in $kMsbuildExpressionToPsRules) { $expression = $expression -replace $rule[0], $rule[1] } if ( !$isCondition -and ($expression.IndexOf('$') -lt 0)) { # we can stop here, further processing is not required return $expression } Write-Debug "Intermediate PS expression: $expression" Initialize-ExpressionVariables $expression [string] $res = "" try { if ( ($expression.IndexOf('::') -ge 0) -or $isCondition) { try { $resInvokeResult = Invoke-Expression $expression if ($resInvokeResult -is [array]) { $res = $resInvokeResult -join ';' } else { $res = $resInvokeResult } } catch { Write-Verbose $_.Exception.Message $res = $ExecutionContext.InvokeCommand.ExpandString($expression) } } else { $res = $ExecutionContext.InvokeCommand.ExpandString($expression) } } catch { Write-Verbose $_.Exception.Message } Write-Debug "Evaluated expression to: $res" return $res } function Evaluate-MSBuildCondition([Parameter(Mandatory = $true)][string] $condition) { Write-Debug "Evaluating condition $condition" try { [string] $expression = Evaluate-MSBuildExpression -expression $condition -isCondition } catch { Write-Verbose $_.Exception.Message return $false } if ($expression -ieq "true") { return $true } if ($expression -ieq "false") { return $false } $expression = $expression -replace 'False', '$false' $expression = $expression -replace 'True', '$true' try { [bool] $res = (Invoke-Expression $expression) -eq $true } catch { Write-Verbose $_.Exception.Message return $false } Write-Debug "Evaluated condition to $res" return $res } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-expression-eval.tests.ps1 ================================================ #Clear-Host # IMPORT code blocks BeforeAll { @( , "$PSScriptRoot\io.ps1" , "$PSScriptRoot\itemdefinition-context.ps1" , "$PSScriptRoot\msbuild-expression-eval.ps1" ) | ForEach-Object { . $_ } } Describe "MSBuild - Powershell Expression translation" { It "Plain expressions" { Evaluate-MSBuildExpression "MyProjectString" | Should -BeExactly "MyProjectString" Evaluate-MSBuildExpression "1905" | Should -BeExactly "1905" Evaluate-MSBuildExpression "a;;b;c" | Should -BeExactly "a;;b;c" Evaluate-MSBuildExpression "a-b-c" | Should -BeExactly "a-b-c" Evaluate-MSBuildExpression "1-2-3" | Should -BeExactly "1-2-3" Evaluate-MSBuildExpression "{1-2-3-4}" | Should -BeExactly "{1-2-3-4}" Evaluate-MSBuildExpression "1.2.3.4" | Should -BeExactly "1.2.3.4" Evaluate-MSBuildExpression "c:\foo\bar.ini" | Should -BeExactly "c:\foo\bar.ini" Evaluate-MSBuildExpression "..\foo\bar" | Should -BeExactly "..\foo\bar" } It "Arithmetical operators" { Evaluate-MSBuildExpression "`$(1+2+3)" | Should -BeExactly "6" Evaluate-MSBuildExpression "`$(1-2-3)" | Should -BeExactly "-4" Evaluate-MSBuildExpression "`$(1*2*3)" | Should -BeExactly "6" Evaluate-MSBuildExpression "`$(10/2)" | Should -BeExactly "5" } It "Read from registry" { $e = '$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$(GetRegValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir"))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles } It "Property expansion" { $ProjectDir = "C:\Users\Default" Evaluate-MSBuildExpression "`$Foo;`$(ProjectDir);..\..;..\..\third-party" ` | Should -BeExactly '$Foo;C:\Users\Default;..\..;..\..\third-party' $TargetName = "Test" Evaluate-MSBuildExpression "%(ASDASD);`$(TargetName)" | Should -BeExactly ";Test" $prop = "123" Evaluate-MSBuildExpression 'plaintext;"$(prop)"' | Should -BeExactly 'plaintext;"123"' Evaluate-MSBuildExpression 'plaintext;''$(prop)''' | Should -BeExactly 'plaintext;"123"' Evaluate-MSBuildExpression 'plaintext;$(prop)-$(prop)' | Should -BeExactly 'plaintext;123-123' $TestDir = $env:ProgramFiles Evaluate-MSBuildExpression '$(TestDir)\first\second' | Should -BeExactly "$env:ProgramFiles\first\second" } It "GetDirectoryNameOfFileAbove() / GetPathOfFileAbove() MSBuild builtin functions" { [string] $MSBuildThisFileDirectory = $env:SystemRoot $e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), ''Program Files'')Program Files' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove(''Program Files'', $(MSBuildThisFileDirectory))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "Program Files")Program Files' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove("Program Files", $(MSBuildThisFileDirectory))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove("Program Files", ''$(MSBuildThisFileDirectory)''))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles [string] $MSBuildThisFileDirectory2 = $MSBuildThisFileDirectory + "\System32" $e = '$([MSBuild]::GetPathOfFileAbove(''Program Files'', "$(MSBuildThisFileDirectory2)../"))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = "`$([MSBuild]::GetDirectoryNameOfFileAbove('$MSBuildThisFileDirectory', 'Program Files')Program Files" Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = "`$([MSBuild]::GetPathOfFileAbove('Program Files', '$MSBuildThisFileDirectory')" Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles [string] $whatToFind = "Program Files" $e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), ''$(whatToFind)'')Program Files' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove(''$(whatToFind)'', $(MSBuildThisFileDirectory))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Program Files)Program Files' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove(Program Files, $(MSBuildThisFileDirectory)))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove(Program Files, ''$(MSBuildThisFileDirectory)''))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles $e = '$([MSBuild]::GetPathOfFileAbove(''Program Files'', ''$(MSBuildThisFileDirectory)''))' Evaluate-MSBuildExpression $e | Should -BeExactly $env:ProgramFiles [string] $_DirectoryBuildPropsFile = "clang-build.ps1" [string] $MSBuildProjectDirectory = "$PSScriptRoot" [string] $DirParent = [System.IO.Directory]::GetParent($MSBuildProjectDirectory) $e = '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), ''$(_DirectoryBuildPropsFile)''))' Evaluate-MSBuildExpression $e | Should -Be "$DirParent" $e = '$([MSBuild]::GetPathOfFileAbove(''$(_DirectoryBuildPropsFile)'', $(MSBuildProjectDirectory)))' Evaluate-MSBuildExpression $e | Should -Be "$DirParent\$_DirectoryBuildPropsFile" } It "MakeRelative() MSBuild builtin function" { $SystemDrive = $env:SystemDrive $SystemRoot = $env:SystemRoot $ProgramFiles = $env:ProgramFiles $e = "`$([MSBuild]::MakeRelative('$SystemDrive', '$SystemRoot'))" Evaluate-MSBuildExpression $e | Should -Be "Windows" $e = "`$([MSBuild]::MakeRelative(`$(SystemDrive), '$SystemRoot'))" Evaluate-MSBuildExpression $e | Should -Be "Windows" $e = '$([MSBuild]::MakeRelative($(SystemDrive), $(SystemRoot)\System32))' Evaluate-MSBuildExpression $e | Should -Be "Windows\System32" $e = '$([MSBuild]::MakeRelative($(SystemRoot), $(SystemRoot)\System32))' Evaluate-MSBuildExpression $e | Should -Be "System32" $e = '$([MSBuild]::MakeRelative($(ProgramFiles), $(SystemRoot)\System32))' Evaluate-MSBuildExpression $e | Should -Be "..\Windows\System32" } It ".NET Method invocation" { $Sys32Folder = "System32" $WinDir = $env:SystemRoot $e = '$([System.IO.Path]::Combine(''$(WinDir)'', ''$(Sys32Folder)''))' Evaluate-MSBuildExpression $e | Should -BeExactly "$WinDir\$Sys32Folder" } } Describe "Condition evaluation" { It "Logical operators" { Evaluate-MSBuildCondition '0 != 1' | Should -BeExactly $true Evaluate-MSBuildCondition '1 != 1' | Should -BeExactly $false Evaluate-MSBuildCondition '1 == 1' | Should -BeExactly $true Evaluate-MSBuildCondition '0 == 1' | Should -BeExactly $false Evaluate-MSBuildCondition '0 < 1' | Should -BeExactly $true Evaluate-MSBuildCondition '1 <= 1' | Should -BeExactly $true Evaluate-MSBuildCondition '1 < 0' | Should -BeExactly $false Evaluate-MSBuildCondition '1 <= 0' | Should -BeExactly $false Evaluate-MSBuildCondition '1 > 0' | Should -BeExactly $true Evaluate-MSBuildCondition '1 >= 1' | Should -BeExactly $true Evaluate-MSBuildCondition '1 < 0 or 0 < 1' | Should -BeExactly $true Evaluate-MSBuildCondition '!(1 < 0 or 0 < 1)' | Should -BeExactly $false Evaluate-MSBuildCondition '1 < 0 and 0 < 1' | Should -BeExactly $false Evaluate-MSBuildCondition '1 < 0 and 0 < 1' | Should -BeExactly $false Evaluate-MSBuildCondition '((1 < 0) or (0 < 1)) and !("a"=="b")' | Should -BeExactly $true Evaluate-MSBuildCondition '"apple" == "apple"' | Should -BeExactly $true Evaluate-MSBuildCondition '''apple'' == ''apple''' | Should -BeExactly $true Evaluate-MSBuildCondition '''apple'' == ''pear''' | Should -BeExactly $false Evaluate-MSBuildCondition '"apple" != "pear"' | Should -BeExactly $true } It "Registry access" { $c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)' != ''" Evaluate-MSBuildCondition $c | Should -BeExactly $true $ProgramFiles = $env:ProgramFiles $c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@ProgramFilesDir)' == '`$(ProgramFiles)'" Evaluate-MSBuildCondition $c | Should -BeExactly $true $c = "'`$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion@NonexistentValue)' == ''" Evaluate-MSBuildCondition $c | Should -BeExactly $true } It "Variable expansion" { $Configuration = "Release2" $Platform = "Win32" Evaluate-MSBuildCondition "'`$(Configuration)|`$(Platform)'=='Debug|Win32' or '`$(Configuration)' == 'Release2'" | Should -BeExactly $true Evaluate-MSBuildCondition "'`$(Configuration)|`$(Platform)'=='Release|Win32'" | Should -BeExactly $false Evaluate-MSBuildCondition '$(Platform.Replace(" ", "")) and $(testB)' | Should -BeExactly $false } It "Exists() MSBuild builtin function" { $WinDir = $env:SystemRoot Evaluate-MSBuildCondition "exists('`$(WinDir)')" | Should -BeExactly $true Evaluate-MSBuildCondition "1 == 1 and exists('`$(WinDir)')" | Should -BeExactly $true Evaluate-MSBuildCondition "exists('`$(WinDir)\System32')" | Should -BeExactly $true Evaluate-MSBuildCondition "exists('`$(WinDir)\System64')" | Should -BeExactly $false $WinDir += "gibberish12345" Evaluate-MSBuildCondition "exists('`$(WinDir)')" | Should -BeExactly $false Evaluate-MSBuildCondition "0 == 1 and exists('`$(WinDir)')" | Should -BeExactly $false [System.Reflection.Assembly]::LoadWithPartialName("System.IO") $eression = 'Exists("$([System.IO.Directory]::GetCurrentDirectory())")' Evaluate-MSBuildCondition $eression | Should -BeExactly $true $eression = 'Exists("$([System.IO.Directory]::GetCurrentDirectory())\nonexistent12345")' Evaluate-MSBuildCondition $eression | Should -BeExactly $false $Sys32 = "$env:SystemRoot\System32" $WinDir = "$Sys32..\.." Evaluate-MSBuildCondition "Exists('`$(Sys32)\..')" | Should -BeExactly $true } It "Access to [String] builtin functions" { $TargetName = "AnotherTest" Evaluate-MSBuildCondition "`$(TargetName.EndsWith('Test'))" | Should -BeExactly $true Evaluate-MSBuildCondition "`$(TargetName.EndsWith('Test2'))" | Should -BeExactly $false $myVar = 'TwoThree' $MySelector = "One;Two;Three" Evaluate-MSBuildCondition "`$(MySelector.Contains(`$(myVar.Substring(3, 3))))"` | Should -BeExactly $true $MySelector = "One;Two;Three" $myVar = "Two" Evaluate-MSBuildCondition "`$(MySelector.Contains(`$(myVar)))" | Should -BeExactly $true $MySelector = "One;Two;Three" Evaluate-MSBuildCondition "`$(MySelector.Contains('Three'))" | Should -BeExactly $true Evaluate-MSBuildCondition "`$(MySelector.Contains('Four'))" | Should -BeExactly $false } It ".NET method invocation" { $year = (Get-Date).Year Evaluate-MSBuildCondition "`$([System.DateTime]::Now.Year) == `$(year)" | Should -BeExactly $true Evaluate-MSBuildCondition "`$([System.DateTime]::Now.Year) != `$(year)" | Should -BeExactly $false } It "HasTrailingSlash() MSBuild builtin function" { Evaluate-MSBuildCondition "HasTrailingSlash('c:\windows\')" | Should -BeExactly $true Evaluate-MSBuildCondition "HasTrailingSlash('c:\windows')" | Should -BeExactly $false $c = "HasTrailingSlash('c:\windows\') and hasTrailingSlash('c:\temp/')" Evaluate-MSBuildCondition $c | Should -BeExactly $true $c = "HasTrailingSlash('c:\windows\') and !hasTrailingSlash('c:\temp/')" Evaluate-MSBuildCondition $c | Should -BeExactly $false $prop = "c:\windows\" Evaluate-MSBuildCondition "hasTrailingSlash(`$(prop))" | Should -BeExactly $true $prop = "c:\windows" Evaluate-MSBuildCondition "hasTrailingSlash(`$(prop))" | Should -BeExactly $false } It "Itemgroupdefinition" { $defVal = "bar" Set-ProjectItemProperty "foo" $defVal Evaluate-MSBuildExpression "%(foo)" | Should -BeExactly $defVal Evaluate-MSBuildCondition "'%(foo)' == '$defVal'" | Should -BeExactly $true Evaluate-MSBuildCondition "'%(foo)' != '$defVal'" | Should -BeExactly $false $P1 = "prop_value" Evaluate-MSBuildExpression '%(foo)|$(P1)' | Should -BeExactly "$defVal|$P1" Evaluate-MSBuildExpression '%(foo);$(P1)' | Should -BeExactly "$defVal;$P1" } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-cache-repository.ps1 ================================================ Set-Variable -name kCptCacheRepo -value "$env:APPDATA\ClangPowerTools\CacheRepository" -option Constant Function Is-CacheLoadingEnabled() { if ("${Env:CPT_CACHEREPO}" -eq "0") { return $false } # if the cache repository directory exists, then we use caching return (Test-Path $kCptCacheRepo) } Function Remove-CachedProjectFile([Parameter(Mandatory = $true)][string] $aCachedFilePath) { if ($aCachedFilePath.StartsWith($kCptCacheRepo)) { Remove-Item $aCachedFilePath | Out-Null } } Function Get-CacheRepositoryIndex() { Write-Verbose "Loading project cache repository index" [System.Collections.Hashtable] $cacheIndex = @{} if (Is-CacheLoadingEnabled) { [string] $cptCacheRepoIndex = "$kCptCacheRepo\index.dat" if (Test-Path $cptCacheRepoIndex) { try { $cacheIndex = [System.Management.Automation.PSSerializer]::Deserialize((Get-Content $cptCacheRepoIndex)) } catch { Write-Verbose "Error: Could not deserialize corrupted cache repository index. Rebuilding from scratch..." return $cacheIndex } } } return $cacheIndex } Function Save-CacheRepositoryIndex([Parameter(Mandatory = $true)][System.Collections.Hashtable] $cacheIndex) { Write-Verbose "Saving project cache repository index" if (! (Is-CacheLoadingEnabled) ) { return } [System.Collections.ArrayList] $indexKeys = @() foreach ($keyIndex in $cacheIndex.Keys) { # make sure we don't invalidate the cacheIndex.Keys collection iterators when modifying it $indexKeys.Add($keyIndex) > $null } foreach ($indexKey in $indexKeys) { [string] $CachedDataPath = $cacheIndex[$indexKey].CachedDataPath if (! (Test-Path $CachedDataPath)) { Write-Verbose "Pruning zombie entry ($($indexKey) : $($CachedDataPath)) from cache repository index" $cacheIndex.Remove($indexKey) > $null } } [string] $cptCacheRepoIndex = "$kCptCacheRepo\index.dat" $serialized = [System.Management.Automation.PSSerializer]::Serialize($cacheIndex) $serialized > $cptCacheRepoIndex } Function Join-ConfigurationPlatformScriptArgs() { return ($aVcxprojConfigPlatform -join ",") } Function Save-ProjectToCacheRepo() { Write-Verbose "Saving current project data to cache repository" if (! (Is-CacheLoadingEnabled) ) { return } Write-Verbose "Collecting $($global:ProjectSpecificVariables.Count) project specific variables" [System.Collections.Hashtable] $projectVariablesMap = @{} foreach ($varName in $global:ProjectSpecificVariables) { $projectVariablesMap[$varName] = Get-Variable -name $varName -ValueOnly } [System.Collections.Hashtable] $genericVariablesMap = @{} $genericVariablesMap['cptVisualStudioVersion' ] = Get-Variable 'cptVisualStudioVersion' -scope Global -ValueOnly $genericVariablesMap['cptCurrentConfigPlatform'] = Get-Variable 'cptCurrentConfigPlatform' -scope Global -ValueOnly $dataToSerialize = New-Object PsObject -Prop @{ "ProjectSpecificVariables" = $projectVariablesMap ; "GenericVariables" = $genericVariablesMap } [string] $pathToSave = "" while ($true) { [string] $pathToSave = "$kCptCacheRepo\$(Get-RandomString).dat" # make sure we don't overwrite an already existing cache entry if (! (Test-Path $pathToSave)) { break } } $serialized = [System.Management.Automation.PSSerializer]::Serialize($dataToSerialize) $serialized > $pathToSave Write-Verbose "Wrote project to cache repository using moniker $pathToSave" [System.Collections.Hashtable] $projectFilesHashes = @{} foreach ($projectFile in $global:ProjectInputFiles) { $projectFilesHashes[$projectFile] = (Get-FileHash $projectFile -Algorithm "SHA1").Hash } [System.Collections.Hashtable] $cacheIndex = Get-CacheRepositoryIndex $cacheObject = New-Object PsObject -Prop @{ "ProjectFilesHashes" = $projectFilesHashes ; "CachedDataPath" = $pathToSave ; "ConfigurationPlatform" = Join-ConfigurationPlatformScriptArgs ; "CptCacheSyntaxVersion" = $kCacheSyntaxVer } $cacheIndex[$MSBuildProjectFullPath] = $cacheObject Save-CacheRepositoryIndex $cacheIndex } Function Load-ProjectFromCache([Parameter(Mandatory = $true)][string] $aVcxprojPath) { Write-Verbose "Trying to load project $aVcxprojPath from cache repository" if (! (Is-CacheLoadingEnabled) ) { Write-Verbose "Cache repository not enabled in %APPDATA%/ClangPowerTools/CacheRepository" return $false } [System.Collections.Hashtable] $cacheIndex = Get-CacheRepositoryIndex if ( ! $cacheIndex.ContainsKey($aVcxprojPath)) { Write-Verbose "Cache repository does not contain record of project" return $false } $projectCacheObject = $cacheIndex[$aVcxprojPath] if ( ! (Test-Path $projectCacheObject.CachedDataPath)) { Write-Verbose "Error: Cache repository contains record of project but cached file no longer exists" return $false } if ($projectCacheObject.CptCacheSyntaxVersion -ne $kCacheSyntaxVer) { Write-Verbose "Cached version of project uses older syntax version. Discarding..." # the cached version uses an outdated syntax, safely discard it Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } [System.Collections.Hashtable] $projectFilesHashes = $projectCacheObject.ProjectFilesHashes foreach ($projectFilePath in $projectFilesHashes.Keys) { Write-Verbose "Checking hash of project file $projectFilePath" $newFileHash = (Get-FileHash $projectFilePath -Algorithm "SHA1").Hash if ($newFileHash -ne $projectFilesHashes[$projectFilePath]) { Write-Verbose "Cached version of project has different file hash. Discarding..." # project file hash not matching, safely discard cached version Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } } if ($projectCacheObject.ConfigurationPlatform -ne (Join-ConfigurationPlatformScriptArgs)) { Write-Verbose "Cached version of project uses different configuration platform. Discarding..." # config-platform not maching, safely discard cached version Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } # Clean global variables that have been set by a previous project load Clear-Vars $global:vcxprojPath = $aVcxprojPath Write-Verbose "Loading cached project from $($projectCacheObject.CachedDataPath)" [string] $data = Get-Content $projectCacheObject.CachedDataPath $deserialized = $null try { $deserialized = [System.Management.Automation.PSSerializer]::Deserialize($data) } catch { Write-Verbose "Error: Failure to deserialize cached project data. Discarding corrupted file" Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } [System.Collections.Hashtable] $projectSpecificVariablesMap = $deserialized.ProjectSpecificVariables [System.Collections.Hashtable] $genericVariablesMap = $deserialized.GenericVariables Write-Verbose "Cached version of project has $($projectSpecificVariablesMap.Count) variables to load" if ($projectSpecificVariablesMap.Keys -notcontains "MSBuildThisFileFullPath") { Write-Verbose "Cached project does not contain MSBuildThisFileFullPath. Discarding..." Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } if ( $projectSpecificVariablesMap['MSBuildThisFileFullPath'] -ne $aVcxprojPath ) { Write-Verbose "Cached project looks to be a different project ($($projectSpecificVariablesMap['MSBuildThisFileFullPath'])). Discarding..." Remove-CachedProjectFile $projectCacheObject.CachedDataPath return $false } foreach ($var in $projectSpecificVariablesMap.Keys) { Set-Var -name $var -value $projectSpecificVariablesMap[$var] } # these variables should be garbage collected between projects # using our custom Set-Var would allow that to happen foreach ($var in $genericVariablesMap.Keys) { Set-Variable -name $var -value $genericVariablesMap[$var] -scope Global } Write-Verbose "Cache repository - project load was successful" return $true } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-cache-repository.tests.ps1 ================================================ Describe "Project Cache Repository" { It "WIP" { } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-data.ps1 ================================================ #------------------------------------------------------------------------------------------------- # PlatformToolset constants Set-Variable -name kDefinesUnicode -value @('"-DUNICODE"' ,'"-D_UNICODE"' ) ` -option Constant Set-Variable -name kDefinesClangXpTargeting ` -value @('"-D_USING_V110_SDK71_"') ` -option Constant Set-Variable -name kIncludePathsXPTargetingSDK ` -value "${Env:ProgramFiles(x86)}\Microsoft SDKs\Windows\v7.1A\Include" ` -option Constant Set-Variable -name kVStudioDefaultPlatformToolset -Value "v141" -option Constant Set-Variable -name kClangFlag32BitPlatform -value "-m32" -option Constant # ------------------------------------------------------------------------------------------------ # Default platform sdks and standard Set-Variable -name kVSDefaultWinSDK -value '8.1' -option Constant Set-Variable -name kVSDefaultWinSDK_XP -value '7.0' -option Constant Set-Variable -name kDefaultCppStd -value "stdcpp14" -option Constant # ------------------------------------------------------------------------------------------------ Set-Variable -name kCProjectCompile -value "CompileAsC" -option Constant Function Should-CompileProject([Parameter(Mandatory = $true)][string] $vcxprojPath) { if ($aVcxprojToCompile -eq $null) { return $true } foreach ($projMatch in $aVcxprojToCompile) { if (IsFileMatchingName -filePath $vcxprojPath -matchName $projMatch) { return $true } } return $false } Function Should-IgnoreProject([Parameter(Mandatory = $true)][string] $vcxprojPath) { if ($aVcxprojToIgnore -eq $null) { return $false } foreach ($projIgnoreMatch in $aVcxprojToIgnore) { if (IsFileMatchingName -filePath $vcxprojPath -matchName $projIgnoreMatch) { return $true } } return $false } Function Should-IgnoreFile([Parameter(Mandatory = $true)][string] $file) { if ($aCppToIgnore -eq $null) { return $false } foreach ($projIgnoreMatch in $aCppToIgnore) { if (IsFileMatchingName -filePath $file -matchName $projIgnoreMatch) { return $true } } foreach ($projIgnoreMatch in $global:cptIgnoredFilesPool) { if (IsFileMatchingName -filePath $file -matchName $projIgnoreMatch) { return $true } } return $false } Function Get-ProjectFilesToCompile() { $projectCompileItems = @(Get-Project-ItemList "ClCompile") if (!$projectCompileItems) { Write-Verbose "Project does not have any items to compile" return @() } $files = @() foreach ($item in $projectCompileItems) { [System.Collections.Hashtable] $itemProps = $item[1]; if ($itemProps -and $itemProps.ContainsKey('ExcludedFromBuild')) { if ($itemProps['ExcludedFromBuild'] -ieq 'true') { Write-Verbose "Skipping $($item[0]) because it is excluded from build" continue } } [string[]] $matchedFiles = @(Canonize-Path -base $ProjectDir -child $item[0] -ignoreErrors) if ($matchedFiles.Count -gt 0) { foreach ($file in $matchedFiles) { $files += New-Object PsObject -Prop @{ "File" = $file ; "Properties" = $itemProps } } } } return $files } Function Get-ProjectHeaders() { $projectCompileItems = @(Get-Project-ItemList "ClInclude") [string[]] $headerPaths = @() foreach ($item in $projectCompileItems) { [string[]] $paths = @(Canonize-Path -base $ProjectDir -child $item[0] -ignoreErrors) if ($paths.Count -gt 0) { $headerPaths += $paths } } return $headerPaths } Function Get-Project-SDKVer() { if (! (VariableExists 'WindowsTargetPlatformVersion')) { return "" } if ([string]::IsNullOrEmpty($WindowsTargetPlatformVersion)) { return "" } return $WindowsTargetPlatformVersion.Trim() } Function Get-Project-MultiThreaded-Define() { Set-ProjectItemContext "ClCompile" [string] $runtimeLibrary = Get-ProjectItemProperty "RuntimeLibrary" # /MT or /MTd if (@("MultiThreaded", "MultiThreadedDebug") -contains $runtimeLibrary) { return @('"-D_MT"') } return @('"-D_MT"', '"-D_DLL"') # default value /MD } Function Is-Project-Unicode() { if (VariableExists 'CharacterSet') { return $CharacterSet -ieq "Unicode" } return $false } Function Get-Project-CppStandard() { Set-ProjectItemContext "ClCompile" $cppStd = Get-ProjectItemProperty "LanguageStandard" if (!$cppStd) { $cppStd = $kDefaultCppStd } $cppStdMap = @{ 'stdcpplatest' = 'c++2c' ; 'stdcpp14' = 'c++14' ; 'stdcpp17' = 'c++17' ; 'stdcpp20' = 'c++20' ; 'stdcpp23' = 'c++23' } if ($kLLVMVersion -ge 13) { $cppStdMap['stdcpplatest'] = 'c++2b' } [string] $cppStdClangValue = $cppStdMap[$cppStd] return $cppStdClangValue } Function Get-ClangCompileFlags([Parameter(Mandatory = $false)][bool] $isCpp = $true) { [string[]] $flags = $aClangCompileFlags if ($isCpp -and !($flags -match "-std=.*")) { [string] $cppStandard = Get-Project-CppStandard $flags = @("-std=$cppStandard") + $flags } if ($Platform -ieq "x86" -or $Platform -ieq "Win32") { $flags += @($kClangFlag32BitPlatform) } return $flags } Function Get-ProjectPlatformToolset() { if (VariableExists 'PlatformToolset') { return $PlatformToolset } else { return $kVStudioDefaultPlatformToolset } } function Get-LatestSDKVersion() { [string] $parentDir = "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\" if (!(Test-Path -LiteralPath $parentDir)) { Write-Verbose "Windows 10 SDK parent directory could not be located" return "" } [System.IO.DirectoryInfo[]]$subdirs = @( get-childitem -path $parentDir | ` where { $_.Name.StartsWith("10.") } | ` sort -Descending -Property Name ) if ($subdirs.Count -eq 0) { Write-Verbose "[ERR] Could not detect latest Windows 10 SDK location" return "" } return $subdirs[0].Name } Function Get-ProjectIncludesFromIncludePathVar { [string[]] $returnArray = @() if ( (VariableExists 'IncludePath') ) { $returnArray += ($IncludePath -split ";") | ` Where-Object { ![string]::IsNullOrWhiteSpace($_) } | ` ForEach-Object { Canonize-Path -base $ProjectDir -child $_.Trim() -ignoreErrors } | ` Where-Object { ![string]::IsNullOrEmpty($_) } | ` ForEach-Object { $_ -replace '\\$', '' } } return $returnArray } Function Get-ProjectIncludeDirectories() { [string[]] $returnArray = @() [string] $vsPath = Get-VisualStudio-Path Write-Verbose "Visual Studio location: $vsPath" [string] $platformToolset = Get-ProjectPlatformToolset if (([int] $global:cptVisualStudioVersion) -lt 2017) { $returnArray += Get-VisualStudio-Includes -vsPath $vsPath } else { $mscVer = Get-MscVer -visualStudioPath $vsPath Write-Verbose "MSCVER: $mscVer" $returnArray += Get-VisualStudio-Includes -vsPath $vsPath -mscVer $mscVer } $sdkVer = Get-Project-SDKVer # We did not find a WinSDK version in the vcxproj. We use Visual Studio's defaults if ([string]::IsNullOrEmpty($sdkVer)) { if ($platformToolset.EndsWith("xp")) { $sdkVer = $kVSDefaultWinSDK_XP } else { $sdkVer = $kVSDefaultWinSDK } } Write-Verbose "WinSDK version: $sdkVer" # ---------------------------------------------------------------------------------------------- # Windows 10 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("10"))) { if ($sdkVer -eq "10.0") { # Project uses the latest Win10 SDK. We have to detect its location. $sdkVer = Get-LatestSDKVersion } $returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\ucrt") if ($platformToolset.EndsWith("xp")) { $returnArray += @($kIncludePathsXPTargetingSDK) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\um" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\shared" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\winrt" , "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\$sdkVer\cppwinrt" ) } } # ---------------------------------------------------------------------------------------------- # Windows 8 / 8.1 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("8."))) { $returnArray += @("${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt") if ($platformToolset.EndsWith("xp")) { $returnArray += @($kIncludePathsXPTargetingSDK) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\um" , "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\shared" , "${Env:ProgramFiles(x86)}\Windows Kits\$sdkVer\Include\winrt" ) } } # ---------------------------------------------------------------------------------------------- # Windows 7 if ((![string]::IsNullOrEmpty($sdkVer)) -and ($sdkVer.StartsWith("7.0"))) { $returnArray += @("$vsPath\VC\Auxiliary\VS\include") if ($platformToolset.EndsWith("xp")) { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt" , $kIncludePathsXPTargetingSDK ) } else { $returnArray += @( "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\7.0\ucrt") } } if ($env:CPT_LOAD_ALL -eq '1') { return @(Get-ProjectIncludesFromIncludePathVar) } else { $returnArray += @(Get-ProjectIncludesFromIncludePathVar) } return ( $returnArray | ForEach-Object { Remove-PathTrailingSlash -path $_ } ) } <# .DESCRIPTION Retrieve array of preprocessor definitions for a given project, in Clang format (-DNAME ) #> Function Get-ProjectPreprocessorDefines() { [string[]] $defines = @() if (Is-Project-Unicode) { $defines += $kDefinesUnicode } $defines += @(Get-Project-MultiThreaded-Define) if ( (VariableExists 'UseOfMfc') -and $UseOfMfc -ieq "Dynamic") { $defines += @('"-D_AFXDLL"') } [string] $platformToolset = Get-ProjectPlatformToolset if ($platformToolset.EndsWith("xp")) { $defines += $kDefinesClangXpTargeting } Set-ProjectItemContext "ClCompile" $preprocDefNodes = Get-ProjectItemProperty "PreprocessorDefinitions" if (!$preprocDefNodes) { return $defines } [string[]] $tokens = @($preprocDefNodes -split ";") # make sure we add the required prefix and escape double quotes $defines += @( $tokens | ` ForEach-Object { $_.Trim() } | ` Where-Object { $_ } | ` ForEach-Object { '"' + $(($kClangDefinePrefix + $_) -replace '"', '\"') + '"' } ) return $defines } Function Get-ProjCanonizedPaths([Parameter(Mandatory = $true)][string] $rawPaths) { [string[]] $tokens = @($rawPaths -split ";") foreach ($token in $tokens) { if ([string]::IsNullOrWhiteSpace($token)) { continue } [string] $includePath = Canonize-Path -base $ProjectDir -child $token.Trim() -ignoreErrors if (![string]::IsNullOrEmpty($includePath)) { $includePath -replace '\\$', '' } } } Function Get-ProjectExternalIncludePaths() { if (!(VariableExistsAndNotEmpty -name "ExternalIncludePath")) { return @() } return Get-ProjCanonizedPaths -rawPaths $ExternalIncludePath } Function Get-PathsFromText([Parameter(Mandatory = $true)][string] $text) { $result = @() [regex]$regex = '"[^"]*\/[^"]*"' $regex.Matches($text) | foreach-object { $result += $_.Value} return $result } # replace unix paths found in a string with dos paths Function Convert-UnixPathToDos([Parameter(Mandatory = $true)][string] $content) { $paths = @(Get-PathsFromText -text $content) foreach ($path in $paths) { if (([string]::IsNullOrWhiteSpace($path))) { continue } # Escape the backslashes in before using it in -replace. $escapedPath = [regex]::Escape($path) $content = $content -replace $escapedPath, ($path -replace '/','\') } return $content } # we will treat two cases of specifying external headers: /external:env:var and /external:I path # /external:env:var - we need to get value from key var # /external:I path - we need do get just path Function Get-PathsFromAdditionalOptions([Parameter(Mandatory = $true)][string] $options) { Write-Verbose "Trying to get paths from AdditionalOptions" # to avoid any problems we will convert unix paths (generarly generated by cmake) in dos paths $options = Convert-UnixPathToDos -content $options [string[]] $paths = @() [string[]] $tokens = @($options -split "/") foreach ($token in $tokens) { if (([string]::IsNullOrWhiteSpace($token)) -or ($token -notlike "*external:*")) { continue } # get the specified path after /external:I $patternExternalIncludes = '^(external:I)\s+(.*)$' if($token -match $patternExternalIncludes) { if(! [string]::IsNullOrWhiteSpace($Matches[2])) { Write-Verbose "Path from /external:I is $($Matches[2])" $paths += $Matches[2] } else { Write-Verbose "Cannot get path from /external:I" } } # retrieve the value of the environment variable specified after the /external:env option if($token -like "*external:env*") { [string[]] $externalAndVar = @($token -split ":") if(! [string]::IsNullOrWhiteSpace($externalAndVar[2])) { $envValue = [Environment]::GetEnvironmentVariable($externalAndVar[2]) if ($envValue -eq $null) { Write-Verbose "The environment variable $($externalAndVar[2]) is not set." } else { $envPaths = $envValue -split ";" $paths += $envPaths Write-Verbose "The value of $($externalAndVar[2]) is: $envValue" } } else { Write-Verbose "Cannot get path from /external:I" } } } return $paths } Function Get-IncludePathsFromAdditionalOptions() { Set-ProjectItemContext "ClCompile" $data = Get-ProjectItemProperty "AdditionalOptions" if (!(VariableExistsAndNotEmpty -name "data")) { return @() } $paths = Get-PathsFromAdditionalOptions -options $data if (!(VariableExistsAndNotEmpty -name "paths")) { return @() } return Get-ProjCanonizedPaths -rawPaths ($paths -join ";") } Function Get-ProjectAdditionalIncludes() { Set-ProjectItemContext "ClCompile" $data = Get-ProjectItemProperty "AdditionalIncludeDirectories" if (!(VariableExistsAndNotEmpty -name "data")) { return @() } return Get-ProjCanonizedPaths -rawPaths $data } Function Get-ProjectForceIncludes() { Set-ProjectItemContext "ClCompile" $forceIncludes = Get-ProjectItemProperty "ForcedIncludeFiles" if ($forceIncludes) { return @($forceIncludes -split ";" | Where-Object { ![string]::IsNullOrWhiteSpace($_) }) } return $null } Function Get-FileForceIncludes([Parameter(Mandatory=$true)] [string] $fileFullName) { try { [string] $forceIncludes = Get-ProjectFileSetting -fileFullName $fileFullName -propertyName "ForcedIncludeFiles" return ($forceIncludes -split ";") | ` Where-Object { ![string]::IsNullOrWhiteSpace($_) } | ` ForEach-Object { Canonize-Path -base $ProjectDir -child $_.Trim() -ignoreErrors } | ` Where-Object { ![string]::IsNullOrEmpty($_) } | ` ForEach-Object { $_ -replace '\\$', '' } } catch { return $null } } <# .DESCRIPTION Retrieve directory in which stdafx.h resides #> Function Get-ProjectStdafxDir( [Parameter(Mandatory = $true)] [string] $pchHeaderName , [Parameter(Mandatory = $false)] [string[]] $includeDirectories , [Parameter(Mandatory = $false)] [string[]] $additionalIncludeDirectories ) { [string] $stdafxPath = "" [string[]] $projectHeaders = @(Get-ProjectHeaders) if ($projectHeaders.Count -gt 0) { # we need to use only backslashes so that we can match against file header paths $pchHeaderName = $pchHeaderName.Replace("/", "\") $stdafxPath = $projectHeaders | Where-Object { (Get-FileName -path $_) -eq $pchHeaderName } } if ([string]::IsNullOrEmpty($stdafxPath)) { [string[]] $searchPool = @($ProjectDir); if ($includeDirectories.Count -gt 0) { $searchPool += $includeDirectories } if ($additionalIncludeDirectories.Count -gt 0) { $searchPool += $additionalIncludeDirectories } foreach ($dir in $searchPool) { [string] $stdafxPathTest = Canonize-Path -base $dir -child $pchHeaderName -ignoreErrors if (![string]::IsNullOrEmpty($stdafxPathTest)) { $stdafxPath = $stdafxPathTest break } } } if ([string]::IsNullOrEmpty($stdafxPath)) { return "" } # Handle case where the PCH header project setting contains directory names from upper hierarchy. # E.g. $(ProjectName)\$(ProjectName)_headers.h # More details at https://github.com/Caphyon/clang-power-tools/issues/1227 elseif ($stdafxPath.EndsWith($pchHeaderName)) { [string] $stdafxDir = $stdafxPath.Remove($stdafxPath.Length - $pchHeaderName.Length) return $stdafxDir } else { [string] $stdafxDir = Get-FileDirectory($stdafxPath) return $stdafxDir } } Function Get-PchCppIncludeHeader([Parameter(Mandatory = $true)][string] $pchCppFile) { [string] $cppPath = Canonize-Path -base $ProjectDir -child $pchCppFile [string[]] $fileLines = @(Get-Content -LiteralPath $cppPath) foreach ($line in $fileLines) { $regexMatch = [regex]::match($line, '^\s*#include\s+"(\S+)"') if ($regexMatch.Success) { return $regexMatch.Groups[1].Value } } return "" } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-data.tests.ps1 ================================================ #Clear-Host # IMPORT code blocks BeforeAll { @( , "$PSScriptRoot\io.ps1" , "$PSScriptRoot\msbuild-expression-eval.ps1" , "$PSScriptRoot\msbuild-project-load.ps1" , "$PSScriptRoot\msbuild-project-data.ps1" ) | ForEach-Object { . $_ } } Describe "VC++ Project Data Processing" { It "To be implemented" { } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-load.ps1 ================================================ #------------------------------------------------------------------------------------------------- # Global variables # vcxproj and property sheet files declare MsBuild properties (e.g. $(MYPROP)). # they are used in project xml nodes expressions. we have a # translation engine (MSBUILD-POWERSHELL) for these. it relies on # PowerShell to evaluate these expressions. We have to inject project # properties in the PowerShell runtime context. We keep track of them in # this list, so that each project can know to clean previous vars before loading begins. if (! (Test-Path variable:global:ProjectSpecificVariables)) { [System.Collections.ArrayList] $global:ProjectSpecificVariables = @() } if (! (Test-Path variable:global:ProjectInputFiles)) { [System.Collections.ArrayList] $global:ProjectInputFiles = @{} } Function Add-ToProjectSpecificVariables([Parameter(Mandatory = $true)] [string] $variableName) { $global:ProjectSpecificVariables.Add($variableName) > $null } if (! (Test-Path variable:global:ScriptParameterBackupValues)) { [System.Collections.Hashtable] $global:ScriptParameterBackupValues = @{} } # path of current project [string] $global:vcxprojPath = ""; Set-Variable -name "kRedundantSeparatorsReplaceRules" -option Constant ` -value @( <# handle multiple consecutive separators #> ` (";+" , ";") ` <# handle separator at end #> ` , (";$" , "") ` <# handle separator at beginning #> ` , ("^;" , "") ` ) Set-Variable -name "kCacheSyntaxVer" -Option Constant -value "1" Add-Type -TypeDefinition @" public class ProjectConfigurationNotFound : System.Exception { public string ConfigPlatform; public string Project; public ProjectConfigurationNotFound(string proj, string configPlatform) { this.Project = proj; this.ConfigPlatform = configPlatform; } } "@ Function Set-Var([parameter(Mandatory = $false)][string] $name ,[parameter(Mandatory = $false)] $value ,[parameter(Mandatory = $false)][switch] $asScriptParameter ) { if ($name -ieq "home") { Write-Verbose "Shimming HOME variable" # the HOME PowerShell variable is protected and we can't overwrite it $name = "CPT_SHIM_HOME" } if ($asScriptParameter) { if (Test-Path "variable:$name") { $oldVar = Get-Variable $name $oldValue = $oldVar.Value if ($oldValue -and $oldValue.GetType() -and $oldValue.GetType().ToString() -eq "System.Management.Automation.SwitchParameter") { $oldValue = $oldValue.ToBool() } $global:ScriptParameterBackupValues[$name] = $oldValue } else { $global:ScriptParameterBackupValues[$name] = $null } } Write-Verbose "SET_VAR $($name): $value" if ($asScriptParameter) { Set-Variable -name $name -Value $value -Scope Script } else { Set-Variable -name $name -Value $value -Scope Global } if (!$asScriptParameter -and !$global:ProjectSpecificVariables.Contains($name)) { Add-ToProjectSpecificVariables $name } } Function Add-Project-Item([parameter(Mandatory = $false)][string] $name ,[parameter(Mandatory = $false)] $value ,[parameter(Mandatory = $false)] $properties = $null) { if (!$value) { return } $itemVarName = "CPT_PROJITEM_$name" if (!(Get-Variable $itemVarName -ErrorAction SilentlyContinue)) { $itemList = New-Object System.Collections.ArrayList Set-Var -name $itemVarName -value $itemList } $itemList = (Get-Variable $itemVarName).Value if ($value -is [array]) { foreach ($arrayValue in $value) { $itemList.Add( @($arrayValue, $properties) ) > $null } } else { $itemList.Add(@($value, $properties)) > $null } } Function Get-Project-Item([parameter(Mandatory = $true)][string] $name) { $itemVarName = "CPT_PROJITEM_$name" $itemVar = Get-Variable $itemVarName -ErrorAction SilentlyContinue if ($itemVar) { $retStr = "" if ($itemVar.Value.GetType().Name -ieq "ArrayList") { foreach ($v in $itemVar.Value) { if ($retStr) { $retStr += ";" } $retStr += $v[0] # index0 = item; index1 = properties } } else { $retStr = $itemVar.Value[0] # index0 = item; index1 = properties } return $retStr } return $null } Function Get-Project-ItemList([parameter(Mandatory = $true)][string] $name) { $retList = New-Object System.Collections.ArrayList $itemVarName = "CPT_PROJITEM_$name" $itemVar = Get-Variable $itemVarName -ErrorAction SilentlyContinue if ($itemVar) { $retStr = "" if ($itemVar.Value.GetType().Name -ieq "ArrayList") { foreach ($v in $itemVar.Value) { if ($retStr) { $retStr += ";" } $retList.Add($v) > $null # v is a pair. index0 = item; index1 = properties } } else { $retList.Add($itemVar.Value) > $null } } return $retList } Function Clear-Vars() { Write-Verbose-Array -array $global:ProjectSpecificVariables ` -name "Deleting variables initialized by previous project" foreach ($var in $global:ProjectSpecificVariables) { Remove-Variable -name $var -scope Global -ErrorAction SilentlyContinue } foreach ($varName in $global:ScriptParameterBackupValues.Keys) { Write-Verbose "Restoring $varName to old value $($ScriptParameterBackupValues[$varName])" Set-Variable -name $varName -value $ScriptParameterBackupValues[$varName] } $global:ScriptParameterBackupValues.Clear() $global:ProjectSpecificVariables.Clear() $global:ProjectInputFiles.Clear() Reset-ProjectItemContext } Function UpdateScriptParameter([Parameter(Mandatory = $true)] [string] $paramName ,[Parameter(Mandatory = $false)][string] $paramValue) { [bool] $isSwitch = $false $evalParamValue = "" # no type specified because we don't know it yet if ($paramValue) # a parameter { $evalParamValue = Invoke-Expression $paramValue # evaluate expression to get actual value } else # a switch { $isSwitch = $true } # the parameter name we detected may be an alias => translate it into the real name [string] $realParamName = Get-CommandParameterName -command "$PSScriptRoot\..\clang-build.ps1" ` -nameOrAlias $paramName if (!$realParamName) { Write-Output "OVERVIEW: Clang Power Tools: compiles or tidies up code from Visual Studio .vcxproj project files`n" Write-Output "USAGE: clang-build.ps1 [options]`n" Write-Output "OPTIONS: " Print-CommandParameters "$PSScriptRoot\..\clang-build.ps1" Fail-Script "Unsupported option '$paramName'. Check cpt.config." } if ($isSwitch) { Set-Var -name $realParamName -value $true -asScriptParameter } else { Set-Var -name $realParamName -value $evalParamValue -asScriptParameter } } Function Get-ConfigFileParameters() { [System.Collections.Hashtable] $retArgs = @{} [string] $startDir = If ( VariableExistsAndNotEmpty 'ProjectDir' ) { $ProjectDir } else { $aSolutionsPath } [string] $configFile = (cpt::GetDirNameOfFileAbove -startDir $startDir -targetFile "cpt.config") + "\cpt.config" if (!(Test-Path -LiteralPath $configFile)) { return $retArgs } Write-Verbose "Found cpt.config in $configFile" [xml] $configXml = Get-Content $configFile $configXpathNS= New-Object System.Xml.XmlNamespaceManager($configXml.NameTable) $configXpathNS.AddNamespace("ns", $configXml.DocumentElement.NamespaceURI) [System.Xml.XmlElement[]] $argElems = $configXml.SelectNodes("/ns:cpt-config/*", $configXpathNS) foreach ($argEl in $argElems) { if ($argEl.Name.StartsWith("vsx-")) { continue # settings for the Visual Studio Extension } if ($argEl.HasAttribute("Condition")) { [bool] $isApplicable = Evaluate-MSBuildCondition -condition $argEl.GetAttribute("Condition") if (!$isApplicable) { continue } } $retArgs[$argEl.Name] = $argEl.InnerText } return $retArgs } Function Update-ParametersFromConfigFile() { [System.Collections.Hashtable] $configParams = Get-ConfigFileParameters if (!$configParams) { return } foreach ($paramName in $configParams.Keys) { UpdateScriptParameter -paramName $paramName -paramValue $configParams[$paramName] } } Function InitializeMsBuildProjectProperties() { Write-Verbose "Importing environment variables into current scope" foreach ($var in (Get-ChildItem Env:)) { Set-Var -name $var.Name -value $var.Value } Set-Var -name "MSBuildProjectFullPath" -value $global:vcxprojPath Set-Var -name "ProjectDir" -value (Get-FileDirectory -filePath $global:vcxprojPath) Set-Var -name "MSBuildProjectExtension" -value ([IO.Path]::GetExtension($global:vcxprojPath)) Set-Var -name "MSBuildProjectFile" -value (Get-FileName -path $global:vcxprojPath) Set-Var -name "MSBuildProjectName" -value (Get-FileName -path $global:vcxprojPath -noext) Set-Var -name "MSBuildProjectDirectory" -value (Get-FileDirectory -filePath $global:vcxprojPath) Set-Var -name "MSBuildProgramFiles32" -value "${Env:ProgramFiles(x86)}" # defaults for projectname and targetname, may be overriden by project settings Set-Var -name "ProjectName" -value $MSBuildProjectName Set-Var -name "TargetName" -value $MSBuildProjectName Set-Var -name "UserRootDir" -value "$LocalAppData\Microsoft\MSBuild\v4.0" # These would enable full project platform references parsing, experimental right now if ($env:CPT_LOAD_ALL -eq '1') { Set-Var -name "ConfigurationType" -value "Application" Set-Var -name "VCTargetsPath" -value "$(Get-VisualStudio-Path)\Common7\IDE\VC\VCTargets\" Set-Var -name "VsInstallRoot" -value (Get-VisualStudio-Path) Set-Var -name "MSBuildExtensionsPath" -value "$(Get-VisualStudio-Path)\MSBuild" Set-Var -name "LocalAppData" -value $env:LOCALAPPDATA Set-Var -name "UniversalCRT_IncludePath" -value "${Env:ProgramFiles(x86)}\Windows Kits\10\Include\10.0.10240.0\ucrt" } [string] $vsVer = (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) Set-Var -name "VisualStudioVersion" -value $vsVer Set-Var -name "MSBuildToolsVersion" -value $vsVer [string] $projectSlnPath = Get-ProjectSolution [string] $projectSlnDir = Get-FileDirectory -filePath $projectSlnPath Set-Var -name "SolutionDir" -value $projectSlnDir [string] $projectSlnName = Get-FileName -path $projectSlnPath -noext Set-Var -name "SolutionName" -value $projectSlnName # pre-initialize Configuration and Platform properties if ( VariableExistsAndNotEmpty -name 'aVcxprojConfigPlatform') { Detect-ProjectDefaultConfigPlatform } Update-ParametersFromConfigFile } Function InitializeMsBuildCurrentFileProperties([Parameter(Mandatory = $true)][string] $filePath) { Set-Var -name "MSBuildThisFileFullPath" -value $filePath Set-Var -name "MSBuildThisFileExtension" -value ([IO.Path]::GetExtension($filePath)) Set-Var -name "MSBuildThisFile" -value (Get-FileName -path $filePath) Set-Var -name "MSBuildThisFileName" -value (Get-FileName -path $filePath -noext) Set-Var -name "MSBuildThisFileDirectory" -value (Get-FileDirectory -filePath $filePath) } <# .DESCRIPTION Sets the Configuration and Platform project properties so that conditions can be properly evaluated. #> function Detect-ProjectDefaultConfigPlatform() { [string] $configPlatformName = "" # detect the first platform/config pair from the project itemgroup $configItems = @(Get-Project-ItemList "ProjectConfiguration") if (![string]::IsNullOrWhiteSpace($global:cptCurrentConfigPlatform)) { # we have script parameters we can use to set the platform/config $configPlatformName = $global:cptCurrentConfigPlatform } if ((!$configItems -or $configItems.Count -eq 0)) { if ([string]::IsNullOrWhiteSpace($configPlatformName)) { throw [ProjectConfigurationNotFound]::new($global:vcxprojPath, ""); } } else { $targetConfiguration = $null if ([string]::IsNullOrEmpty($configPlatformName)) { $targetConfiguration = $configItems[0] } else { foreach ($configItem in $configItems) { [string] $platformName = $configItem[0] if ($platformName -ieq $configPlatformName) { $targetConfiguration = $configItem break } } if ($null -eq $targetConfiguration) { throw [ProjectConfigurationNotFound]::new($global:vcxprojPath, $configPlatformName); } } $configPlatformName = $targetConfiguration[0] } $global:cptCurrentConfigPlatform = $configPlatformName [string[]] $configAndPlatform = $configPlatformName.Split('|') Set-Var -Name "Configuration" -Value $configAndPlatform[0] Set-Var -Name "Platform" -Value $configAndPlatform[1] # manually set PlatformTarget for vcpkg # note that $(PlatformTarget) is not available at the top of the .vcxproj file. if($configAndPlatform[1] -eq "Win32") { # solution platforms use 'x86' and 'x64', not Win32 # set PlatformTarget to 'x86' to build the correct path for vcpkg lib Set-Var -Name "PlatformTarget" -Value "x86" } else { Set-Var -Name "PlatformTarget" -Value $configAndPlatform[1] } } function NodeHasUnsatisfiedCondition([System.Xml.XmlNode] $node) { if ($node.HasAttribute("Condition")) { [string] $nodeCondition = $node.GetAttribute("Condition") [bool] $conditionSatisfied = ((Evaluate-MSBuildCondition($nodeCondition)) -eq $true) return !$conditionSatisfied } return $false } function SanitizeProjectNode([System.Xml.XmlNode] $node) { if ($node.Name -ieq "#comment") { return } [System.Collections.ArrayList] $nodesToRemove = @() if ($node.Name -ieq "#text" -and $node.InnerText.Length -gt 0) { # evaluate node content $node.InnerText = Evaluate-MSBuildExpression $node.InnerText } if ($node.Name -ieq "Import") { [string] $relPath = Evaluate-MSBuildExpression $node.GetAttribute("Project") if (!$relPath) { return } [string[]] $paths = @(Canonize-Path -base (Get-Location) -child $relPath -ignoreErrors) [bool] $loadedProjectSheet = $false foreach ($path in $paths) { if (![string]::IsNullOrEmpty($path) -and (Test-Path -LiteralPath $path)) { Write-Verbose "Property sheet: $path" ParseProjectFile($path) $loadedProjectSheet = $true } } if (!$loadedProjectSheet) { Write-Verbose "Could not find property sheet $relPath" if ($relPath -like "\Microsoft.Cpp.props") { # now we can begin to evaluate directory.build.props XML element conditions, load it LoadDirectoryBuildPropSheetFile } } } if ( ($node.Name -ieq "ClCompile" -or $node.Name -ieq "ClInclude") -and ![string]::IsNullOrEmpty($node.GetAttribute("Include")) ) { [string] $expandedAttr = Evaluate-MSBuildExpression $node.GetAttribute("Include") $node.Attributes["Include"].Value = $expandedAttr } if ($node.Name -ieq "Otherwise") { [System.Xml.XmlElement[]] $siblings = @($node.ParentNode.ChildNodes | ` Where-Object { $_.GetType().Name -ieq "XmlElement" -and $_ -ne $node }) if ($siblings.Count -gt 0) { # means there's a element that matched # should not be evaluated, we could set unwated properties return } } if ($node.Name -ieq "ItemGroup") { [string] $oldItemContextName = Get-ProjectItemContext foreach ($child in $node.ChildNodes) { if ($child.GetType().Name -ine "XmlElement") { continue } [string] $childEvaluatedValue = Evaluate-MSBuildExpression $child.GetAttribute("Include") $itemProperties = @{} Set-ProjectItemContext $child.Name $contextProperties = Get-ProjectItemProperty if ($contextProperties -ne $null) { foreach ($k in $contextProperties.Keys) { $itemProperties[$k] = $contextProperties[$k] } } foreach ($nodePropChild in $child.ChildNodes) { if ($nodePropChild.GetType().Name -ine "XmlElement") { continue } if (NodeHasUnsatisfiedCondition -node $nodePropChild) { continue } $itemProperties[$nodePropChild.Name] = Evaluate-MSBuildExpression $nodePropChild.InnerText } Add-Project-Item -name $child.Name -value $childEvaluatedValue -properties $itemProperties } Set-ProjectItemContext $oldItemContextName if ($node.GetAttribute("Label") -ieq "ProjectConfigurations") { Detect-ProjectDefaultConfigPlatform } } if ($node.Name -ieq "ItemDefinitionGroup") { foreach ($child in $node.ChildNodes) { if ($child.GetType().Name -ine "XmlElement") { continue } Push-ProjectItemContext $child.Name foreach ($propNode in $child.ChildNodes) { if ($propNode.GetType().Name -ine "XmlElement") { continue } if (NodeHasUnsatisfiedCondition -node $propNode) { continue } [string] $propVal = Evaluate-MSBuildExpression $propNode.InnerText Set-ProjectItemProperty $propNode.Name $propVal } Pop-ProjectItemContext } } if ($node.ParentNode -and $node.ParentNode.Name -ieq "PropertyGroup") { # set new property value [string] $propertyName = $node.Name [string] $propertyValue = Evaluate-MSBuildExpression $node.InnerText Set-Var -Name $propertyName -Value $propertyValue return } if ($node.ChildNodes.Count -eq 0) { return } foreach ($child in $node.ChildNodes) { [bool] $validChild = $true if ($child.GetType().Name -ieq "XmlElement") { if ($child.HasAttribute("Condition")) { # process node condition [string] $nodeCondition = $child.GetAttribute("Condition") $validChild = ((Evaluate-MSBuildCondition($nodeCondition)) -eq $true) if ($validChild) { $child.RemoveAttribute("Condition") } } } if (!$validChild) { $nodesToRemove.Add($child) > $null continue } else { SanitizeProjectNode($child) } } foreach ($nodeToRemove in $nodesToRemove) { $nodeToRemove.ParentNode.RemoveChild($nodeToRemove) > $null } } <# .DESCRIPTION Parses a project file and loads data into corresponding data structures. Project elements that are conditioned will be evaluated and discarded if their condition is evaluted to False. #> function ParseProjectFile([string] $projectFilePath) { if ($projectFilePath.EndsWith("vcpkg.props")) { [string] $installDir = cpt::GetPathOfFileAbove -startDir (Get-FileDirectory $projectFilePath) -targetFile "Installed" if (! [string]::IsNullOrWhiteSpace($installDir) -and ! (VariableExistsAndNotEmpty -name "VcpkgInstalledDir") -and (Evaluate-MSBuildCondition "'`$(VcpkgEnableManifest)' != 'true'" )) { Set-Var -name "VcpkgInstalledDir" -value $installDir } [string] $rootDir = cpt::GetDirNameOfFileAbove -startDir (Get-FileDirectory $projectFilePath) -targetFile ".vcpkg-root" if ( ![string]::IsNullOrWhiteSpace($rootDir) -and ! (VariableExistsAndNotEmpty -name "VcpkgRoot")) { Set-Var -name "VcpkgRoot" -value $rootDir } } # keep current file path, we'll need to restore it [string] $currentFile = "" if (VariableExistsAndNotEmpty 'MSBuildThisFileFullPath') { $currentFile = $MSBuildThisFileFullPath } Write-Verbose "`nSanitizing $projectFilePath" [xml] $fileXml = Get-Content -LiteralPath $projectFilePath $global:ProjectInputFiles.Add($projectFilePath) > $null Push-Location -LiteralPath (Get-FileDirectory -filePath $projectFilePath) InitializeMsBuildCurrentFileProperties -filePath $projectFilePath SanitizeProjectNode($fileXml.Project) Pop-Location # restore previous path if (![string]::IsNullOrWhiteSpace(($currentFile))) { Write-Verbose "[INFO] Restoring project file properties localstate to parent file" InitializeMsBuildCurrentFileProperties -filePath $currentFile } } function LoadDirectoryBuildPropSheetFile() { if ($env:CPT_LOAD_ALL -ne "1") { # Tries to find a Directory.Build.props property sheet, starting from the # project directory, going up. When one is found, the search stops. # Multiple Directory.Build.props sheets are not supported. [string] $directoryBuildSheetPath = (cpt::GetDirNameOfFileAbove -startDir $ProjectDir ` -targetFile "Directory.Build.props") + "\Directory.Build.props" if (Test-Path -LiteralPath $directoryBuildSheetPath) { ParseProjectFile($directoryBuildSheetPath) } [string] $vcpkgIncludePath = "$env:LOCALAPPDATA\vcpkg\vcpkg.user.props" if (Test-Path -LiteralPath $vcpkgIncludePath) { ParseProjectFile($vcpkgIncludePath) } [string] $vcpkgIncludePath = "$env:LOCALAPPDATA\vcpkg\vcpkg.user.targets" if (Test-Path -LiteralPath $vcpkgIncludePath) { ParseProjectFile($vcpkgIncludePath) } } } <# .DESCRIPTION Loads vcxproj and property sheets into memory. This needs to be called only once when processing a project. Accessing project data can be done using ItemGroups and Properties #> function LoadProject([string] $vcxprojPath) { # Clean global variables that have been set by a previous project load Clear-Vars $global:vcxprojPath = $vcxprojPath InitializeMsBuildProjectProperties ParseProjectFile -projectFilePath $global:vcxprojPath } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/msbuild-project-load.tests.ps1 ================================================ #Clear-Host # IMPORT code blocks BeforeAll { @( , "$PSScriptRoot\io.ps1" , "$PSScriptRoot\msbuild-expression-eval.ps1" , "$PSScriptRoot\msbuild-project-load.ps1" ) | ForEach-Object { . $_ } } Describe "VC++ Project Data Loading" { It "To be implemented" { } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/visualstudio-detection.ps1 ================================================ # ------------------------------------------------------------------------------------------------ # Helpers for locating Visual Studio on the computer # VsWhere is available starting with Visual Studio 2017 version 15.2. Set-Variable -name kVsWhereLocation ` -value "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" #` #-option Constant Function Convert-MSVCFolderName2Toolset([Parameter(Mandatory = $true)][string] $internalVer) { # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering $internalVer = $internalVer.Replace('.', ''); return $internalVer.Substring(0, 3); } Function Convert-PlatformToolset2VsVer([Parameter(Mandatory = $true)][string] $toolset) { switch ($toolset) { "141" { "2017" } "142" { "2019" } "143" { "2022" } "145" { "2026" } } } Function Get-VisualStudioToolsets() { $toolsetFolders = (Get-Item "$(Get-VisualStudio-Path)\VC\Tools\MSVC\" | Get-ChildItem) [string[]] $toolsets = @() foreach ($folder in $toolsetFolders) { $toolsets += @(Convert-MSVCFolderName2Toolset -internalVer $folder.Name) } return ($toolsets | Where-Object { ![string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique) } Function Get-MscVer() { [string[]] $mscVerFolders = ((Get-Item "$(Get-VisualStudio-Path)\VC\Tools\MSVC\" | Get-ChildItem).Name | Sort-Object -Descending) foreach ($mscVerFolderName in $mscVerFolders) { # get the latest toolset (mscver) that matches our target Visual Studio version [string] $platformToolset = Convert-MSVCFolderName2Toolset $mscVerFolderName [string] $vsTargetVer = Convert-PlatformToolset2VsVer $platformToolset if ($vsTargetVer -eq $global:cptVisualStudioVersion) { return $mscVerFolderName } } } Function Get-VisualStudio-Includes([Parameter(Mandatory = $true)][string] $vsPath, [Parameter(Mandatory = $false)][string] $mscVer) { [string] $mscVerToken = "" If (![string]::IsNullOrEmpty($mscVer)) { $mscVerToken = "Tools\MSVC\$mscVer\" } return @( "$vsPath\VC\$($mscVerToken)include" , "$vsPath\VC\$($mscVerToken)atlmfc\include" , "$vsPath\VC\Auxiliary\VS\include" ) } Function Get-VsWhere-VisualStudio-Version() { switch ($global:cptVisualStudioVersion) { "2013" { return "[12.0, 13)" } "2015" { return "[14.0, 15)" } "2017" { return "[15.0, 16)" } "2019" { return "[16.0, 17)" } "2022" { return "[17.0, 18)" } "2026" { return "[18.0, 19)" } default { throw "Unsupported Visual Studio version: $cptVisualStudioVersion" } } } Function Get-VisualStudio-VersionNumber([Parameter(Mandatory = $true)][string] $vsYearVersion) { switch ($vsYearVersion) { "2013" { return "12.0" } "2015" { return "14.0" } "2017" { return "15.0" } "2019" { return "16.0" } "2022" { return "17.0" } "2026" { return "18.0" } default { throw "Unsupported Visual Studio version: $vsYearVersion" } } } # Newer Visual Studio versions support installing older toolset versions, for compatibility reasons. # Returns default instalation path of the current VS version/toolset. Function Get-VisualStudio-CompatiblityToolset-InstallLocation() { return "${Env:ProgramFiles(x86)}\Microsoft Visual Studio " + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } Function Get-VisualStudio2015-RegistryLocation() { return "HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\" + (Get-VisualStudio-VersionNumber $global:cptVisualStudioVersion) } Function Get-VisualStudio-Path() { # Depending of the version of Visual Studio, we have different approaches to locating it. if ( ([int] $global:cptVisualStudioVersion) -le 2015 ) { # Older Visual Studio (<= 2015). VSWhere is not available. [string] $installLocation = (Get-Item (Get-VisualStudio2015-RegistryLocation)).GetValue("InstallDir") if ($installLocation) { $installLocation = Canonize-Path -base $installLocation -child "..\.." -ignoreErrors } if ($installLocation) { return $installLocation } # we may have a newer VS installation with an older toolset feature installed [string] $toolsetDiskLocation = (Get-VisualStudio-CompatiblityToolset-InstallLocation) [string] $iostreamLocation = Canonize-Path -base $toolsetDiskLocation ` -child "VC\include\iostream" -ignoreErrors if ($iostreamLocation) { return $toolsetDiskLocation } Write-Err "Visual Studio $($global:cptVisualStudioVersion) installation location could not be detected" } else { # modern Visual Studio (> 2017). Use VSWhere to locate it. if (Test-Path -LiteralPath $kVsWhereLocation) { [string] $product = "*" if (![string]::IsNullOrEmpty($aVisualStudioSku)) { $product = "Microsoft.VisualStudio.Product.$aVisualStudioSku" } [string] $version = Get-VsWhere-VisualStudio-Version [string[]] $output = @(& "$kVsWhereLocation" -nologo ` -property installationPath ` -products $product ` -version $version ` -prerelease) # the -prerelease switch is not available on older VS2017 versions if (($output -join "").Contains("0x57")) <# error code for unknown parameter #> { $output = (& "$kVsWhereLocation" -nologo ` -property installationPath ` -version $version ` -products $product) } if (!$output) { throw "VsWhere could not detect Visual Studio $($global:cptVisualStudioVersion) $product." } [string] $installationPath = $output[0] Write-Verbose "Detected (vswhere) VisualStudio installation path: $installationPath" return $installationPath } if ( ([int] $global:cptVisualStudioVersion) -le 2022) { [string] $kVsDefaultLocation = "${Env:ProgramFiles}\Microsoft Visual Studio\$global:cptVisualStudioVersion\$aVisualStudioSku" } else { [string] $kVsDefaultLocation = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\$global:cptVisualStudioVersion\$aVisualStudioSku" } if (Test-Path -LiteralPath $kVsDefaultLocation) { return $kVsDefaultLocation } throw "Cannot locate Visual Studio $($global:cptVisualStudioVersion)" } } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/visualstudio-detection.tests.ps1 ================================================ # #Clear-Host # # IMPORT code blocks # BeforeAll { # @( # , "$PSScriptRoot\io.ps1" # , "$PSScriptRoot\visualstudio-detection.ps1" # ) | ForEach-Object { . $_ } # } # Describe "Visual Studio detection" { # # Mock script parameters # $global:cptVisualStudioVersion = "2017" # $aVisualStudioSku = "Professional" # It "Get-MscVer" { # [string[]] $mscVer = Get-MscVer # $mscVer.Count | Should -BeExactly 1 # $mscVer[0] | Should -Not -BeNullOrEmpty # $mscVer[0].Length | Should -BeGreaterThan 3 # $mscVer[0].Contains(".") | Should -BeExactly $true # } # It "Get-VisualStudio-Path" { # $vsPath = Get-VisualStudio-Path # $vsPath | Should -Not -BeNullOrEmpty # } # It "Get-VisualStudio-Path [2015]" { # # see first if VS 2015 is installed # [Microsoft.Win32.RegistryKey] $vs14Key = Get-Item "HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0" # [bool] $vs2015isInstalled = $vs14Key -and ![string]::IsNullOrEmpty($vs14Key.GetValue("InstallDir")) # $oldMockValue = $global:cptVisualStudioVersion # $vsPath = Get-VisualStudio-Path # $vsPath | Should -Not -BeNullOrEmpty # # Re-Mock script parameter # $global:cptVisualStudioVersion = "2015" # # Maybe we have a VS 2017 installation with v140 toolset installed # [string] $vs2017ToolsetV140Path = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0" # if (Test-Path "$vs2017ToolsetV140Path\VC\include\iostream") # { # $vs2015isInstalled = $true # } # if ($vs2015isInstalled) # { # $vs2015Path = Get-VisualStudio-Path # $vs2015Path | Should -Not -BeNullOrEmpty # $vs2015Path | Should -Not -Be $vsPath # } # else # { # { Get-VisualStudio-Path } | Should -Throw # } # $global:cptVisualStudioVersion = $oldMockValue # } # It "Get-VisualStudio-Includes" { # [string] $vsPath = Get-VisualStudio-Path # [string] $mscver = Get-MscVer # [string[]] $includes = Get-VisualStudio-Includes -vsPath $vsPath -mscVer $mscver # $includes.Count | Should -BeGreaterThan 1 # $includes | ForEach-Object { [System.IO.Directory]::Exists($_) | Should -BeExactly $true } # } # } ================================================ FILE: ClangPowerTools/ClangPowerToolsShared/Tooling/v1/psClang/~advinst.tests.ps1 ================================================ BeforeAll { . "$PsScriptRoot\io.ps1" } Describe "ai" { It "Should build Advanced Installer" { [string] $advinstRepo = $env:ADVINST_CPT if ($advinstRepo) { Push-Location $advinstRepo [string] $scriptLocation = Canonize-Path -base "$PSScriptRoot" -child "..\clang-build.ps1" &"$scriptLocation" 2>&1 | Out-Default [int] $exitCode = $LASTEXITCODE Pop-Location Write-Output "$PSScriptRoot" $exitCode | Should -BeExactly 0 } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/ClangCommandTests/IgnoreCompileCommandTests.cs ================================================ using ClangPowerTools.Commands; using EnvDTE80; using Xunit; namespace ClangPowerTools.Tests { [VsTestSettings(UIThread = true)] public class IgnoreCompileCommandTests { #region Members private const string kGeneralSettingsPath = @"C:\Users\Enache Ionut\AppData\Roaming\ClangPowerTools\GeneralConfiguration.config"; private DTE2 mDte; private IgnoreCompileCommand mIgnoreCompileCommand; #endregion /* #region Test Methods // Empty State [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_EmptyState_UIAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); //Act Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kSingleFileToIgnore); settingsHandler.SaveSettings(); var filesToIgnore = settingsProvider.GetCompilerSettingsModel().FilesToIgnore; var expectedRestul = string.Join(";", IgnoreCommand.kSingleFileToIgnore); settingsHandler.ResetSettings(); //Assert Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_EmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kSingleFileToIgnore); SettingsHandler.SaveGeneralSettings(); if (!File.Exists(kGeneralSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var generalSettingsModel = serializer.DeserializeFromFile(kGeneralSettingsPath); var filesToIgnore = generalSettingsModel.FilesToIgnoreCollection; var expectedRestul = string.Join(";", IgnoreCommand.kSingleFileToIgnore); SettingsTestUtility.ResetClangGeneralOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveMultipleFilesToIgnore_EmptyState_UIAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveGeneralSettings(); var filesToIgnore = mGeneralOptions.FilesToIgnore; var expectedRestul = string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); SettingsTestUtility.ResetClangGeneralOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveMultipleFilesToIgnore_EmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveGeneralSettings(); if (!File.Exists(kGeneralSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var generalSettingsModel = serializer.DeserializeFromFile(kGeneralSettingsPath); var filesToIgnore = generalSettingsModel.FilesToIgnoreCollection; var expectedRestul = string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); SettingsTestUtility.ResetClangGeneralOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } // No Empty State [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_NoEmptyState_UIAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var expectedResult = string.Join(";", IgnoreCommand.kStartUpMultipleFilesToIgnore); Initialize(expectedResult); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveGeneralSettings(); expectedResult += ";" + string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); var filesToIgnore = mGeneralOptions.FilesToIgnore; SettingsTestUtility.ResetClangGeneralOptionsView(); Assert.Equal(filesToIgnore, expectedResult); } [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_NoEmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var expectedResult = string.Join(";", IgnoreCommand.kStartUpMultipleFilesToIgnore); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kStartUpMultipleFilesToIgnore); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveGeneralSettings(); if (!File.Exists(kGeneralSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var generalSettingsModel = serializer.DeserializeFromFile(kGeneralSettingsPath); expectedResult += ";" + string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); var filesToIgnore = generalSettingsModel.FilesToIgnoreCollection; SettingsTestUtility.ResetClangGeneralOptionsView(); Assert.Equal(filesToIgnore, expectedResult); } #endregion #region Private Methods private void Initialize(string ignoreFiles) { ThreadHelper.ThrowIfNotOnUIThread(); mDte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); SettingsTestUtility.ResetClangGeneralOptionsView(); mIgnoreCompileCommand = IgnoreCompileCommand.Instance; mGeneralOptions = SettingsProvider.GeneralSettings; mGeneralOptions.FilesToIgnore = ignoreFiles; } private Task IgnoreFilesAsync(List aFilesToIgnore) { return Task.Run(() => { mIgnoreCompileCommand.AddIgnoreFilesToSettings(aFilesToIgnore); }); } #endregion */ } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/ClangCommandTests/IgnoreFormatCommandTests.cs ================================================ using ClangPowerTools.Commands; using EnvDTE80; using Xunit; namespace ClangPowerTools.Tests { [VsTestSettings(UIThread = true)] public class IgnoreFormatCommandTests { #region Members private const string kFormatSettingsPath = @"C:\Users\Enache Ionut\AppData\Roaming\ClangPowerTools\FormatConfiguration.config"; private DTE2 mDte; private IgnoreFormatCommand mIgnoreFormatCommand; #endregion /* #region Public Methods [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_EmptyState_UIAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); // Act Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kSingleFileToIgnore); var filesToIgnore = settingsProvider.GetFormatSettingsModel().FilesToIgnore; var expectedRestul = string.Join(";", IgnoreCommand.kSingleFileToIgnore); settingsHandler.ResetSettings(); // Assert Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_EmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kSingleFileToIgnore); SettingsHandler.SaveFormatSettings(); if (!File.Exists(kFormatSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var formatSettingsModel = serializer.DeserializeFromFile(kFormatSettingsPath); var filesToIgnore = formatSettingsModel.SkipFiles; var expectedRestul = string.Join(";", IgnoreCommand.kSingleFileToIgnore); SettingsTestUtility.ResetClangFormatOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveMultipleFilesToIgnore_EmptyState_UIAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveFormatSettings(); var filesToIgnore = mFormatOptions.FilesToIgnore; var expectedRestul = string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); SettingsTestUtility.ResetClangFormatOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } [VsFact(Version = "2019")] public async Task SaveMultipleFilesToIgnore_EmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); Initialize(string.Empty); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveFormatSettings(); if (!File.Exists(kFormatSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var formatSettingsModel = serializer.DeserializeFromFile(kFormatSettingsPath); var filesToIgnore = formatSettingsModel.SkipFiles; var expectedRestul = string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); SettingsTestUtility.ResetClangFormatOptionsView(); Assert.Equal(filesToIgnore, expectedRestul); } // No Empty State [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_NoEmptyState_UIAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var expectedResult = string.Join(";", IgnoreCommand.kStartUpMultipleFilesToIgnore); Initialize(expectedResult); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveFormatSettings(); expectedResult += ";" + string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); var filesToIgnore = mFormatOptions.FilesToIgnore; SettingsTestUtility.ResetClangFormatOptionsView(); Assert.Equal(filesToIgnore, expectedResult); } [VsFact(Version = "2019")] public async Task SaveFilesToIgnore_NoEmptyState_ConfigAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); var expectedResult = string.Join(";", IgnoreCommand.kStartUpMultipleFilesToIgnore); Initialize(expectedResult); await IgnoreFilesAsync(IgnoreCommand.kMultipleFilesToIgnore); SettingsHandler.SaveFormatSettings(); if (!File.Exists(kFormatSettingsPath)) Assert.False(true); XmlSerializer serializer = new XmlSerializer(); var formatSettingsModel = serializer.DeserializeFromFile(kFormatSettingsPath); expectedResult += ";" + string.Join(";", IgnoreCommand.kMultipleFilesToIgnore); var filesToIgnore = formatSettingsModel.SkipFiles; SettingsTestUtility.ResetClangFormatOptionsView(); Assert.Equal(filesToIgnore, expectedResult); } #endregion #region Private Methods private void Initialize(string ignoreFiles) { ThreadHelper.ThrowIfNotOnUIThread(); mDte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); SettingsTestUtility.ResetClangFormatOptionsView(); mIgnoreFormatCommand = IgnoreFormatCommand.Instance; mFormatOptions = SettingsProvider.ClangFormatSettings; mFormatOptions.FilesToIgnore = ignoreFiles; } private async Task IgnoreFilesAsync(List aFilesToIgnore) { await System.Threading.Tasks.Task.Run(() => { mIgnoreFormatCommand.AddIgnoreFilesToSettings(aFilesToIgnore); }); } #endregion */ } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/ClangCommandTests/ScriptTests.cs ================================================ using ClangPowerTools.Helpers; using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Microsoft; using Microsoft.VisualStudio.Shell; using System.Collections.Generic; using Xunit; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Tests.ClangCommandTests { [VsTestSettings(UIThread = true)] public class ScriptTests { #region Members private readonly string solutionPath = @"C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln"; // Expected results for files private readonly string compileOnFileExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.vcxproj'' -file ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.cpp'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -parallel -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; private readonly string tidyOnFileExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.vcxproj'' -file ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.cpp'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -tidy ''-*,modernize-avoid-bind,modernize-avoid-c-arrays,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-trailing-return-type,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,modernize-use-using,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-deleted-default,readability-delete-null-pointer,readability-else-after-return,readability-identifier-naming,readability-implicit-bool-conversion,readability-inconsistent-declaration-parameter-name,readability-isolate-declaration,readability-magic-numbers,readability-misleading-indentation,readability-misplaced-array-index,readability-named-parameter,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-preprocessor,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-uppercase-literal-suffix'' -header-filter ''.*'' -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; private readonly string tidyFixOnFileExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.vcxproj'' -file ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocatorTest\CustomAllocatorTest.cpp'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -tidy-fix ''-*,modernize-avoid-bind,modernize-avoid-c-arrays,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-trailing-return-type,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,modernize-use-using,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-deleted-default,readability-delete-null-pointer,readability-else-after-return,readability-identifier-naming,readability-implicit-bool-conversion,readability-inconsistent-declaration-parameter-name,readability-isolate-declaration,readability-magic-numbers,readability-misleading-indentation,readability-misplaced-array-index,readability-named-parameter,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-preprocessor,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-uppercase-literal-suffix'' -header-filter ''.*'' -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; // Expected results for projects private readonly string compileOnProjectExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator\CustomAllocator.vcxproj'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -parallel -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; private readonly string tidyOnProjectExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator\CustomAllocator.vcxproj'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -tidy ''-*,modernize-avoid-bind,modernize-avoid-c-arrays,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-trailing-return-type,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,modernize-use-using,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-deleted-default,readability-delete-null-pointer,readability-else-after-return,readability-identifier-naming,readability-implicit-bool-conversion,readability-inconsistent-declaration-parameter-name,readability-isolate-declaration,readability-magic-numbers,readability-misleading-indentation,readability-misplaced-array-index,readability-named-parameter,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-preprocessor,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-uppercase-literal-suffix'' -header-filter ''.*'' -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; private readonly string tidyFixOnProjectExpectedResult = @"PowerShell.exe -ExecutionPolicy Unrestricted -NoProfile -Noninteractive -command '& ''c:\users\enache ionut\appdata\local\microsoft\visualstudio\16.0_ada83f57exp\extensions\caphyon\clang power tools\5.2.1\clang-build.ps1'' -proj ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator\CustomAllocator.vcxproj'' -active-config ''Debug|x64'' -clang-flags (''-Wall'',''-fms-compatibility-version=19.10'',''-Wmicrosoft'',''-Wno-invalid-token-paste'',''-Wno-unknown-pragmas'',''-Wno-unused-value'') -tidy-fix ''-*,modernize-avoid-bind,modernize-avoid-c-arrays,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-default-member-init,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-trailing-return-type,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,modernize-use-using,readability-avoid-const-params-in-decls,readability-braces-around-statements,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-deleted-default,readability-delete-null-pointer,readability-else-after-return,readability-identifier-naming,readability-implicit-bool-conversion,readability-inconsistent-declaration-parameter-name,readability-isolate-declaration,readability-magic-numbers,readability-misleading-indentation,readability-misplaced-array-index,readability-named-parameter,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-member-init,readability-redundant-preprocessor,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-boolean-expr,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-uppercase-literal-suffix'' -header-filter ''.*'' -vs-ver 2019 -vs-sku Professional -dir ''C:\GitRepos\ClangPowerToolsTests\CustomAllocator\CustomAllocator.sln'' '"; private readonly Dictionary mVsVersions = new Dictionary { {"11.0", "2010"}, {"12.0", "2012"}, {"13.0", "2013"}, {"14.0", "2015"}, {"15.0", "2017"}, {"16.0", "2019"} }; #endregion #region Test Methods #region On File Tests [VsFact(Version = "2019")] public async Task CompileOnFile_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, true); var compileOnFileScriptTestResult = CreateScript(CommandIds.kCompileId, edition, version, item); CloseSolution(); //Assert Assert.Equal(compileOnFileScriptTestResult, compileOnFileExpectedResult); } [VsFact(Version = "2019")] public async Task TidyOnFile_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, true); var tidyOnFileScriptTestResult = CreateScript(CommandIds.kTidyId, edition, version, item); CloseSolution(); //Assert Assert.Equal(tidyOnFileScriptTestResult, tidyOnFileExpectedResult); } [VsFact(Version = "2019")] public async Task TidyFixOnFile_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, true); var tidyFixOnFileScriptTestResult = CreateScript(CommandIds.kTidyFixId, edition, version, item); CloseSolution(); //Assert Assert.Equal(tidyFixOnFileScriptTestResult, tidyFixOnFileExpectedResult); } #endregion #region On Project Tests [VsFact(Version = "2019")] public async Task CompileOnProject_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, false); var compileOnProjectScriptTestResult = CreateScript(CommandIds.kCompileId, edition, version, item); CloseSolution(); //Assert Assert.Equal(compileOnProjectScriptTestResult, compileOnProjectExpectedResult); } [VsFact(Version = "2019")] public async Task TidyOnProject_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, false); var tidyOnProjectScriptTestResult = CreateScript(CommandIds.kTidyId, edition, version, item); CloseSolution(); //Assert Assert.Equal(tidyOnProjectScriptTestResult, tidyOnProjectExpectedResult); } [VsFact(Version = "2019")] public async Task TidyFixOnProject_CreateScript_Async() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var settingsHandler = new SettingsHandler(); //Act LoadSolution(); settingsHandler.ResetSettings(); GetVisualStudioInfo(out string edition, out string version, out IItem item, false); var tidyFixOnProjectScriptTestResult = CreateScript(CommandIds.kTidyFixId, edition, version, item); CloseSolution(); //Assert Assert.Equal(tidyFixOnProjectScriptTestResult, tidyFixOnProjectExpectedResult); } #endregion #endregion #region Private Methods private void LoadSolution() { ThreadHelper.ThrowIfNotOnUIThread(); var dte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); Assumes.Present(dte); dte.Solution.Open(solutionPath); var build = dte.Solution.SolutionBuild; build.Build(true); } private void CloseSolution() { ThreadHelper.ThrowIfNotOnUIThread(); var dte = (DTE2)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); Assumes.Present(dte); dte.Solution.Close(); } private string CreateScript(int commandId, string edition, string version, IItem item) { var runModeParameters = ScriptGenerator.GetRunModeParamaters(); var genericParameters = ScriptGenerator.GetGenericParamaters(commandId, edition, version); var itemRelatedParameters = item is CurrentProject ? ScriptGenerator.GetItemRelatedParameters(item as CurrentProject) : ScriptGenerator.GetItemRelatedParameters(item as CurrentProjectItem); return JoinUtility.Join(" ", runModeParameters.Remove(runModeParameters.Length - 1), itemRelatedParameters, genericParameters, "'"); } private void GetVisualStudioInfo(out string edition, out string version, out IItem item, bool onFile) { ThreadHelper.ThrowIfNotOnUIThread(); var dte = (DTE2)VsServiceProvider.GetService(typeof(DTE)); edition = dte.Edition; mVsVersions.TryGetValue(dte.Version, out string vsVersion); version = vsVersion; item = onFile ? (IItem) new CurrentProjectItem(dte.Solution.Projects.Item(1).ProjectItems.Item(4)) : (IItem) new CurrentProject(dte.Solution.Projects.Item(2)); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/ClangPowerToolsUnitTests.csproj ================================================  net472 x86 all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/Constants/IgnoreCommand.cs ================================================ using System.Collections.Generic; namespace ClangPowerToolsUnitTests.Constants { public class IgnoreCommand { public static readonly List kSingleFileToIgnore = new List() { @"DispatcherHandler.cpp", }; public static readonly List kMultipleFilesToIgnore = new List() { @"DispatcherHandler.cpp", @"VsServiceProviderTests.cpp", @"AsyncPackageTests.cpp" }; public static readonly List kStartUpMultipleFilesToIgnore = new List() { @"CommandController.cpp", @"Settings.cpp", @"Options.cpp" }; } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/PackageTests/AsyncPackageTests.cs ================================================ using Microsoft; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using Xunit; using Task = System.Threading.Tasks.Task; namespace ClangPowerTools.Tests { public class AsyncPackageTests { [VsTheory(Version = "2019")] [InlineData(RunClangPowerToolsPackage.PackageGuidString, true)] [InlineData("11111111-2222-3333-4444-555555555555", false)] public async Task LoadTestAsync(string guidString, bool expectedSuccess) { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); IVsShell7 shell = (IVsShell7)ServiceProvider.GlobalProvider.GetService(typeof(SVsShell)); await UnitTestUtility.LoadPackageAsync(); //Act Assumes.Present(shell); Guid guid = Guid.Parse(guidString); //Assert if (expectedSuccess) { await shell.LoadPackageAsync(ref guid); Assert.True(true, "Package loaded"); } else { Assert.True(true, "Package failed to load"); } } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/Settings Tests/CompilerSettingsTests.cs ================================================ using Xunit; namespace ClangPowerTools.Tests.Settings { [VsTestSettings(UIThread = true)] public class CompilerSettingsTests { [VsFact(Version = "2019-")] public void CompilerSettings_NotNull() { //Arrange var settingsProvider = new SettingsProvider(); //Act var compilerSettingsModel = settingsProvider.GetCompilerSettingsModel(); //Assert Assert.NotNull(compilerSettingsModel); } [VsFact(Version = "2019-")] public void CompileFlags_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { CompileFlags = "-Wall" }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.CompileFlags, settingsProvider.GetCompilerSettingsModel().CompileFlags); } [VsFact(Version = "2019-")] public void FilesToIgnore_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { FilesToIgnore = "Test.cpp" }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.FilesToIgnore, settingsProvider.GetCompilerSettingsModel().FilesToIgnore); } [VsFact(Version = "2019-")] public void ProjectToIgnore_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { ProjectsToIgnore = "TestProject" }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.ProjectsToIgnore, settingsProvider.GetCompilerSettingsModel().ProjectsToIgnore); } [VsFact(Version = "2019-")] public void AdditionalIncludes_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { AdditionalIncludes = ClangGeneralAdditionalIncludes.SystemIncludeDirectories }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.AdditionalIncludes, settingsProvider.GetCompilerSettingsModel().AdditionalIncludes); } [VsFact(Version = "2019-")] public void TreatWarningsAsErrors_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { WarningsAsErrors = true }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.WarningsAsErrors, settingsProvider.GetCompilerSettingsModel().WarningsAsErrors); } [VsFact(Version = "2019-")] public void ContinueOnError_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { ContinueOnError = true }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.ContinueOnError, settingsProvider.GetCompilerSettingsModel().ContinueOnError); } [VsFact(Version = "2019-")] public void ClangCompileAfterVsCompile_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { ClangAfterMSVC = true }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.ClangAfterMSVC, settingsProvider.GetCompilerSettingsModel().ClangAfterMSVC); } [VsFact(Version = "2019-")] public void VerboseMode_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var compilerSettingsModel = new CompilerSettingsModel { VerboseMode = true }; settingsProvider.SetCompilerSettingsModel(compilerSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(compilerSettingsModel.VerboseMode, settingsProvider.GetCompilerSettingsModel().VerboseMode); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/Settings Tests/FormatSettingsTests.cs ================================================ using Xunit; namespace ClangPowerTools.Tests.Settings { [VsTestSettings(UIThread = true)] public class FormatSettingsTests { [VsFact(Version = "2019-")] public void FormatSettings_NotNull() { //Arrange var settingsProvider = new SettingsProvider(); //Act var formatSettingsModel = settingsProvider.GetFormatSettingsModel(); //Assert Assert.NotNull(formatSettingsModel); } [VsFact(Version = "2019-")] public void FormatOnSave_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { FormatOnSave = true }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.FormatOnSave, settingsProvider.GetFormatSettingsModel().FormatOnSave); } [VsFact(Version = "2019-")] public void FileExtensions_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { FileExtensions = ".cpp" }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.FileExtensions, settingsProvider.GetFormatSettingsModel().FileExtensions); } [VsFact(Version = "2019-")] public void FilesToIgnore_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { FilesToIgnore = "Test.cpp" }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.FilesToIgnore, settingsProvider.GetFormatSettingsModel().FilesToIgnore); } [VsFact(Version = "2019-")] public void AssumeFilename_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { AssumeFilename = "Test" }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.AssumeFilename, settingsProvider.GetFormatSettingsModel().AssumeFilename); } [VsFact(Version = "2019-")] public void FallbackStyle_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { FallbackStyle = ClangFormatFallbackStyle.Mozilla }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.FallbackStyle, settingsProvider.GetFormatSettingsModel().FallbackStyle); } [VsFact(Version = "2019-")] public void FormatStyle_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { Style = ClangFormatStyle.Mozilla }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.Style, settingsProvider.GetFormatSettingsModel().Style); } [VsFact(Version = "2019-")] public void CustomExecutable_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var formatSettingsModel = new FormatSettingsModel { CustomExecutable = @"D:\Test.exe" }; settingsProvider.SetFormatSettingsModel(formatSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(formatSettingsModel.CustomExecutable, settingsProvider.GetFormatSettingsModel().CustomExecutable); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/Settings Tests/GeneralSettingsTests.cs ================================================ using Xunit; namespace ClangPowerTools.Tests.Settings { [VsTestSettings(UIThread = true)] public class GeneralSettingsTests { [VsFact(Version = "2019-")] public void GeneralSettings_NotNull() { //Arrange var settingsProvider = new SettingsProvider(); //Act var generalSettingsModel = settingsProvider.GetGeneralSettingsModel(); //Assert Assert.NotNull(generalSettingsModel); } [VsFact(Version ="2019-")] public void Version_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var generalSettingsModel = new GeneralSettingsModel { Version = "5.0.0" }; settingsProvider.SetGeneralSettingsModel(generalSettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(generalSettingsModel.Version, settingsProvider.GetGeneralSettingsModel().Version); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/Settings Tests/TidySettingsTests.cs ================================================ using System.Collections.Generic; using System.Text; using Xunit; namespace ClangPowerTools.Tests.Settings { [VsTestSettings(UIThread = true)] public class TidySettingsTests { [VsFact(Version = "2019-")] public void TidySettings_NotNull() { //Arrange var settingsProvider = new SettingsProvider(); //Act var tidySettingsModel = settingsProvider.GetTidySettingsModel(); //Assert Assert.NotNull(tidySettingsModel); } [VsFact(Version = "2019-")] public void FormatAfterTidy_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { FormatAfterTidy = true }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.FormatAfterTidy, settingsProvider.GetTidySettingsModel().FormatAfterTidy); } [VsFact(Version = "2019-")] public void ClangTidyOnSave_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { TidyOnSave = true }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.TidyOnSave, settingsProvider.GetTidySettingsModel().TidyOnSave); } [VsFact(Version = "2019-")] public void HeaderFilter_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { HeaderFilter = "test" }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.HeaderFilter, settingsProvider.GetTidySettingsModel().HeaderFilter); } [VsFact(Version = "2019-")] public void ChecksFrom_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { UseChecksFrom = ClangTidyUseChecksFrom.TidyFile }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.UseChecksFrom, settingsProvider.GetTidySettingsModel().UseChecksFrom); } [VsFact(Version = "2019-")] public void CustomExecutable_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { CustomExecutable = @"D:\Test.exe" }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.CustomExecutable, settingsProvider.GetTidySettingsModel().CustomExecutable); } [VsFact(Version = "2019-")] public void PredefinedChecks_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidyChecks = new TidyChecks(); var tidyPredefinedChecks = new List(tidyChecks.Checks); var checks = new StringBuilder(); tidyPredefinedChecks[0].IsChecked = true; foreach (TidyCheckModel item in tidyPredefinedChecks) { if (item.IsChecked) { checks.Append(item.Name).Append(";"); } } var tidySettingsModel = new TidySettingsModel { PredefinedChecks = checks.ToString() }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.PredefinedChecks, settingsProvider.GetTidySettingsModel().PredefinedChecks); } [VsFact(Version = "2019-")] public void CustomChecks_ChangeValue_CompareViewToFile() { var settingsHandler = new SettingsHandler(); var settingsProvider = new SettingsProvider(); var tidySettingsModel = new TidySettingsModel { CustomChecks = "test-check" }; settingsProvider.SetTidySettingsModel(tidySettingsModel); settingsHandler.SaveSettings(); settingsHandler.ResetSettings(); settingsHandler.LoadSettings(); Assert.Equal(tidySettingsModel.CustomChecks, settingsProvider.GetTidySettingsModel().CustomChecks); } } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/VSVersionTests.cs ================================================ using Xunit; namespace ClangPowerTools.Tests { [VsTestSettings(UIThread = true)] public class VsVersionTests { #region Test Methods //[VsFact(Version = "2015")] //public void RunVisualStudio2015_Test() //{ // Assert.Equal("14.0", UnitTestUtility.GetVsVersion()); //} [VsFact(Version = "2017")] public void RunVisualStudio2017() { Assert.Equal("15.0", UnitTestUtility.GetVsVersion()); } [VsFact(Version = "2019")] public void RunVisualStudio2019() { Assert.Equal("16.0", UnitTestUtility.GetVsVersion()); } #endregion } } ================================================ FILE: ClangPowerTools/ClangPowerToolsUnitTests/VsServiceProviderTests.cs ================================================ using ClangPowerTools.Services; using EnvDTE; using EnvDTE80; using Xunit; using Microsoft.VisualStudio.Shell; using Task = System.Threading.Tasks.Task; using Microsoft.VisualStudio.Shell.Interop; namespace ClangPowerTools.Tests { [VsTestSettings(UIThread = true)] public class VsServiceProviderTests { #region Test Methods [VsFact(Version = "2019")] public async Task DteService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(DTE), out object dteService); //Assert Assert.NotNull(dteService as DTE); } [VsFact(Version = "2019")] public async Task Dte2Service_SuccessfulRegistrationAsync() { // Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(DTE), out object dteService); // Assert Assert.NotNull(dteService as DTE2); } [VsFact(Version = "2019")] public async Task OutputWindowService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(SVsOutputWindow), out object outputWindowService); // Assert Assert.NotNull(outputWindowService as IVsOutputWindow); } // ---------------------------------------------------------------------------- [VsFact(Version = "2019")] public async Task VsStatusbarService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(SVsStatusbar), out object statusBarService); // Assert Assert.NotNull(statusBarService as IVsStatusbar); } [VsFact(Version = "2019")] public async Task RunningDocumentTableService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(SVsRunningDocumentTable), out object runningDocumentTableService); // Assert Assert.NotNull(runningDocumentTableService as IVsRunningDocumentTable); } [VsFact(Version = "2019")] public async Task FileChangeService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(SVsFileChangeEx), out object fileChangeService); // Assert Assert.NotNull(fileChangeService as IVsFileChangeEx); } [VsFact(Version = "2019")] public async Task SolutionService_SuccessfulRegistrationAsync() { //Arrange await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await UnitTestUtility.LoadPackageAsync(); VsServiceProvider.TryGetService(typeof(SVsSolution), out object vsSolutionService); // Assert Assert.NotNull(vsSolutionService as IVsSolution); } #endregion } } ================================================ FILE: ClangPowerTools/VsixAI/InfoDocument.txt ================================================ Here i will generate ClangPowerTools.vsix and ClangPowerTools2022.vsix ================================================ FILE: LICENSE.TXT ================================================ ============================================================================== Apache License v2.0 with LLVM Exceptions: ============================================================================== Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. ============================================================================== Software from third parties included in the LLVM Project: ============================================================================== The LLVM Project contains third party software which is under different license terms. All such code will be identified clearly using at least one of two mechanisms: 1) It will be in a separate directory tree with its own `LICENSE.txt` or `LICENSE` file at the top containing the specific license and restrictions which apply to that software, or 2) It will contain specific license and restriction terms at the top of every file. ============================================================================== Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ================================================ FILE: README.md ================================================ # Clang Power Tools A tool bringing clang-tidy magic to Visual Studio C++ developers. [www.clangpowertools.com](http://www.clangpowertools.com) ### Version History [Release Notes](http://www.clangpowertools.com/CHANGELOG) ### FAQ [Frequently asked questions](http://www.clangpowertools.com/QaA)