├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ └── pr.yml ├── .gitignore ├── Directory.Build.props ├── LICENSE ├── NuGet.Config ├── README.md ├── ReferenceTrimmer.sln ├── examples └── BuildWithReferenceTrimmer.cmd ├── global.json ├── src ├── Analyzer │ ├── ReferenceTrimmer.Analyzer.csproj │ └── ReferenceTrimmerAnalyzer.cs ├── Loggers │ ├── MSVC │ │ ├── CentralLogger.cs │ │ ├── ForwardingLogger.cs │ │ └── UnusedLibsCustomBuildEventArgs.cs │ └── ReferenceTrimmer.Loggers.csproj ├── Package │ ├── ReferenceTrimmer.Package.csproj │ ├── build │ │ ├── ReferenceTrimmer.props │ │ └── ReferenceTrimmer.targets │ ├── buildMultiTargeting │ │ ├── ReferenceTrimmer.props │ │ └── ReferenceTrimmer.targets │ └── tools │ │ ├── install.ps1 │ │ └── uninstall.ps1 ├── Shared │ ├── DeclaredReferences.cs │ └── NetStandardPolyfills.cs ├── Tasks │ ├── CollectDeclaredReferencesTask.cs │ └── ReferenceTrimmer.Tasks.csproj └── Tests │ ├── E2ETests.cs │ ├── MsvcLoggerTests.cs │ ├── ReferenceTrimmer.Tests.csproj │ └── TestData │ ├── AbsoluteIntermediateOutputPath │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── BuildExtensions │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── BuildPackageReference │ └── Library │ │ └── Library.csproj │ ├── Directory.Build.props │ ├── Directory.Build.targets │ ├── LegacyStyleProject │ └── Library │ │ ├── Class1.cs │ │ ├── Library.csproj │ │ └── Properties │ │ └── AssemblyInfo.cs │ ├── MissingReferenceSourceTarget │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── NoTargets │ └── Project.csproj │ ├── NuGet.Config │ ├── PackageReferenceWithFakeBuildFile │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── PlatformPackageConflictResolution │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── ReferenceInPackage │ └── Tests │ │ ├── FooTests.cs │ │ └── Tests.csproj │ ├── ReferenceTrimmerDisabled │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── TargetFrameworkWithOs │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedCppDelayLoadLibrary │ ├── App │ │ ├── App.cpp │ │ └── App.vcxproj │ └── Dll │ │ ├── DLL.vcxproj │ │ ├── dllmain.cpp │ │ ├── framework.h │ │ ├── pch.cpp │ │ └── pch.h │ ├── UnusedCppLibrary │ ├── App │ │ ├── App.cpp │ │ └── App.vcxproj │ └── Library │ │ ├── Library.cpp │ │ └── Library.vcxproj │ ├── UnusedDirectAndTransitiveProjectReference │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ ├── Library │ │ ├── Library.cs │ │ └── Library.csproj │ └── TransitiveDependency │ │ ├── TransitiveDependency.cs │ │ └── TransitiveDependency.csproj │ ├── UnusedPackageReference │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedPackageReferenceDocDisabled │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedPackageReferenceNoWarn │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedPackageReferenceTreatAsUsed │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReference │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReferenceNoReferenceAssembly │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReferenceNoWarn │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReferenceProduceReferenceAssembly │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReferenceSuppressed │ ├── .globalconfig │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedProjectReferenceTreatAsUsed │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceFromGac │ ├── Class1.cs │ ├── Library.csproj │ └── Properties │ │ └── AssemblyInfo.cs │ ├── UnusedReferenceHintPath │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceHintPathNoWarn │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceHintPathTreatAsUsed │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceItemSpec │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceItemSpecNoWarn │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedReferenceItemSpecTreatAsUsed │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UnusedTransitiveProjectReference │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ ├── Library │ │ ├── Library.cs │ │ └── Library.csproj │ └── TransitiveDependency │ │ ├── TransitiveDependency.cs │ │ └── TransitiveDependency.csproj │ ├── UnusedWinSdkImportLibrary │ └── App │ │ ├── App.cpp │ │ ├── App.vcxproj │ │ └── util.cpp │ ├── UsedIndirectPackageReference │ └── WebHost │ │ ├── Program.cs │ │ └── WebHost.csproj │ ├── UsedPackageReference │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UsedProjectReference │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UsedProjectReferenceNoReferenceAssembly │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UsedProjectReferenceProduceReferenceAssembly │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UsedReferenceFromGac │ ├── Class1.cs │ ├── Library.csproj │ └── Properties │ │ └── AssemblyInfo.cs │ ├── UsedReferenceHintPath │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ ├── UsedReferenceItemSpec │ ├── Dependency │ │ ├── Dependency.cs │ │ └── Dependency.csproj │ └── Library │ │ ├── Library.cs │ │ └── Library.csproj │ └── WpfApp │ ├── Dependency │ ├── Dependency.cs │ └── Dependency.csproj │ └── WpfApp │ ├── App.xaml │ ├── App.xaml.cs │ ├── AssemblyInfo.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ └── WpfApp.csproj └── version.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test - CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - "v*" 9 | # Allow manually triggering 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | # TODO: Add ubuntu-latest 15 | runs-on: windows-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 # Git Versioning requires a non-shallow clone 20 | 21 | - name: Setup .NET 22 | uses: actions/setup-dotnet@v3 23 | 24 | - name: Run vcvarsall.bat on Windows for MSVC testing 25 | uses: ilammy/msvc-dev-cmd@v1 26 | 27 | - name: Restore 28 | run: dotnet restore -bl:logs/restore.binlog 29 | 30 | - name: Build 31 | run: dotnet build --configuration Release --no-restore -bl:logs/build.binlog 32 | 33 | - name: Test 34 | run: dotnet test --configuration Release --no-build --logger trx --results-directory TestResults --collect:"Code Coverage;Format=Cobertura" 35 | 36 | # - name: Upload coverage to Codecov 37 | # uses: codecov/codecov-action@v4 38 | # with: 39 | # directory: ./TestResults 40 | # files: "*.cobertura.xml" 41 | 42 | - name: Upload test results 43 | uses: actions/upload-artifact@v4 44 | with: 45 | name: test-results 46 | path: ./TestResults 47 | if: ${{ always() }} # Always run this step even on failure 48 | 49 | - name: Upload logs 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: logs 53 | path: ./logs 54 | if: ${{ always() }} # Always run this step even on failure 55 | 56 | - name: Upload artifacts 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: artifacts 60 | path: ./artifacts 61 | if: ${{ always() }} # Always run this step even on failure 62 | 63 | - name: Push NuGet package 64 | run: dotnet nuget push artifacts\*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate 65 | if: startsWith(github.ref, 'refs/tags/v') 66 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | os: [windows-latest, ubuntu-latest] 13 | runs-on: ${{ matrix.os }} 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 # Git Versioning requires a non-shallow clone 18 | 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v3 21 | 22 | - name: Run vcvarsall.bat on Windows for MSVC testing 23 | uses: ilammy/msvc-dev-cmd@v1 24 | 25 | - name: Restore 26 | run: dotnet restore -bl:logs/restore.binlog 27 | 28 | - name: Build 29 | run: dotnet build --configuration Release --no-restore -bl:logs/build.binlog 30 | 31 | - name: Test 32 | run: dotnet test --configuration Release --no-build --logger trx --results-directory TestResults --collect:"Code Coverage;Format=Cobertura" 33 | 34 | # - name: Upload coverage to Codecov 35 | # uses: codecov/codecov-action@v4 36 | # with: 37 | # directory: ./TestResults 38 | # files: "*.cobertura.xml" 39 | 40 | - name: Upload test results 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: test-results-${{ matrix.os }} 44 | path: ./TestResults 45 | if: ${{ always() }} # Always run this step even on failure 46 | 47 | - name: Upload logs 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: logs-${{ matrix.os }} 51 | path: ./logs 52 | if: ${{ always() }} # Always run this step even on failure 53 | 54 | - name: Upload artifacts 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: artifacts-${{ matrix.os }} 58 | path: ./artifacts 59 | if: ${{ always() }} # Always run this step even on failure 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.binlog 70 | *.vspscc 71 | *.vssscc 72 | .builds 73 | *.pidb 74 | *.svclog 75 | *.scc 76 | 77 | # Chutzpah Test files 78 | _Chutzpah* 79 | 80 | # Visual C++ cache files 81 | ipch/ 82 | *.aps 83 | *.ncb 84 | *.opendb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | *.VC.db 89 | *.VC.VC.opendb 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | *.sap 96 | 97 | # TFS 2012 Local Workspace 98 | $tf/ 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | *.DotSettings.user 107 | 108 | # JustCode is a .NET coding add-in 109 | .JustCode 110 | 111 | # TeamCity is a build add-in 112 | _TeamCity* 113 | 114 | # DotCover is a Code Coverage Tool 115 | *.dotCover 116 | 117 | # Visual Studio code coverage results 118 | *.coverage 119 | *.coveragexml 120 | 121 | # NCrunch 122 | _NCrunch_* 123 | .*crunch*.local.xml 124 | nCrunchTemp_* 125 | 126 | # MightyMoose 127 | *.mm.* 128 | AutoTest.Net/ 129 | 130 | # Web workbench (sass) 131 | .sass-cache/ 132 | 133 | # Installshield output folder 134 | [Ee]xpress/ 135 | 136 | # DocProject is a documentation generator add-in 137 | DocProject/buildhelp/ 138 | DocProject/Help/*.HxT 139 | DocProject/Help/*.HxC 140 | DocProject/Help/*.hhc 141 | DocProject/Help/*.hhk 142 | DocProject/Help/*.hhp 143 | DocProject/Help/Html2 144 | DocProject/Help/html 145 | 146 | # Click-Once directory 147 | publish/ 148 | 149 | # Publish Web Output 150 | *.[Pp]ublish.xml 151 | *.azurePubxml 152 | # TODO: Comment the next line if you want to checkin your web deploy settings 153 | # but database connection strings (with potential passwords) will be unencrypted 154 | *.pubxml 155 | *.publishproj 156 | 157 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 158 | # checkin your Azure Web App publish settings, but sensitive information contained 159 | # in these scripts will be unencrypted 160 | PublishScripts/ 161 | 162 | # NuGet Packages 163 | *.nupkg 164 | # The packages folder can be ignored because of Package Restore 165 | **/packages/* 166 | # except build/, which is used as an MSBuild target. 167 | !**/packages/build/ 168 | # Uncomment if necessary however generally it will be regenerated when needed 169 | #!**/packages/repositories.config 170 | # NuGet v3's project.json files produces more ignorable files 171 | *.nuget.props 172 | *.nuget.targets 173 | 174 | # Microsoft Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Microsoft Azure Emulator 179 | ecf/ 180 | rcf/ 181 | 182 | # Windows Store app package directories and files 183 | AppPackages/ 184 | BundleArtifacts/ 185 | Package.StoreAssociation.xml 186 | _pkginfo.txt 187 | 188 | # Visual Studio cache files 189 | # files ending in .cache can be ignored 190 | *.[Cc]ache 191 | # but keep track of directories ending in .cache 192 | !*.[Cc]ache/ 193 | 194 | # Others 195 | ClientBin/ 196 | ~$* 197 | *~ 198 | *.dbmdl 199 | *.dbproj.schemaview 200 | *.jfm 201 | *.pfx 202 | *.publishsettings 203 | orleans.codegen.cs 204 | 205 | # Since there are multiple workflows, uncomment next line to ignore bower_components 206 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 207 | #bower_components/ 208 | 209 | # RIA/Silverlight projects 210 | Generated_Code/ 211 | 212 | # Backup & report files from converting an old project file 213 | # to a newer Visual Studio version. Backup files are not needed, 214 | # because we have git ;-) 215 | _UpgradeReport_Files/ 216 | Backup*/ 217 | UpgradeLog*.XML 218 | UpgradeLog*.htm 219 | 220 | # SQL Server files 221 | *.mdf 222 | *.ldf 223 | *.ndf 224 | 225 | # Business Intelligence projects 226 | *.rdl.data 227 | *.bim.layout 228 | *.bim_*.settings 229 | 230 | # Microsoft Fakes 231 | FakesAssemblies/ 232 | 233 | # GhostDoc plugin setting file 234 | *.GhostDoc.xml 235 | 236 | # Node.js Tools for Visual Studio 237 | .ntvs_analysis.dat 238 | node_modules/ 239 | 240 | # Typescript v1 declaration files 241 | typings/ 242 | 243 | # Visual Studio 6 build log 244 | *.plg 245 | 246 | # Visual Studio 6 workspace options file 247 | *.opt 248 | 249 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 250 | *.vbw 251 | 252 | # Visual Studio LightSwitch build output 253 | **/*.HTMLClient/GeneratedArtifacts 254 | **/*.DesktopClient/GeneratedArtifacts 255 | **/*.DesktopClient/ModelManifest.xml 256 | **/*.Server/GeneratedArtifacts 257 | **/*.Server/ModelManifest.xml 258 | _Pvt_Extensions 259 | 260 | # Paket dependency manager 261 | .paket/paket.exe 262 | paket-files/ 263 | 264 | # FAKE - F# Make 265 | .fake/ 266 | 267 | # JetBrains Rider 268 | .idea/ 269 | *.sln.iml 270 | 271 | # CodeRush 272 | .cr/ 273 | 274 | # Python Tools for Visual Studio (PTVS) 275 | __pycache__/ 276 | *.pyc 277 | 278 | # Cake - Uncomment if you are using it 279 | # tools/** 280 | # !tools/packages.config 281 | 282 | # Telerik's JustMock configuration file 283 | *.jmconfig 284 | 285 | # BizTalk build output 286 | *.btp.cs 287 | *.btm.cs 288 | *.odx.cs 289 | *.xsd.cs 290 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | $(MSBuildThisFileDirectory.TrimEnd('\\')) 12 | Enable 13 | 14 | 15 | true 16 | true 17 | 18 | 19 | true 20 | true 21 | Recommended 22 | 23 | 24 | true 25 | 26 | 27 | Enable 28 | 29 | Latest 30 | 31 | 32 | embedded 33 | 34 | 38 | false 39 | 40 | 41 | 42 | 43 | David Federman 44 | © David Federman. All rights reserved. 45 | Easily identify which dependencies can be removed from an MSBuild project. 46 | https://github.com/dfederm/ReferenceTrimmer 47 | https://github.com/dfederm/ReferenceTrimmer.git 48 | MIT 49 | 50 | 51 | 52 | 53 | true 54 | true 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 David Federman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReferenceTrimmer 2 | [![NuGet Version](https://img.shields.io/nuget/v/ReferenceTrimmer.svg)](https://www.nuget.org/packages/ReferenceTrimmer) 3 | [![NuGet Downloads](https://img.shields.io/nuget/dt/ReferenceTrimmer.svg)](https://www.nuget.org/packages/ReferenceTrimmer) 4 | 5 | Easily identify which C# dependencies can be removed from an MSBuild project, and expose MSVC output to show unused libraries and delay-load DLLs at link time. Removing project dependencies flattens your build dependency graph which can improve build parallelism and reduce end-to-end build time. 6 | 7 | ## Rules 8 | The following warnings are generated by this package: 9 | 10 | | Id | Description | 11 | |--------|-------------| 12 | | RT0000 | Enable documentation generation for accuracy of used references detection | 13 | | RT0001 | Unnecessary reference | 14 | | RT0002 | Unnecessary project reference | 15 | | RT0003 | Unnecessary package reference | 16 | 17 | ## How to use 18 | Add a package reference to the [ReferenceTrimmer](https://www.nuget.org/packages/ReferenceTrimmer) package in your projects, or as a common package reference in the repo's [`Directory.Packages.props`](./Directory.Build.props). 19 | 20 | If you're using [Central Package Management](https://learn.microsoft.com/en-us/nuget/consume-packages/Central-Package-Management), you can use it as a `GlobalPackageReference` in your `Directory.Packages.props` to apply it to the entire repo. 21 | 22 | ```xml 23 | 24 | 25 | 26 | ``` 27 | 28 | ### C# 29 | You'll need to enable C# documentation XML generation to ensure good analysis results. If your repo is not already using docxml globally, this can introduce a large number of errors and warnings specific to docxml. Additionally, turning on docxml adds additional output I/O that can slow down large repos. 30 | 31 | You can turn off specific docxml related warnings and errors while defaulting ReferenceTrimmer to off using a block of code like this in your `Directory.Build.props`. Turn on the ReferenceTrimmer build by setting `/p:EnableReferenceTrimmer=true` on the MSBuild command line or setting the same property value as an environment variable. You could create a separate build pipeline for your repo to run ReferenceTrimmer builds. 32 | 33 | ```xml 34 | 35 | 36 | false 37 | 38 | 39 | 40 | true 41 | 42 | 51 | $(NoWarn);419;1570;1573;1574;1584;1591;SA1602 52 | 53 | ``` 54 | 55 | Note: To get better results, enable the [`IDE0005`](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005) unnecessary `using` rule. This avoids the C# compiler seeing a false positive assembly usage from unneeded `using` directives causing it to miss a removable dependency. See also the note for why IDE0005 code analysis rule requires `` property to be enabled. Documentation generation is also required for accuracy of used references detection (based on https://github.com/dotnet/roslyn/issues/66188). 56 | 57 | ### C++ (.vcxproj projects) 58 | ReferenceTrimmer for C++ is an MSBuild [distributed logger](https://learn.microsoft.com/en-us/visualstudio/msbuild/logging-in-a-multi-processor-environment?view=vs-2022). It writes guidance to the MSBuild stdout stream (not to the MSBuild internal logger at this time) and writes `ReferenceTrimmerUnusedMSVCLibraries.json.log` to the build working directory. 59 | 60 | The distributed logger requires configuration at the MSBuild command line using the `-distributedlogger` parameter. See the [BuildWithReferenceTrimmer example script](./examples/BuildWithReferenceTrimmer.cmd) for how to orchestrate pulling and using the package's loggers. 61 | 62 | Use `msbuild -restore` or `msbuild /t:Restore` instead of `dotnet restore` to ensure .vcxproj restore will work to add the ReferenceTrimmer props and targets to your build. *NOTE*: If you are seeing a `Sequence contains no elements` exception from MSBuild, see https://github.com/dotnet/NuGet.BuildTasks/issues/154 for a workaround or status on a fix. 63 | 64 | The current implementation turns on MSVC `link.exe` flags `/VERBOSE:UNUSEDLIBS` and `/VERBOSE:UNUSEDDELAYLOAD`. These flags tell the linker to print out unused .lib files and delay-load DLLs to stdout. This will include .lib files containing code bundles as well as import libraries for DLLs. Removing these libraries reduces I/O and memory usage by the linker. Here's an example of the linker output: 65 | 66 | ```text 67 | Unused libraries: 68 | C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\um\x64\gdi32.lib 69 | C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\um\x64\winspool.lib 70 | C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\um\x64\comdlg32.lib 71 | ``` 72 | 73 | ReferenceTrimmer reads this output and splits the resulting libraries into two sets: 74 | 75 | #### Windows SDK import libraries 76 | The Microsoft C++ SDK for MSBuild includes in the `AdditionalDependencies` property a default list of Win32 import libraries like kernel32.lib and user32.lib. You can find the default list in your local VS installation by searching: 77 | 78 | ```cmd 79 | findstr /s CoreLibraryDependencies "\Program Files"\*props 80 | ``` 81 | 82 | To disable these, modify the vcxproj `` property to just the list of SDK .lib files needed for the project, and do not add `%(AdditionalDependencies)` to the property to avoid the default list. Example: 83 | 84 | ```xml 85 | 86 | 87 | kernel32.lib;shlwapi.lib;ws2_32.lib 88 | 89 | 90 | ``` 91 | 92 | Not all SDK .lib files can be removed this way. You might need to use `` as well: 93 | 94 | ```xml 95 | 96 | 97 | OLDNAMES.lib;%(IgnoreSpecificDefaultLibraries) 98 | 99 | 100 | ``` 101 | 102 | #### Package or Project libraries 103 | If you find an unused .lib that is created by a .vcxproj in your repo, you should be able to remove the `ProjectReference` to that vcxproj to improve your build dependency graph and allow greater parallelism during build. 104 | 105 | If you find an unused .lib that is from a package, remove the reference to that .lib from your project to speed up linking. 106 | 107 | ## Disabling a rule on a reference 108 | To turn off a rule on a specific project or package reference, add the relevant RTxxxx code to a NoWarn metadata attribute. For example: 109 | 110 | ```xml 111 | 112 | ``` 113 | 114 | ## Configuration 115 | `$(EnableReferenceTrimmer)` - Controls whether the build logic should run for a given project. Defaults to `true`. 116 | 117 | `$(ReferenceTrimmerEnableVcxproj)` - Controls whether MSVC link flags are set up to print out unused libraries and delay-load DLLs. Defaults to `true`. 118 | 119 | ## How does it work? 120 | 121 | ### C# 122 | There are two main pieces to C# support. First there is an MSBuild task which collects all references passed to the compiler. There is also a Roslyn Analyzer which uses the [`GetUsedAssemblyReferences`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.compilation.getusedassemblyreferences) analyzer API which is available starting with Roslyn compiler that shipped with Visual Studio 2019 version 16.10, .NET 5. (see https://github.com/dotnet/roslyn/blob/main/docs/wiki/NuGet-packages.md#versioning). This is the compiler telling us exactly what references were needed as part of compilation. The analyzer then compares the set of references the Task gathered with the references the compiler says were used. 123 | 124 | ### C++ (.vcxproj projects) 125 | ReferenceTrimmer enables the MSVC `link.exe` flags noted above, then parses output coming from the `Link` MSBuild task. It categorizes the outputs and emits them into the MSBuild console output and the JSON output file noted above. It does not issue MSBuild warnings at this time. 126 | 127 | ## Future development 128 | The outcome of https://github.com/dotnet/sdk/issues/10414 may be of use for `ReferenceTrimmer` future updates. 129 | -------------------------------------------------------------------------------- /ReferenceTrimmer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8ED5F7AF-CA4B-4D0E-B5C0-5AF98E065315}" 7 | ProjectSection(SolutionItems) = preProject 8 | .editorconfig = .editorconfig 9 | .gitignore = .gitignore 10 | Directory.Build.props = Directory.Build.props 11 | Directory.Build.rsp = Directory.Build.rsp 12 | global.json = global.json 13 | LICENSE = LICENSE 14 | NuGet.Config = NuGet.Config 15 | README.md = README.md 16 | version.json = version.json 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A2BF83-6DB4-4DB9-9B49-4237731A6627}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceTrimmer.Tasks", "src\Tasks\ReferenceTrimmer.Tasks.csproj", "{70B8B49A-03B2-48DE-ACB4-C801F1201C1E}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceTrimmer.Analyzer", "src\Analyzer\ReferenceTrimmer.Analyzer.csproj", "{6E7F5033-F180-4A47-9552-96C3DC3FDA06}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceTrimmer.Tests", "src\Tests\ReferenceTrimmer.Tests.csproj", "{3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}" 26 | EndProject 27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceTrimmer.Package", "src\Package\ReferenceTrimmer.Package.csproj", "{4C15C9AF-25D5-4725-BFB9-5C04533420AB}" 28 | EndProject 29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferenceTrimmer.Loggers", "src\Loggers\ReferenceTrimmer.Loggers.csproj", "{CE532C1F-579C-402C-A408-51713A54E879}" 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Debug|x64 = Debug|x64 35 | Release|Any CPU = Release|Any CPU 36 | Release|x64 = Release|x64 37 | EndGlobalSection 38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 39 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Debug|x64.ActiveCfg = Debug|Any CPU 42 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Debug|x64.Build.0 = Debug|Any CPU 43 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Release|x64.ActiveCfg = Release|Any CPU 46 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E}.Release|x64.Build.0 = Release|Any CPU 47 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Debug|x64.ActiveCfg = Debug|Any CPU 50 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Debug|x64.Build.0 = Debug|Any CPU 51 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Release|x64.ActiveCfg = Release|Any CPU 54 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06}.Release|x64.Build.0 = Release|Any CPU 55 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Debug|x64.ActiveCfg = Debug|x64 58 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Debug|x64.Build.0 = Debug|x64 59 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Release|x64.ActiveCfg = Release|x64 62 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA}.Release|x64.Build.0 = Release|x64 63 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Debug|x64.ActiveCfg = Debug|Any CPU 66 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Debug|x64.Build.0 = Debug|Any CPU 67 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Release|Any CPU.ActiveCfg = Release|Any CPU 68 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Release|Any CPU.Build.0 = Release|Any CPU 69 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Release|x64.ActiveCfg = Release|Any CPU 70 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB}.Release|x64.Build.0 = Release|Any CPU 71 | {CE532C1F-579C-402C-A408-51713A54E879}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 72 | {CE532C1F-579C-402C-A408-51713A54E879}.Debug|Any CPU.Build.0 = Debug|Any CPU 73 | {CE532C1F-579C-402C-A408-51713A54E879}.Debug|x64.ActiveCfg = Debug|Any CPU 74 | {CE532C1F-579C-402C-A408-51713A54E879}.Debug|x64.Build.0 = Debug|Any CPU 75 | {CE532C1F-579C-402C-A408-51713A54E879}.Release|Any CPU.ActiveCfg = Release|Any CPU 76 | {CE532C1F-579C-402C-A408-51713A54E879}.Release|Any CPU.Build.0 = Release|Any CPU 77 | {CE532C1F-579C-402C-A408-51713A54E879}.Release|x64.ActiveCfg = Release|Any CPU 78 | {CE532C1F-579C-402C-A408-51713A54E879}.Release|x64.Build.0 = Release|Any CPU 79 | EndGlobalSection 80 | GlobalSection(SolutionProperties) = preSolution 81 | HideSolutionNode = FALSE 82 | EndGlobalSection 83 | GlobalSection(NestedProjects) = preSolution 84 | {70B8B49A-03B2-48DE-ACB4-C801F1201C1E} = {49A2BF83-6DB4-4DB9-9B49-4237731A6627} 85 | {6E7F5033-F180-4A47-9552-96C3DC3FDA06} = {49A2BF83-6DB4-4DB9-9B49-4237731A6627} 86 | {3099F4D8-0CFA-4819-A6A7-2BDFED107FFA} = {49A2BF83-6DB4-4DB9-9B49-4237731A6627} 87 | {4C15C9AF-25D5-4725-BFB9-5C04533420AB} = {49A2BF83-6DB4-4DB9-9B49-4237731A6627} 88 | {CE532C1F-579C-402C-A408-51713A54E879} = {49A2BF83-6DB4-4DB9-9B49-4237731A6627} 89 | EndGlobalSection 90 | GlobalSection(ExtensibilityGlobals) = postSolution 91 | SolutionGuid = {1E4FD4B2-8674-4378-AAC7-9C14865D333A} 92 | EndGlobalSection 93 | EndGlobal 94 | -------------------------------------------------------------------------------- /examples/BuildWithReferenceTrimmer.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | @rem Builds with ReferenceTrimmer C# and C++ modes 3 | @rem Assumes RefTrim is wired into Directory.Build.props or Directory.Packages.props as a global package reference. 4 | @rem Usage: BuildWithReferenceTrimmer [msbuild args] 5 | setlocal EnableDelayedExpansion 6 | 7 | @rem Explicitly turn on in case the repo is defaulting to false. 8 | set EnableReferenceTrimmer=true 9 | 10 | @echo Restoring with ReferenceTrimmer enabled 11 | call msbuild /t:Restore 12 | 13 | @rem Find the RefTrim latest package in the package store. 14 | set NuGetPkgBase=%NUGET_PACKAGES% 15 | if "%NuGetPkgBase%"=="" set NuGetPkgBase=%USERPROFILE%\.nuget\packages 16 | set RefTrimPkgBase=%NuGetPkgBase%\ReferenceTrimmer 17 | for /d %%d in (%RefTrimPkgBase%\*) do set RefTrimPkg=%%d 18 | set MSBuildLoggerParam=-distributedlogger:CentralLogger,%RefTrimPkg%\build\ReferenceTrimmer.Loggers.dll*ForwardingLogger,%RefTrimPkg%\build\ReferenceTrimmer.Loggers.dll 19 | 20 | @echo Building with ReferenceTrimmer C# and C++ logger. 21 | set cmd=msbuild %MSBuildLoggerParam% %* 22 | echo %cmd% 23 | call %cmd% 24 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "msbuild-sdks": { 3 | "Microsoft.Build.NoTargets": "3.7.56", 4 | "MSTest.Sdk": "3.6.0" 5 | } 6 | } -------------------------------------------------------------------------------- /src/Analyzer/ReferenceTrimmer.Analyzer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | false 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Analyzer/ReferenceTrimmerAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using ReferenceTrimmer.Shared; 5 | 6 | namespace ReferenceTrimmer.Analyzer; 7 | 8 | [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] 9 | public class ReferenceTrimmerAnalyzer : DiagnosticAnalyzer 10 | { 11 | private const string DeclaredReferencesFileName = "_ReferenceTrimmer_DeclaredReferences.tsv"; 12 | private const string UsedReferencesFileName = "_ReferenceTrimmer_UsedReferences.log"; 13 | private const string UnusedReferencesFileName = "_ReferenceTrimmer_UnusedReferences.log"; 14 | 15 | private static readonly DiagnosticDescriptor RT0000Descriptor = new( 16 | "RT0000", 17 | "Enable documentation generation for accuracy of used references detection", 18 | "Enable /doc parameter or in MSBuild set true for accuracy of used references detection", 19 | "ReferenceTrimmer", 20 | DiagnosticSeverity.Warning, 21 | isEnabledByDefault: true); 22 | 23 | private static readonly DiagnosticDescriptor RT0001Descriptor = new( 24 | "RT0001", 25 | "Unnecessary reference", 26 | "Reference {0} can be removed", 27 | "ReferenceTrimmer", 28 | DiagnosticSeverity.Warning, 29 | isEnabledByDefault: true); 30 | 31 | private static readonly DiagnosticDescriptor RT0002Descriptor = new( 32 | "RT0002", 33 | "Unnecessary project reference", 34 | "ProjectReference {0} can be removed", 35 | "ReferenceTrimmer", 36 | DiagnosticSeverity.Warning, 37 | isEnabledByDefault: true); 38 | 39 | private static readonly DiagnosticDescriptor RT0003Descriptor = new( 40 | "RT0003", 41 | "Unnecessary package reference", 42 | "PackageReference {0} can be removed", 43 | "ReferenceTrimmer", 44 | DiagnosticSeverity.Warning, 45 | isEnabledByDefault: true); 46 | 47 | /// 48 | /// The supported diagnostics. 49 | /// 50 | public override ImmutableArray SupportedDiagnostics 51 | => ImmutableArray.Create( 52 | RT0000Descriptor, 53 | RT0001Descriptor, 54 | RT0002Descriptor, 55 | RT0003Descriptor); 56 | 57 | /// 58 | public override void Initialize(AnalysisContext context) 59 | { 60 | context.EnableConcurrentExecution(); 61 | context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); 62 | context.RegisterCompilationAction(DumpUsedReferences); 63 | } 64 | 65 | private static void DumpUsedReferences(CompilationAnalysisContext context) 66 | { 67 | string? declaredReferencesPath = GetDeclaredReferencesPath(context); 68 | if (declaredReferencesPath == null) 69 | { 70 | // Reference Trimmer is disabled 71 | return; 72 | } 73 | 74 | DeclaredReferences declaredReferences = DeclaredReferences.ReadFromFile(declaredReferencesPath); 75 | Compilation compilation = context.Compilation; 76 | if (compilation.SyntaxTrees.FirstOrDefault()?.Options.DocumentationMode == DocumentationMode.None) 77 | { 78 | context.ReportDiagnostic(Diagnostic.Create(RT0000Descriptor, Location.None)); 79 | } 80 | 81 | if (!compilation.Options.Errors.IsEmpty) 82 | { 83 | return; 84 | } 85 | 86 | HashSet usedReferences = new(StringComparer.OrdinalIgnoreCase); 87 | foreach (MetadataReference metadataReference in compilation.GetUsedAssemblyReferences()) 88 | { 89 | if (metadataReference.Display != null) 90 | { 91 | usedReferences.Add(metadataReference.Display); 92 | } 93 | } 94 | 95 | var globalOptions = context.Options.AnalyzerConfigOptionsProvider.GlobalOptions; 96 | if (globalOptions.TryGetValue("build_property.EnableReferenceTrimmerDiagnostics", out string? enableDiagnostics) 97 | && string.Equals(enableDiagnostics, "true", StringComparison.OrdinalIgnoreCase)) 98 | { 99 | HashSet unusedReferences = new(StringComparer.OrdinalIgnoreCase); 100 | foreach (MetadataReference metadataReference in compilation.References) 101 | { 102 | if (metadataReference.Display != null && !usedReferences.Contains(metadataReference.Display)) 103 | { 104 | unusedReferences.Add(metadataReference.Display); 105 | } 106 | } 107 | 108 | DumpReferencesInfo(usedReferences, unusedReferences, declaredReferencesPath); 109 | } 110 | 111 | Dictionary> packageAssembliesDict = new(StringComparer.OrdinalIgnoreCase); 112 | foreach (DeclaredReference declaredReference in declaredReferences.References) 113 | { 114 | switch (declaredReference.Kind) 115 | { 116 | case DeclaredReferenceKind.Reference: 117 | { 118 | if (!usedReferences.Contains(declaredReference.AssemblyPath)) 119 | { 120 | context.ReportDiagnostic(Diagnostic.Create(RT0001Descriptor, Location.None, declaredReference.Spec)); 121 | } 122 | 123 | break; 124 | } 125 | case DeclaredReferenceKind.ProjectReference: 126 | { 127 | if (!usedReferences.Contains(declaredReference.AssemblyPath)) 128 | { 129 | context.ReportDiagnostic(Diagnostic.Create(RT0002Descriptor, Location.None, declaredReference.Spec)); 130 | } 131 | 132 | break; 133 | } 134 | case DeclaredReferenceKind.PackageReference: 135 | { 136 | if (!packageAssembliesDict.TryGetValue(declaredReference.Spec, out List packageAssemblies)) 137 | { 138 | packageAssemblies = new List(); 139 | packageAssembliesDict.Add(declaredReference.Spec, packageAssemblies); 140 | } 141 | 142 | packageAssemblies.Add(declaredReference.AssemblyPath); 143 | break; 144 | } 145 | } 146 | } 147 | 148 | // Do a second pass for package assemblies since if any assembly in the package is used, the package is used. 149 | foreach (KeyValuePair> kvp in packageAssembliesDict) 150 | { 151 | string packageName = kvp.Key; 152 | List packageAssemblies = kvp.Value; 153 | if (!packageAssemblies.Any(usedReferences.Contains)) 154 | { 155 | context.ReportDiagnostic(Diagnostic.Create(RT0003Descriptor, Location.None, packageName)); 156 | } 157 | } 158 | } 159 | 160 | private static void DumpReferencesInfo(HashSet usedReferences, HashSet unusedReferences, string declaredReferencesPath) 161 | { 162 | string dir = Path.GetDirectoryName(declaredReferencesPath); 163 | string filePath = Path.Combine(dir, UsedReferencesFileName); 164 | string text = string.Join(Environment.NewLine, usedReferences.OrderBy(s => s)); 165 | WriteFile(filePath, text); 166 | filePath = Path.Combine(dir, UnusedReferencesFileName); 167 | text = string.Join(Environment.NewLine, unusedReferences.OrderBy(s => s)); 168 | WriteFile(filePath, text); 169 | } 170 | 171 | private static void WriteFile(string filePath, string text) 172 | { 173 | try 174 | { 175 | if (File.Exists(filePath)) 176 | { 177 | string oldText = File.ReadAllText(filePath); 178 | if (string.Equals(text, oldText, StringComparison.OrdinalIgnoreCase)) 179 | { 180 | return; 181 | } 182 | } 183 | 184 | File.WriteAllText(filePath, text); 185 | } 186 | catch 187 | { 188 | } 189 | } 190 | 191 | private static string? GetDeclaredReferencesPath(CompilationAnalysisContext context) 192 | { 193 | foreach (AdditionalText additionalText in context.Options.AdditionalFiles) 194 | { 195 | if (Path.GetFileName(additionalText.Path).Equals(DeclaredReferencesFileName, StringComparison.Ordinal)) 196 | { 197 | return additionalText.Path; 198 | } 199 | } 200 | 201 | return null; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/Loggers/MSVC/CentralLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Framework; 2 | using Microsoft.Build.Utilities; 3 | 4 | namespace ReferenceTrimmer.Loggers.MSVC; 5 | 6 | /// 7 | /// Central logger instance run in the main MSBuild process. 8 | /// 9 | public sealed class CentralLogger : Logger 10 | { 11 | private readonly object _jsonLogWriteLock = new(); 12 | private Lazy? _lazyJsonLogFileStreamWriter; 13 | private bool _firstEvent = true; 14 | private string? _jsonLogFilePath; 15 | 16 | internal const string JsonLogFileName = ForwardingLogger.HelpKeyword + ".json.log"; 17 | 18 | /// 19 | public override void Initialize(IEventSource eventSource) 20 | { 21 | _jsonLogFilePath = Path.Combine(Directory.GetCurrentDirectory(), JsonLogFileName); 22 | if (File.Exists(_jsonLogFilePath)) 23 | { 24 | File.Delete(_jsonLogFilePath); 25 | } 26 | 27 | _lazyJsonLogFileStreamWriter = new Lazy(() => 28 | { 29 | try 30 | { 31 | var writer = new StreamWriter(_jsonLogFilePath); 32 | 33 | // Begin JSON array as text. 34 | writer.WriteLine("["); 35 | 36 | return writer; 37 | } 38 | catch (Exception ex) 39 | { 40 | throw new LoggerException($"Failed to create JSON log file for ReferenceTrimmer for MSVC: {ex.Message}"); 41 | } 42 | }); 43 | 44 | eventSource.CustomEventRaised += CustomEventHandler; 45 | } 46 | 47 | /// 48 | public override void Shutdown() 49 | { 50 | lock (_jsonLogWriteLock) 51 | { 52 | if (_lazyJsonLogFileStreamWriter is not null && _lazyJsonLogFileStreamWriter.IsValueCreated) 53 | { 54 | _lazyJsonLogFileStreamWriter.Value.WriteLine(); 55 | _lazyJsonLogFileStreamWriter.Value.WriteLine("]"); 56 | _lazyJsonLogFileStreamWriter.Value.Dispose(); 57 | } 58 | } 59 | } 60 | 61 | private void CustomEventHandler(object sender, CustomBuildEventArgs e) 62 | { 63 | if (e is not UnusedLibsCustomBuildEventArgs unusedLibsEvent || unusedLibsEvent.UnusedLibraryPathsJson.Length == 0) 64 | { 65 | return; 66 | } 67 | 68 | Console.WriteLine(unusedLibsEvent.Message + Environment.NewLine + $" * JSON version of this information added to {_jsonLogFilePath}"); 69 | 70 | lock (_jsonLogWriteLock) 71 | { 72 | StreamWriter sw = _lazyJsonLogFileStreamWriter!.Value; 73 | if (_firstEvent) 74 | { 75 | _firstEvent = false; 76 | } 77 | else 78 | { 79 | // Separate JSON objects with a comma. 80 | sw.WriteLine(','); 81 | } 82 | 83 | sw.Write(unusedLibsEvent.UnusedLibraryPathsJson); 84 | sw.Flush(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Loggers/MSVC/ForwardingLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Text; 3 | using Microsoft.Build.Framework; 4 | 5 | namespace ReferenceTrimmer.Loggers.MSVC; 6 | 7 | /// 8 | /// Forwarding logger that runs in each MSBuild worker node outside of the primary node. 9 | /// 10 | public sealed class ForwardingLogger : IForwardingLogger 11 | { 12 | private const string LinkTaskName = "Link"; 13 | 14 | // Default library list in $(CoreLibraryDependencies) used as a default list for $(AdditionalDependencies) 15 | // in the MSVC MSBuild SDK. To update with current lib list: 16 | // findstr /s CoreLibraryDependencies "\Program Files"\*props 17 | // Ignores WindowsApp.lib for the WindowsAppContainer case. 18 | private static readonly HashSet DefaultWin32DllImportLibraries = new(StringComparer.OrdinalIgnoreCase) 19 | { 20 | "advapi32.lib", 21 | "comdlg32.lib", 22 | "gdi32.lib", 23 | "kernel32.lib", 24 | "odbc32.lib", 25 | "odbccp32.lib", 26 | "ole32.lib", 27 | "oleaut32.lib", 28 | "shell32.lib", 29 | "user32.lib", 30 | "uuid.lib", 31 | "winspool.lib", 32 | }; 33 | 34 | private enum State 35 | { 36 | LinkStarted, 37 | UnusedLibsStarted, 38 | UnusedLibsEnded, 39 | } 40 | 41 | private enum LibType 42 | { 43 | DefaultImportLib, 44 | PackageOrDependencyLib, 45 | } 46 | 47 | private sealed class ProjectStateLibs 48 | { 49 | public State ProjectState { get; set; } 50 | public SortedSet UnusedProjectLibPaths { get; } = new(StringComparer.OrdinalIgnoreCase); 51 | } 52 | 53 | private IEventSource? _eventSource; 54 | private readonly ConcurrentDictionary _projects = new(StringComparer.OrdinalIgnoreCase); 55 | 56 | public const string HelpKeyword = "ReferenceTrimmerUnusedMSVCLibraries"; 57 | 58 | /// 59 | /// Gets or sets the level of detail to show in the event log. 60 | /// 61 | public LoggerVerbosity Verbosity { get; set; } 62 | 63 | /// 64 | /// The logger takes a single parameter to suppress the output of the errors 65 | /// and warnings summary at the end of a build. 66 | /// 67 | public string? Parameters { get; set; } 68 | 69 | /// 70 | /// This property is set by the build engine to allow node loggers to forward messages to the 71 | /// central logger. 72 | /// 73 | public IEventRedirector? BuildEventRedirector { get; set; } 74 | 75 | /// 76 | /// The identifier of the node. 77 | /// 78 | public int NodeId { get; set; } 79 | 80 | /// 81 | /// Signs up the logger for all build events. 82 | /// 83 | public void Initialize(IEventSource eventSource, int nodeCount) 84 | { 85 | Initialize(eventSource); 86 | } 87 | 88 | /// 89 | /// Signs up the logger for all build events. 90 | /// 91 | public void Initialize(IEventSource eventSource) 92 | { 93 | _eventSource = eventSource; 94 | 95 | eventSource.TaskStarted += OnTaskStarted; 96 | eventSource.TaskFinished += OnTaskFinished; 97 | eventSource.MessageRaised += OnMessageRaised; 98 | } 99 | 100 | /// 101 | /// Called when Engine is done with this logger 102 | /// 103 | public void Shutdown() 104 | { 105 | if (_eventSource is null) 106 | { 107 | return; 108 | } 109 | 110 | _eventSource.TaskStarted -= OnTaskStarted; 111 | _eventSource.TaskFinished -= OnTaskFinished; 112 | _eventSource.MessageRaised -= OnMessageRaised; 113 | } 114 | 115 | private void OnTaskStarted(object sender, TaskStartedEventArgs e) 116 | { 117 | if (!string.IsNullOrEmpty(e.ProjectFile) && e.TaskName.Equals(LinkTaskName, StringComparison.OrdinalIgnoreCase)) 118 | { 119 | _projects[e.ProjectFile] = new ProjectStateLibs { ProjectState = State.LinkStarted }; 120 | } 121 | } 122 | 123 | private void OnTaskFinished(object sender, TaskFinishedEventArgs e) 124 | { 125 | if (string.IsNullOrEmpty(e.ProjectFile) || e.TaskName != LinkTaskName || !e.Succeeded) 126 | { 127 | return; 128 | } 129 | 130 | string projectFilePath = e.ProjectFile; 131 | 132 | // Project state present in map if the Link task was detected running in OnTaskStarted. 133 | if (!_projects.TryGetValue(projectFilePath, out ProjectStateLibs projState)) 134 | { 135 | return; 136 | } 137 | 138 | if (projState.ProjectState is State.UnusedLibsStarted or State.UnusedLibsEnded && 139 | projState.UnusedProjectLibPaths.Count > 0) 140 | { 141 | // Hack the output JSON format to avoid importing Newtonsoft or System.Text.Json that could collide with 142 | // versions in the current MSBuild process. 143 | var jsonSb = new StringBuilder(256); 144 | jsonSb.AppendLine(" {"); 145 | jsonSb.AppendLine($" \"{EscapeJsonChars(projectFilePath)}\": ["); 146 | 147 | // Classify the libraries. 148 | var defaultImportLibraries = new List(); 149 | var otherLibraries = new List(); 150 | var implicitlyUsedImportLibraries = new HashSet(DefaultWin32DllImportLibraries, StringComparer.OrdinalIgnoreCase); 151 | bool first = true; 152 | foreach (string libPath in projState.UnusedProjectLibPaths) 153 | { 154 | if (first) 155 | { 156 | first = false; 157 | } 158 | else 159 | { 160 | jsonSb.AppendLine(","); 161 | } 162 | 163 | jsonSb.AppendLine(" {") 164 | .AppendLine($" \"LibPath\": \"{EscapeJsonChars(libPath)}\","); 165 | 166 | string libFileName = Path.GetFileName(libPath); 167 | LibType type; 168 | if (DefaultWin32DllImportLibraries.Contains(libFileName)) 169 | { 170 | defaultImportLibraries.Add(libPath); 171 | implicitlyUsedImportLibraries.Remove(libFileName); 172 | type = LibType.DefaultImportLib; 173 | } 174 | else 175 | { 176 | otherLibraries.Add(libPath); 177 | type = LibType.PackageOrDependencyLib; 178 | } 179 | 180 | jsonSb.AppendLine($" \"LibType\": \"{type}\"") 181 | .Append(" }"); 182 | } 183 | 184 | jsonSb.AppendLine(); 185 | jsonSb.AppendLine(" ]"); 186 | jsonSb.Append(" }"); 187 | 188 | var sb = new StringBuilder($" Unused MSVC libraries detected in project {projectFilePath}:", 256); 189 | sb.AppendLine(); 190 | 191 | if (defaultImportLibraries.Count > 0) 192 | { 193 | var implicitlyUsedImportLibrariesSorted = new List(implicitlyUsedImportLibraries); 194 | implicitlyUsedImportLibrariesSorted.Sort(StringComparer.OrdinalIgnoreCase); 195 | sb.Append(" * Default Windows SDK import libraries:"); 196 | if (implicitlyUsedImportLibrariesSorted.Count > 0) 197 | { 198 | sb.AppendLine().Append($" - Libraries needed: {string.Join(";", implicitlyUsedImportLibrariesSorted)} (set in $(AdditionalDependencies) without %(AdditionalDependencies))"); 199 | } 200 | 201 | sb.AppendLine().Append($" - Unneeded: {string.Join(", ", defaultImportLibraries.Select(Path.GetFileName))} (remove from $(AdditionalDependencies))"); 202 | } 203 | 204 | if (otherLibraries.Count > 0) 205 | { 206 | sb.AppendLine().Append( 207 | " * Other libraries - if a lib from a project in this repo, remove the related ProjectReference to improve your build dependency graph; " + 208 | "if a package lib, remove from $(AdditionalDependencies):"); 209 | foreach (string lib in otherLibraries) 210 | { 211 | sb.AppendLine().Append($" - {lib}"); 212 | } 213 | } 214 | 215 | BuildEventRedirector!.ForwardEvent( 216 | new UnusedLibsCustomBuildEventArgs( 217 | message: sb.ToString(), 218 | projectFilePath, 219 | jsonSb.ToString())); 220 | } 221 | 222 | _projects.TryRemove(projectFilePath, out _); 223 | } 224 | 225 | private static string EscapeJsonChars(string str) 226 | { 227 | return str.Replace("\\", "\\\\").Replace("\"", "\\\""); 228 | } 229 | 230 | private void OnMessageRaised(object sender, BuildMessageEventArgs e) 231 | { 232 | string? projectFilePath = e.ProjectFile; 233 | string? message = e.Message; 234 | 235 | if (string.IsNullOrEmpty(projectFilePath) || message is null) 236 | { 237 | return; 238 | } 239 | 240 | if (!_projects.TryGetValue(projectFilePath, out ProjectStateLibs? projState)) 241 | { 242 | return; 243 | } 244 | 245 | // The 'Unused libraries' message is at the tail of Link's stdout. 246 | // Once found, assume the rest of the output is the list of unused libs. 247 | switch (projState.ProjectState) 248 | { 249 | case State.LinkStarted: 250 | if (message!.IndexOf("Unused libraries:", StringComparison.OrdinalIgnoreCase) != -1) 251 | { 252 | projState.ProjectState = State.UnusedLibsStarted; 253 | } 254 | break; 255 | 256 | case State.UnusedLibsStarted: 257 | string lib = message!.Trim(); 258 | if (lib.Length > 0) 259 | { 260 | try 261 | { 262 | lib = Path.GetFullPath(lib); 263 | } 264 | finally 265 | { 266 | projState.UnusedProjectLibPaths.Add(lib); 267 | } 268 | } 269 | else 270 | { 271 | projState.ProjectState = State.UnusedLibsEnded; 272 | } 273 | break; 274 | 275 | // Avoid parsing any other text after the usual empty line emitted after the unused libs list. 276 | // Allow to fall through. 277 | case State.UnusedLibsEnded: 278 | 279 | default: 280 | break; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/Loggers/MSVC/UnusedLibsCustomBuildEventArgs.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Framework; 2 | 3 | namespace ReferenceTrimmer.Loggers.MSVC; 4 | 5 | /// 6 | /// Passes the unused library information from to 7 | /// . Note that the MSBuild binary logger will serialize this event in its 8 | /// entirety, so to aid complete debugging fully analyzed information is passed here. 9 | /// 10 | [Serializable] 11 | internal sealed class UnusedLibsCustomBuildEventArgs : CustomBuildEventArgs 12 | { 13 | public UnusedLibsCustomBuildEventArgs() 14 | { 15 | ProjectPath = string.Empty; 16 | UnusedLibraryPathsJson = string.Empty; 17 | } 18 | 19 | public UnusedLibsCustomBuildEventArgs( 20 | string message, 21 | string projectPath, 22 | string unusedLibraryPathsJson) 23 | : base(message, ForwardingLogger.HelpKeyword, senderName: projectPath) 24 | { 25 | ProjectPath = projectPath; 26 | UnusedLibraryPathsJson = unusedLibraryPathsJson; 27 | } 28 | 29 | public string ProjectPath { get; set; } 30 | public string UnusedLibraryPathsJson { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /src/Loggers/ReferenceTrimmer.Loggers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Package/ReferenceTrimmer.Package.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | true 5 | true 6 | ReferenceTrimmer 7 | true 8 | true 9 | $(TargetsForTfmSpecificContentInPackage);GetMyPackageFiles 10 | false 11 | $(RepoRoot)\artifacts 12 | README.md 13 | 14 | 15 | true 16 | 17 | 18 | 21 | 24 | 27 | 28 | 29 | 30 | true 31 | build 32 | 33 | 34 | true 35 | buildMultiTargeting 36 | 37 | 38 | true 39 | tools 40 | 41 | 42 | true 43 | \ 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/Package/build/ReferenceTrimmer.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)ReferenceTrimmer.Tasks.dll 5 | 6 | 7 | 8 | 9 | 21 | /VERBOSE:UNUSEDLIBS /VERBOSE:UNUSEDDELAYLOAD %(AdditionalOptions) 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Package/build/ReferenceTrimmer.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(CoreCompileDependsOn);CollectDeclaredReferences 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <_ReferenceTrimmerDeclaredReferencesFile>$(IntermediateOutputPath)\_ReferenceTrimmer_DeclaredReferences.tsv 15 | <_ReferenceTrimmerUsedReferencesFile>$(IntermediateOutputPath)\_ReferenceTrimmer_UsedReferences.log 16 | <_ReferenceTrimmerUnusedReferencesFile>$(IntermediateOutputPath)\_ReferenceTrimmer_UnusedReferences.log 17 | 18 | 19 | 23 | <_ReferenceTrimmerReferences Include="@(Reference)" /> 24 | <_ReferenceTrimmerReferences Remove="@(_NETStandardLibraryNETFrameworkLib -> '%(FileName)')" /> 25 | 26 | <_ReferenceTrimmerResolvedReferences Include="@(ReferencePathWithRefAssemblies)" Condition="'%(ReferencePathWithRefAssemblies.ReferenceSourceTarget)' == 'ResolveAssemblyReference'"/> 27 | 28 | <_ReferenceTrimmerProjectReferences Include="@(ReferencePathWithRefAssemblies)" Condition="'%(ReferencePathWithRefAssemblies.ReferenceSourceTarget)' == 'ProjectReference'" /> 29 | 30 | 31 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/Package/buildMultiTargeting/ReferenceTrimmer.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Package/buildMultiTargeting/ReferenceTrimmer.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Package/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not install analyzers via install.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | if (Test-Path $analyzersPath) 17 | { 18 | # Install the language agnostic analyzers. 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Install language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Package/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | # Uninstall the language agnostic analyzers. 17 | if (Test-Path $analyzersPath) 18 | { 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Uninstall language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | try 55 | { 56 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 57 | } 58 | catch 59 | { 60 | 61 | } 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Shared/DeclaredReferences.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace ReferenceTrimmer.Shared; 4 | 5 | internal record DeclaredReferences(IReadOnlyList References) 6 | { 7 | private const char FieldDelimiter = '\t'; 8 | 9 | private static readonly char[] FieldDelimiters = new[] { FieldDelimiter }; 10 | 11 | private static readonly Dictionary KindEnumToString = new() 12 | { 13 | { DeclaredReferenceKind.Reference, nameof(DeclaredReferenceKind.Reference) }, 14 | { DeclaredReferenceKind.ProjectReference, nameof(DeclaredReferenceKind.ProjectReference) }, 15 | { DeclaredReferenceKind.PackageReference, nameof(DeclaredReferenceKind.PackageReference) }, 16 | }; 17 | 18 | private static readonly Dictionary KindStringToEnum = new() 19 | { 20 | { nameof(DeclaredReferenceKind.Reference), DeclaredReferenceKind.Reference }, 21 | { nameof(DeclaredReferenceKind.ProjectReference), DeclaredReferenceKind.ProjectReference }, 22 | { nameof(DeclaredReferenceKind.PackageReference), DeclaredReferenceKind.PackageReference }, 23 | }; 24 | 25 | public void SaveToFile(string filePath) 26 | { 27 | StringBuilder writer = new(); 28 | foreach (DeclaredReference reference in References) 29 | { 30 | writer.Append(reference.AssemblyPath); 31 | writer.Append(FieldDelimiter); 32 | writer.Append(KindEnumToString[reference.Kind]); 33 | writer.Append(FieldDelimiter); 34 | writer.Append(reference.Spec); 35 | writer.AppendLine(); 36 | } 37 | 38 | string newContent = writer.ToString(); 39 | if (File.Exists(filePath)) 40 | { 41 | string existing = File.ReadAllText(filePath); 42 | if (string.Equals(existing, newContent, StringComparison.OrdinalIgnoreCase)) 43 | { 44 | return; 45 | } 46 | } 47 | 48 | File.WriteAllText(filePath, newContent); 49 | } 50 | 51 | public static DeclaredReferences ReadFromFile(string filePath) 52 | { 53 | List references = new(); 54 | 55 | using FileStream stream = File.OpenRead(filePath); 56 | using StreamReader reader = new(stream); 57 | 58 | string? line; 59 | while ((line = reader.ReadLine()) != null) 60 | { 61 | string[] parts = line.Split(FieldDelimiters, 3); 62 | if (parts.Length != 3) 63 | { 64 | throw new InvalidDataException($"File '{filePath}' is invalid. Line: {references.Count + 1}"); 65 | } 66 | 67 | string assemblyName = parts[0]; 68 | DeclaredReferenceKind kind = KindStringToEnum[parts[1]]; 69 | string spec = parts[2]; 70 | DeclaredReference reference = new(assemblyName, kind, spec); 71 | references.Add(reference); 72 | } 73 | 74 | return new DeclaredReferences(references); 75 | } 76 | } 77 | 78 | internal record DeclaredReference(string AssemblyPath, DeclaredReferenceKind Kind, string Spec); 79 | 80 | internal enum DeclaredReferenceKind { Reference, ProjectReference, PackageReference } -------------------------------------------------------------------------------- /src/Shared/NetStandardPolyfills.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices; 2 | 3 | internal sealed class IsExternalInit { } -------------------------------------------------------------------------------- /src/Tasks/CollectDeclaredReferencesTask.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Xml.Linq; 3 | using Microsoft.Build.Framework; 4 | using NuGet.Common; 5 | using NuGet.Frameworks; 6 | using NuGet.ProjectModel; 7 | using ReferenceTrimmer.Shared; 8 | using MSBuildTask = Microsoft.Build.Utilities.Task; 9 | 10 | namespace ReferenceTrimmer.Tasks; 11 | 12 | public sealed class CollectDeclaredReferencesTask : MSBuildTask 13 | { 14 | private static readonly HashSet NugetAssemblies = new(StringComparer.OrdinalIgnoreCase) 15 | { 16 | // Direct dependency 17 | "NuGet.ProjectModel", 18 | 19 | // Indirect dependencies 20 | "NuGet.Common", 21 | "NuGet.Frameworks", 22 | "NuGet.Packaging", 23 | "NuGet.Versioning", 24 | }; 25 | 26 | private const string NoWarn = "NoWarn"; 27 | private const string TreatAsUsed = "TreatAsUsed"; 28 | 29 | [Required] 30 | public string? OutputFile { get; set; } 31 | 32 | [Required] 33 | public string? MSBuildProjectFile { get; set; } 34 | 35 | public ITaskItem[]? References { get; set; } 36 | 37 | public ITaskItem[]? ResolvedReferences { get; set; } 38 | 39 | public ITaskItem[]? ProjectReferences { get; set; } 40 | 41 | public ITaskItem[]? PackageReferences { get; set; } 42 | 43 | public string? ProjectAssetsFile { get; set; } 44 | 45 | public string? TargetFrameworkMoniker { get; set; } 46 | 47 | public string? TargetPlatformMoniker { get; set; } 48 | 49 | public string? RuntimeIdentifier { get; set; } 50 | 51 | public string? NuGetRestoreTargets { get; set; } 52 | 53 | public ITaskItem[]? TargetFrameworkDirectories { get; set; } 54 | 55 | public string? NuGetPackageRoot { get; set; } 56 | 57 | public override bool Execute() 58 | { 59 | AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; 60 | try 61 | { 62 | List declaredReferences = new(); 63 | 64 | if (References != null) 65 | { 66 | HashSet targetFrameworkAssemblies = GetTargetFrameworkAssemblyNames(); 67 | foreach (ITaskItem reference in References) 68 | { 69 | // Ignore implicitly defined references (references which are SDK-provided) 70 | if (reference.GetMetadata("IsImplicitlyDefined").Equals("true", StringComparison.OrdinalIgnoreCase)) 71 | { 72 | continue; 73 | } 74 | 75 | // During the _HandlePackageFileConflicts target (ResolvePackageFileConflicts task), assembly conflicts may be 76 | // resolved with an assembly from the target framework instead of a package. The package may be an indirect dependency, 77 | // so the resulting reference would be unavoidable. 78 | if (targetFrameworkAssemblies.Contains(reference.ItemSpec)) 79 | { 80 | continue; 81 | } 82 | 83 | // Ignore references from packages. Those as handled later. 84 | if (reference.GetMetadata("NuGetPackageId").Length != 0) 85 | { 86 | continue; 87 | } 88 | 89 | // Ignore suppressions 90 | if (IsSuppressed(reference, "RT0001")) 91 | { 92 | continue; 93 | } 94 | 95 | var referenceSpec = reference.ItemSpec; 96 | var referenceHintPath = reference.GetMetadata("HintPath"); 97 | 98 | string? referencePath; 99 | if (!string.IsNullOrEmpty(referenceHintPath) && File.Exists(referenceHintPath)) 100 | { 101 | referencePath = Path.GetFullPath(referenceHintPath); 102 | } 103 | else if (File.Exists(referenceSpec)) 104 | { 105 | referencePath = Path.GetFullPath(referenceSpec); 106 | } 107 | else 108 | { 109 | var resolvedReference = ResolvedReferences.SingleOrDefault(rr => string.Equals(rr.GetMetadata("OriginalItemSpec"), referenceSpec, StringComparison.OrdinalIgnoreCase)); 110 | referencePath = resolvedReference is null ? null : resolvedReference.ItemSpec; 111 | } 112 | 113 | // If the reference is under the nuget package root, it's likely a Reference added in a package's props or targets. 114 | if (NuGetPackageRoot != null && referencePath != null) 115 | { 116 | if (referencePath.StartsWith(NuGetPackageRoot, StringComparison.OrdinalIgnoreCase)) 117 | { 118 | continue; 119 | } 120 | } 121 | 122 | if (referencePath is not null) 123 | { 124 | declaredReferences.Add(new DeclaredReference(referencePath, DeclaredReferenceKind.Reference, referenceSpec)); 125 | } 126 | } 127 | } 128 | 129 | if (ProjectReferences != null) 130 | { 131 | foreach (ITaskItem projectReference in ProjectReferences) 132 | { 133 | // Ignore suppressions 134 | if (IsSuppressed(projectReference, "RT0002")) 135 | { 136 | continue; 137 | } 138 | 139 | // Weirdly, NuGet restore is actually how transitive project references are determined and they're 140 | // added to to project.assets.json and collected via the IncludeTransitiveProjectReferences target. 141 | // This also adds the NuGetPackageId metadata, so use that as a signal that it's transitive. 142 | bool isTransitiveDependency = !string.IsNullOrEmpty(projectReference.GetMetadata("NuGetPackageId")); 143 | if (isTransitiveDependency) 144 | { 145 | // Ignore transitive project references since the project doesn't have direct control over them. 146 | continue; 147 | } 148 | 149 | string projectReferenceAssemblyPath = Path.GetFullPath(projectReference.ItemSpec); 150 | string referenceProjectFile = projectReference.GetMetadata("OriginalProjectReferenceItemSpec"); 151 | 152 | declaredReferences.Add(new DeclaredReference(projectReferenceAssemblyPath, DeclaredReferenceKind.ProjectReference, referenceProjectFile)); 153 | } 154 | } 155 | 156 | if (PackageReferences != null) 157 | { 158 | Dictionary packageInfos = GetPackageInfos(); 159 | foreach (ITaskItem packageReference in PackageReferences) 160 | { 161 | // Ignore suppressions 162 | if (IsSuppressed(packageReference, "RT0003")) 163 | { 164 | continue; 165 | } 166 | 167 | if (!packageInfos.TryGetValue(packageReference.ItemSpec, out PackageInfo packageInfo)) 168 | { 169 | // These are likely Analyzers, tools, etc. 170 | continue; 171 | } 172 | 173 | // Ignore packages with build logic as we cannot easily evaluate whether the build logic is necessary or not. 174 | if (packageInfo.BuildFiles.Count > 0) 175 | { 176 | continue; 177 | } 178 | 179 | foreach (string assemblyPath in packageInfo.CompileTimeAssemblies) 180 | { 181 | declaredReferences.Add(new DeclaredReference(assemblyPath, DeclaredReferenceKind.PackageReference, packageReference.ItemSpec)); 182 | } 183 | } 184 | } 185 | 186 | if (OutputFile is not null) 187 | { 188 | new DeclaredReferences(declaredReferences).SaveToFile(OutputFile); 189 | } 190 | } 191 | finally 192 | { 193 | AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly; 194 | } 195 | 196 | return !Log.HasLoggedErrors; 197 | } 198 | 199 | private Dictionary GetPackageInfos() 200 | { 201 | var packageInfoBuilders = new Dictionary(StringComparer.OrdinalIgnoreCase); 202 | 203 | var lockFile = LockFileUtilities.GetLockFile(ProjectAssetsFile, NullLogger.Instance); 204 | var packageFolders = lockFile.PackageFolders.Select(item => item.Path).ToList(); 205 | 206 | LockFileTarget? nugetTarget = null; 207 | if (!string.IsNullOrEmpty(TargetFrameworkMoniker)) 208 | { 209 | var nugetFramework = NuGetFramework.ParseComponents(TargetFrameworkMoniker!, TargetPlatformMoniker); 210 | nugetTarget = lockFile.GetTarget(nugetFramework, RuntimeIdentifier); 211 | } 212 | 213 | List nugetLibraries; 214 | if (nugetTarget?.Libraries is not null) 215 | { 216 | nugetLibraries = nugetTarget.Libraries 217 | .Where(nugetLibrary => string.Equals(nugetLibrary.Type, "Package", StringComparison.OrdinalIgnoreCase)) 218 | .ToList(); 219 | } 220 | else 221 | { 222 | nugetLibraries = new List(); 223 | } 224 | 225 | // Compute the hierarchy of packages. 226 | // Keys are packages and values are packages which depend on that package. 227 | var nugetDependents = new Dictionary>(StringComparer.OrdinalIgnoreCase); 228 | foreach (LockFileTargetLibrary nugetLibrary in nugetLibraries) 229 | { 230 | string? packageId = nugetLibrary.Name; 231 | if (packageId is null) 232 | { 233 | continue; 234 | } 235 | 236 | foreach (var dependency in nugetLibrary.Dependencies) 237 | { 238 | if (!nugetDependents.TryGetValue(dependency.Id, out var parents)) 239 | { 240 | parents = new List(); 241 | nugetDependents.Add(dependency.Id, parents); 242 | } 243 | 244 | parents.Add(packageId); 245 | } 246 | } 247 | 248 | // Get the transitive closure of assemblies included by each package 249 | foreach (LockFileTargetLibrary nugetLibrary in nugetLibraries) 250 | { 251 | if (nugetLibrary.Name is null) 252 | { 253 | continue; 254 | } 255 | 256 | string nugetLibraryRelativePath = lockFile.GetLibrary(nugetLibrary.Name, nugetLibrary.Version).Path; 257 | string? nugetLibraryAbsolutePath = packageFolders 258 | .Select(packageFolder => Path.Combine(packageFolder, nugetLibraryRelativePath)) 259 | .FirstOrDefault(Directory.Exists); 260 | if (nugetLibraryAbsolutePath is null) 261 | { 262 | // This can happen if the project has a stale lock file. 263 | // Just ignore it as NuGet itself will likely error. 264 | continue; 265 | } 266 | 267 | List nugetLibraryAssemblies = nugetLibrary.CompileTimeAssemblies 268 | .Select(item => item.Path) 269 | .Where(IsValidFile) 270 | .Select(path => 271 | { 272 | var fullPath = Path.Combine(nugetLibraryAbsolutePath, path); 273 | return Path.GetFullPath(fullPath); 274 | }) 275 | .ToList(); 276 | 277 | List buildFiles = nugetLibrary.Build 278 | .Select(item => item.Path) 279 | .Where(IsValidFile) 280 | .Select(path => Path.Combine(nugetLibraryAbsolutePath, path)) 281 | .ToList(); 282 | 283 | // Add this package's assets, if there are any 284 | if (nugetLibraryAssemblies.Count > 0 || buildFiles.Count > 0) 285 | { 286 | // Walk up to add assets to all packages which directly or indirectly depend on this one. 287 | var seenDependents = new HashSet(StringComparer.OrdinalIgnoreCase); 288 | var queue = new Queue(); 289 | queue.Enqueue(nugetLibrary.Name); 290 | while (queue.Count > 0) 291 | { 292 | var packageId = queue.Dequeue(); 293 | 294 | if (!packageInfoBuilders.TryGetValue(packageId, out PackageInfoBuilder packageInfoBuilder)) 295 | { 296 | packageInfoBuilder = new PackageInfoBuilder(); 297 | packageInfoBuilders.Add(packageId, packageInfoBuilder); 298 | } 299 | 300 | packageInfoBuilder.AddCompileTimeAssemblies(nugetLibraryAssemblies); 301 | packageInfoBuilder.AddBuildFiles(buildFiles); 302 | 303 | // Recurse though dependents 304 | if (nugetDependents.TryGetValue(packageId, out var dependents)) 305 | { 306 | foreach (var dependent in dependents) 307 | { 308 | if (seenDependents.Add(dependent)) 309 | { 310 | queue.Enqueue(dependent); 311 | } 312 | } 313 | } 314 | } 315 | } 316 | } 317 | 318 | // Create the final collection 319 | var packageInfos = new Dictionary(packageInfoBuilders.Count, StringComparer.OrdinalIgnoreCase); 320 | foreach (KeyValuePair packageInfoBuilder in packageInfoBuilders) 321 | { 322 | packageInfos.Add(packageInfoBuilder.Key, packageInfoBuilder.Value.ToPackageInfo()); 323 | } 324 | 325 | return packageInfos; 326 | } 327 | 328 | private static bool IsValidFile(string path) => !path.EndsWith("_._", StringComparison.Ordinal); 329 | 330 | private HashSet GetTargetFrameworkAssemblyNames() 331 | { 332 | HashSet targetFrameworkAssemblyNames = new(); 333 | 334 | // This follows the same logic as FrameworkListReader. 335 | // See: https://github.com/dotnet/sdk/blob/main/src/Tasks/Common/ConflictResolution/FrameworkListReader.cs 336 | if (TargetFrameworkDirectories != null) 337 | { 338 | foreach (ITaskItem targetFrameworkDirectory in TargetFrameworkDirectories) 339 | { 340 | string frameworkListPath = Path.Combine(targetFrameworkDirectory.ItemSpec, "RedistList", "FrameworkList.xml"); 341 | if (!File.Exists(frameworkListPath)) 342 | { 343 | continue; 344 | } 345 | 346 | XDocument frameworkList = XDocument.Load(frameworkListPath); 347 | if (frameworkList.Root is not null) 348 | { 349 | foreach (XElement file in frameworkList.Root.Elements("File")) 350 | { 351 | string? type = file.Attribute("Type")?.Value; 352 | if (type?.Equals("Analyzer", StringComparison.OrdinalIgnoreCase) ?? false) 353 | { 354 | continue; 355 | } 356 | 357 | string? assemblyName = file.Attribute("AssemblyName")?.Value; 358 | if (!string.IsNullOrEmpty(assemblyName)) 359 | { 360 | targetFrameworkAssemblyNames.Add(assemblyName!); 361 | } 362 | } 363 | } 364 | } 365 | } 366 | 367 | return targetFrameworkAssemblyNames; 368 | } 369 | 370 | /// 371 | /// Assembly resolution needed for parsing the lock file, needed if the version the task depends on is a different version than MSBuild's 372 | /// 373 | private Assembly? ResolveAssembly(object sender, ResolveEventArgs args) 374 | { 375 | AssemblyName assemblyName = new(args.Name); 376 | 377 | if (NugetAssemblies.Contains(assemblyName.Name)) 378 | { 379 | string nugetProjectModelFile = Path.Combine(Path.GetDirectoryName(NuGetRestoreTargets)!, assemblyName.Name + ".dll"); 380 | if (File.Exists(nugetProjectModelFile)) 381 | { 382 | return Assembly.LoadFrom(nugetProjectModelFile); 383 | } 384 | } 385 | 386 | return null; 387 | } 388 | 389 | private static bool IsSuppressed(ITaskItem item, string warningId) 390 | { 391 | ReadOnlySpan warningIdSpan = warningId.AsSpan(); 392 | ReadOnlySpan remainingNoWarn = item.GetMetadata(NoWarn).AsSpan(); 393 | while (!remainingNoWarn.IsEmpty) 394 | { 395 | ReadOnlySpan currentNoWarn; 396 | int idx = remainingNoWarn.IndexOf(';'); 397 | if (idx == -1) 398 | { 399 | currentNoWarn = remainingNoWarn; 400 | remainingNoWarn = ReadOnlySpan.Empty; 401 | } 402 | else 403 | { 404 | currentNoWarn = remainingNoWarn.Slice(0, idx); 405 | remainingNoWarn = remainingNoWarn.Slice(idx + 1); 406 | } 407 | 408 | if (currentNoWarn.Trim().Equals(warningIdSpan, StringComparison.OrdinalIgnoreCase)) 409 | { 410 | return true; 411 | } 412 | } 413 | 414 | if (item.GetMetadata(TreatAsUsed).Equals("True", StringComparison.OrdinalIgnoreCase)) 415 | { 416 | return true; 417 | } 418 | 419 | return false; 420 | } 421 | 422 | private sealed class PackageInfoBuilder 423 | { 424 | private List? _compileTimeAssemblies; 425 | private List? _buildFiles; 426 | 427 | public void AddCompileTimeAssemblies(List compileTimeAssemblies) 428 | { 429 | if (compileTimeAssemblies.Count == 0) 430 | { 431 | return; 432 | } 433 | 434 | _compileTimeAssemblies ??= new(compileTimeAssemblies.Count); 435 | _compileTimeAssemblies.AddRange(compileTimeAssemblies); 436 | } 437 | 438 | public void AddBuildFiles(List buildFiles) 439 | { 440 | if (buildFiles.Count == 0) 441 | { 442 | return; 443 | } 444 | 445 | _buildFiles ??= new(buildFiles.Count); 446 | _buildFiles.AddRange(buildFiles); 447 | } 448 | 449 | public PackageInfo ToPackageInfo() 450 | => new( 451 | (IReadOnlyCollection?)_compileTimeAssemblies ?? Array.Empty(), 452 | (IReadOnlyCollection?)_buildFiles ?? Array.Empty()); 453 | } 454 | 455 | private readonly record struct PackageInfo( 456 | IReadOnlyCollection CompileTimeAssemblies, 457 | IReadOnlyCollection BuildFiles); 458 | } 459 | -------------------------------------------------------------------------------- /src/Tasks/ReferenceTrimmer.Tasks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/MsvcLoggerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Framework; 2 | using ReferenceTrimmer.Loggers.MSVC; 3 | 4 | #pragma warning disable CA1707 // Underscores in test names 5 | 6 | namespace ReferenceTrimmer.Tests; 7 | 8 | [TestClass] 9 | public sealed class MsvcLoggerTests 10 | { 11 | private sealed class MockEventSource : IEventSource 12 | { 13 | public event BuildMessageEventHandler? MessageRaised; 14 | public event BuildErrorEventHandler? ErrorRaised; 15 | public event BuildWarningEventHandler? WarningRaised; 16 | public event BuildStartedEventHandler? BuildStarted; 17 | public event BuildFinishedEventHandler? BuildFinished; 18 | public event ProjectStartedEventHandler? ProjectStarted; 19 | public event ProjectFinishedEventHandler? ProjectFinished; 20 | public event TargetStartedEventHandler? TargetStarted; 21 | public event TargetFinishedEventHandler? TargetFinished; 22 | public event TaskStartedEventHandler? TaskStarted; 23 | public event TaskFinishedEventHandler? TaskFinished; 24 | public event CustomBuildEventHandler? CustomEventRaised; 25 | public event BuildStatusEventHandler? StatusEventRaised; 26 | public event AnyEventHandler? AnyEventRaised; 27 | 28 | public void AssertExpectedForwardingEventSubscriptions() 29 | { 30 | Assert.IsNotNull(MessageRaised); 31 | Assert.IsNotNull(TaskStarted); 32 | Assert.IsNotNull(TaskFinished); 33 | } 34 | 35 | public void AssertExpectedCentralLoggerEventSubscriptions() 36 | { 37 | Assert.IsNotNull(CustomEventRaised); 38 | } 39 | 40 | public void SendTaskStarted(TaskStartedEventArgs e) 41 | { 42 | TaskStarted?.Invoke(this, e); 43 | } 44 | 45 | public void SendTaskFinished(TaskFinishedEventArgs e) 46 | { 47 | TaskFinished?.Invoke(this, e); 48 | } 49 | 50 | public void SendMessageRaised(BuildMessageEventArgs e) 51 | { 52 | MessageRaised?.Invoke(this, e); 53 | } 54 | 55 | public void SendCustomEvent(CustomBuildEventArgs e) 56 | { 57 | CustomEventRaised?.Invoke(this, e); 58 | } 59 | } 60 | 61 | private sealed class MockEventRedirector : IEventRedirector 62 | { 63 | public List Events { get; } = new(); 64 | 65 | public void ForwardEvent(BuildEventArgs buildEvent) 66 | { 67 | Events.Add(buildEvent); 68 | } 69 | } 70 | 71 | private sealed class NonUnusedLibCustomEventArgs : CustomBuildEventArgs 72 | { 73 | } 74 | 75 | [TestMethod] 76 | public void ForwardingLoggerInitShutdown() 77 | { 78 | var eventRedirector = new MockEventRedirector(); 79 | var forwardingLogger = new ForwardingLogger 80 | { 81 | BuildEventRedirector = eventRedirector, 82 | NodeId = 1, 83 | Verbosity = LoggerVerbosity.Normal 84 | }; 85 | 86 | var eventSource = new MockEventSource(); 87 | forwardingLogger.Initialize(eventSource, nodeCount: 2); 88 | eventSource.AssertExpectedForwardingEventSubscriptions(); 89 | forwardingLogger.Shutdown(); 90 | } 91 | 92 | [TestMethod] 93 | public void ForwardingLogger_ForwardsNothingIfLinkTaskNotStarted() 94 | { 95 | var eventSource = new MockEventSource(); 96 | var eventRedirector = new MockEventRedirector(); 97 | var logger = new ForwardingLogger { BuildEventRedirector = eventRedirector }; 98 | logger.Initialize(eventSource); 99 | try 100 | { 101 | eventSource.AssertExpectedForwardingEventSubscriptions(); 102 | eventSource.SendTaskStarted(new TaskStartedEventArgs(message: "Not Link!", helpKeyword: "NotLink", projectFile: "a.proj", taskFile: "a.proj", taskName: "NotLink")); 103 | Assert.AreEqual(0, eventRedirector.Events.Count); 104 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: "a non-link message", helpKeyword: "NotLink", senderName: "NotLink", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 105 | Assert.AreEqual(0, eventRedirector.Events.Count); 106 | eventSource.SendTaskFinished(new TaskFinishedEventArgs(message: "Not Link!", helpKeyword: "NotLink", projectFile: "a.proj", taskFile: "a.proj", taskName: "NotLink", succeeded: true)); 107 | Assert.AreEqual(0, eventRedirector.Events.Count); 108 | } 109 | finally 110 | { 111 | logger.Shutdown(); 112 | } 113 | } 114 | 115 | [TestMethod] 116 | public void ForwardingLogger_ForwardsNothingIfLinkTaskGetsNoUnusedLibMessages() 117 | { 118 | var eventSource = new MockEventSource(); 119 | var eventRedirector = new MockEventRedirector(); 120 | var logger = new ForwardingLogger { BuildEventRedirector = eventRedirector }; 121 | logger.Initialize(eventSource); 122 | try 123 | { 124 | eventSource.AssertExpectedForwardingEventSubscriptions(); 125 | eventSource.SendTaskStarted(new TaskStartedEventArgs(message: "Link starting", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link")); 126 | Assert.AreEqual(0, eventRedirector.Events.Count); 127 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: "Generic link message", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 128 | Assert.AreEqual(0, eventRedirector.Events.Count); 129 | eventSource.SendTaskFinished(new TaskFinishedEventArgs(message: "Link finished", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link", succeeded: true)); 130 | Assert.AreEqual(0, eventRedirector.Events.Count); 131 | } 132 | finally 133 | { 134 | logger.Shutdown(); 135 | } 136 | } 137 | 138 | [TestMethod] 139 | public void ForwardingLogger_ForwardsNothingIfLinkTaskGetsUnusedLibHeaderOnly() 140 | { 141 | var eventSource = new MockEventSource(); 142 | var eventRedirector = new MockEventRedirector(); 143 | var logger = new ForwardingLogger { BuildEventRedirector = eventRedirector }; 144 | logger.Initialize(eventSource); 145 | try 146 | { 147 | eventSource.AssertExpectedForwardingEventSubscriptions(); 148 | eventSource.SendTaskStarted(new TaskStartedEventArgs(message: "Link starting", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link")); 149 | Assert.AreEqual(0, eventRedirector.Events.Count); 150 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: "Unused libraries:", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 151 | Assert.AreEqual(0, eventRedirector.Events.Count); 152 | eventSource.SendTaskFinished(new TaskFinishedEventArgs(message: "Link finished", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link", succeeded: true)); 153 | Assert.AreEqual(0, eventRedirector.Events.Count); 154 | } 155 | finally 156 | { 157 | logger.Shutdown(); 158 | } 159 | } 160 | 161 | [TestMethod] 162 | public void ForwardingLogger_ForwardsUnusedLibs() 163 | { 164 | var eventSource = new MockEventSource(); 165 | var eventRedirector = new MockEventRedirector(); 166 | var logger = new ForwardingLogger { BuildEventRedirector = eventRedirector }; 167 | logger.Initialize(eventSource); 168 | try 169 | { 170 | eventSource.AssertExpectedForwardingEventSubscriptions(); 171 | eventSource.SendTaskStarted(new TaskStartedEventArgs(message: "Link starting", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link")); 172 | Assert.AreEqual(0, eventRedirector.Events.Count); 173 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: "Unused libraries:", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 174 | Assert.AreEqual(0, eventRedirector.Events.Count); 175 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: " user32.lib", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 176 | Assert.AreEqual(0, eventRedirector.Events.Count); 177 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: " bar.lib", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 178 | Assert.AreEqual(0, eventRedirector.Events.Count); 179 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: string.Empty, helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 180 | Assert.AreEqual(0, eventRedirector.Events.Count); 181 | eventSource.SendTaskFinished(new TaskFinishedEventArgs(message: "Link finished", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link", succeeded: true)); 182 | Assert.AreEqual(1, eventRedirector.Events.Count); 183 | var unusedLibArgs = eventRedirector.Events[0] as UnusedLibsCustomBuildEventArgs; 184 | Assert.IsNotNull(unusedLibArgs); 185 | Assert.AreEqual("a.proj", unusedLibArgs.ProjectPath); 186 | Assert.IsTrue(unusedLibArgs.Message!.Contains("user32.lib", StringComparison.Ordinal), unusedLibArgs.Message); 187 | Assert.IsTrue(unusedLibArgs.Message.Contains("bar.lib", StringComparison.Ordinal), unusedLibArgs.Message); 188 | Assert.IsTrue(unusedLibArgs.UnusedLibraryPathsJson.Length > 0); 189 | } 190 | finally 191 | { 192 | logger.Shutdown(); 193 | } 194 | } 195 | 196 | [TestMethod] 197 | public void ForwardingLogger_ForwardsNothingIfLinkTaskFails() 198 | { 199 | var eventSource = new MockEventSource(); 200 | var eventRedirector = new MockEventRedirector(); 201 | var logger = new ForwardingLogger { BuildEventRedirector = eventRedirector }; 202 | logger.Initialize(eventSource); 203 | try 204 | { 205 | eventSource.AssertExpectedForwardingEventSubscriptions(); 206 | eventSource.SendTaskStarted(new TaskStartedEventArgs(message: "Link starting", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link")); 207 | Assert.AreEqual(0, eventRedirector.Events.Count); 208 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: "Unused libraries:", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 209 | Assert.AreEqual(0, eventRedirector.Events.Count); 210 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: " kernel32.lib", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 211 | Assert.AreEqual(0, eventRedirector.Events.Count); 212 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: " foo.lib", helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 213 | Assert.AreEqual(0, eventRedirector.Events.Count); 214 | eventSource.SendMessageRaised(new BuildMessageEventArgs(message: string.Empty, helpKeyword: "Link", senderName: "Link", MessageImportance.High, DateTime.Now) { ProjectFile = "a.proj" }); 215 | Assert.AreEqual(0, eventRedirector.Events.Count); 216 | eventSource.SendTaskFinished(new TaskFinishedEventArgs(message: "Link finished", helpKeyword: "Link", projectFile: "a.proj", taskFile: "a.proj", taskName: "Link", succeeded: false)); 217 | Assert.AreEqual(0, eventRedirector.Events.Count); 218 | } 219 | finally 220 | { 221 | logger.Shutdown(); 222 | } 223 | } 224 | 225 | [TestMethod] 226 | [DoNotParallelize] 227 | public void CentralLogger_WritesNoJsonIfNoUnusedLibEvents() 228 | { 229 | string jsonPath = Path.Combine(Environment.CurrentDirectory, CentralLogger.JsonLogFileName); 230 | DeleteIfExists(jsonPath); 231 | 232 | var eventSource = new MockEventSource(); 233 | var centralLogger = new CentralLogger(); 234 | centralLogger.Initialize(eventSource); 235 | eventSource.AssertExpectedCentralLoggerEventSubscriptions(); 236 | eventSource.SendCustomEvent(new NonUnusedLibCustomEventArgs()); 237 | eventSource.SendCustomEvent(new UnusedLibsCustomBuildEventArgs()); 238 | centralLogger.Shutdown(); 239 | Assert.IsFalse(File.Exists(jsonPath)); 240 | } 241 | 242 | [TestMethod] 243 | [DoNotParallelize] 244 | public async Task CentralLogger_JsonOnUnusedLibEvents() 245 | { 246 | string jsonPath = Path.Combine(Environment.CurrentDirectory, CentralLogger.JsonLogFileName); 247 | DeleteIfExists(jsonPath); 248 | 249 | var eventSource = new MockEventSource(); 250 | var centralLogger = new CentralLogger(); 251 | centralLogger.Initialize(eventSource); 252 | eventSource.AssertExpectedCentralLoggerEventSubscriptions(); 253 | eventSource.SendCustomEvent(new UnusedLibsCustomBuildEventArgs(message: "Unused libraries!", 254 | projectPath: "a.proj", unusedLibraryPathsJson: "{ \"aProp\": \"aValue\" }")); 255 | eventSource.SendCustomEvent(new UnusedLibsCustomBuildEventArgs(message: "Unused libraries 2!", 256 | projectPath: "a2.proj", unusedLibraryPathsJson: "{ \"aProp2\": \"aValue2\" }")); 257 | centralLogger.Shutdown(); 258 | Assert.IsTrue(File.Exists(jsonPath)); 259 | Assert.AreEqual($"[{Environment.NewLine}{{ \"aProp\": \"aValue\" }},{Environment.NewLine}{{ \"aProp2\": \"aValue2\" }}{Environment.NewLine}]{Environment.NewLine}", 260 | await File.ReadAllTextAsync(jsonPath)); 261 | } 262 | 263 | private static void DeleteIfExists(string path) 264 | { 265 | if (File.Exists(path)) 266 | { 267 | File.Delete(path); 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/Tests/ReferenceTrimmer.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | x64 5 | AnyCPU;x64 6 | $(NoWarn);0067;1591;CA1861 7 | 8 | 9 | $(DefaultItemExcludes);TestData/**;TestResults/** 10 | 11 | 12 | 13 | false 14 | Build;Pack 15 | 16 | 17 | 18 | 19 | 20 | PreserveNewest 21 | 22 | 23 | 24 | 25 | 26 | PreserveNewest 27 | 28 | 29 | 30 | 31 | 35 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Tests/TestData/AbsoluteIntermediateOutputPath/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Newtonsoft.Json.JsonConvert.SerializeObject(null); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/AbsoluteIntermediateOutputPath/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | $(MSBuildProjectDirectory)\obj 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/BuildExtensions/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/BuildExtensions/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/BuildExtensions/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | 7 | public static string Baz() => Newtonsoft.Json.JsonConvert.SerializeObject(null); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/BuildExtensions/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net462 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Tests/TestData/BuildPackageReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | $(NoWarn);1591 7 | 8 | 10 | <_NuGetTargetFallbackMoniker>$(_NuGetTargetFallbackMoniker);native,Version=v0.0 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Tests/TestData/LegacyStyleProject/Library/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ClassLibrary1 8 | { 9 | public class Class1 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/LegacyStyleProject/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 80472081-bc7f-43a9-af72-dc02c677c2c1 8 | Library 9 | Properties 10 | Library 11 | Library 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\Library.xml 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | bin\Release\Library.xml 34 | 35 | 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | bin\Debug\Library.xml 44 | 45 | 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | bin\Release\Library.xml 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/Tests/TestData/LegacyStyleProject/Library/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ClassLibrary1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ClassLibrary1")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("80472081-bc7f-43a9-af72-dc02c677c2c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Tests/TestData/MissingReferenceSourceTarget/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/MissingReferenceSourceTarget/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | 6 | netstandard2.0 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/MissingReferenceSourceTarget/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/MissingReferenceSourceTarget/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/NoTargets/Project.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Tests/TestData/PackageReferenceWithFakeBuildFile/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Newtonsoft.Json.JsonConvert.SerializeObject(null); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/PackageReferenceWithFakeBuildFile/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/PlatformPackageConflictResolution/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/PlatformPackageConflictResolution/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/ReferenceInPackage/Tests/FooTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace Tests 4 | { 5 | [TestClass] 6 | public class FooTests 7 | { 8 | [TestMethod] 9 | public static void Foo() => Assert.IsTrue(true); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Tests/TestData/ReferenceInPackage/Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/ReferenceTrimmerDisabled/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/ReferenceTrimmerDisabled/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | false 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Tests/TestData/TargetFrameworkWithOs/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library; 2 | 3 | public static class Foo 4 | { 5 | public static string Bar() => Newtonsoft.Json.JsonConvert.SerializeObject(null); 6 | } 7 | -------------------------------------------------------------------------------- /src/Tests/TestData/TargetFrameworkWithOs/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net6.0-windows 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/App/App.cpp: -------------------------------------------------------------------------------- 1 | // App.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | 6 | int main() 7 | { 8 | std::cout << "Hello World!\n"; 9 | } 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/App/App.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | Win32 6 | 7 | 8 | Release 9 | Win32 10 | 11 | 12 | Debug 13 | x64 14 | 15 | 16 | Release 17 | x64 18 | 19 | 20 | 21 | 16.0 22 | {500F3F51-4D42-48DB-BA30-B8DA2864F168} 23 | Win32Proj 24 | App 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | 117 | 118 | Level3 119 | MaxSpeed 120 | true 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 137 | Level3 138 | MaxSpeed 139 | true 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | 145 | 146 | Console 147 | true 148 | true 149 | true 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | {10e385bf-5b1f-49be-b708-afc869118cf2} 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/Dll/DLL.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | Win32Proj 24 | {10e385bf-5b1f-49be-b708-afc869118cf2} 25 | DLL 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 78 | true 79 | Use 80 | pch.h 81 | 82 | 83 | Windows 84 | true 85 | false 86 | 87 | 88 | 89 | 90 | Level3 91 | true 92 | true 93 | true 94 | WIN32;NDEBUG;DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 95 | true 96 | Use 97 | pch.h 98 | 99 | 100 | Windows 101 | true 102 | true 103 | true 104 | false 105 | 106 | 107 | 108 | 109 | Level3 110 | true 111 | _DEBUG;DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 112 | true 113 | Use 114 | pch.h 115 | 116 | 117 | Windows 118 | true 119 | false 120 | 121 | 122 | 123 | 124 | Level3 125 | true 126 | true 127 | true 128 | NDEBUG;DLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 129 | true 130 | Use 131 | pch.h 132 | 133 | 134 | Windows 135 | true 136 | true 137 | true 138 | false 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Create 149 | Create 150 | Create 151 | Create 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/Dll/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "pch.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | __declspec(dllexport) void __cdecl DoNothingInDll() 21 | { 22 | // Do nothing 23 | } 24 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/Dll/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 4 | // Windows Header Files 5 | #include 6 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/Dll/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppDelayLoadLibrary/Dll/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: This is a precompiled header file. 2 | // Files listed below are compiled only once, improving build performance for future builds. 3 | // This also affects IntelliSense performance, including code completion and many code browsing features. 4 | // However, files listed here are ALL re-compiled if any one of them is updated between builds. 5 | // Do not add files here that you will be updating frequently as this negates the performance advantage. 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // add headers that you want to pre-compile here 11 | #include "framework.h" 12 | 13 | #endif //PCH_H 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppLibrary/App/App.cpp: -------------------------------------------------------------------------------- 1 | // App.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | 6 | int main() 7 | { 8 | std::cout << "Hello World!\n"; 9 | } 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppLibrary/App/App.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | Win32 6 | 7 | 8 | Release 9 | Win32 10 | 11 | 12 | Debug 13 | x64 14 | 15 | 16 | Release 17 | x64 18 | 19 | 20 | 21 | 16.0 22 | {500F3F51-4D42-48DB-BA30-B8DA2864F168} 23 | Win32Proj 24 | App 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | 117 | 118 | Level3 119 | MaxSpeed 120 | true 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 137 | Level3 138 | MaxSpeed 139 | true 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | 145 | 146 | Console 147 | true 148 | true 149 | true 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | {f3844c7d-e56d-42bc-8169-cb466a06bdfc} 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppLibrary/Library/Library.cpp: -------------------------------------------------------------------------------- 1 | void DoNothing() 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedCppLibrary/Library/Library.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | Win32 6 | 7 | 8 | Release 9 | Win32 10 | 11 | 12 | Debug 13 | x64 14 | 15 | 16 | Release 17 | x64 18 | 19 | 20 | 21 | 17.0 22 | Win32Proj 23 | {f3844c7d-e56d-42bc-8169-cb466a06bdfc} 24 | StaticLib 25 | 10.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | StaticLibrary 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Level3 75 | true 76 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 77 | true 78 | 79 | 80 | 81 | 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | 96 | 97 | true 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_LIB;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | 111 | 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | true 120 | true 121 | NDEBUG;_LIB;%(PreprocessorDefinitions) 122 | true 123 | 124 | 125 | 126 | 127 | true 128 | true 129 | true 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Bar"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/TransitiveDependency/TransitiveDependency.cs: -------------------------------------------------------------------------------- 1 | namespace TransitiveDependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Baz() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedDirectAndTransitiveProjectReference/TransitiveDependency/TransitiveDependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceDocDisabled/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceDocDisabled/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceNoWarn/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceNoWarn/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceTreatAsUsed/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedPackageReferenceTreatAsUsed/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReference/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReference/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoReferenceAssembly/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoReferenceAssembly/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | false 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoReferenceAssembly/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoReferenceAssembly/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoWarn/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoWarn/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoWarn/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceNoWarn/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceProduceReferenceAssembly/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceProduceReferenceAssembly/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceProduceReferenceAssembly/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceProduceReferenceAssembly/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceSuppressed/.globalconfig: -------------------------------------------------------------------------------- 1 | is_global=true 2 | 3 | dotnet_diagnostic.RT0002.severity = suggestion -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceSuppressed/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceSuppressed/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceSuppressed/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceSuppressed/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceTreatAsUsed/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceTreatAsUsed/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceTreatAsUsed/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedProjectReferenceTreatAsUsed/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceFromGac/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ClassLibrary1 8 | { 9 | public class Class1 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceFromGac/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 80472081-bc7f-43a9-af72-dc02c677c2c1 8 | Library 9 | Properties 10 | Library 11 | Library 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\Library.xml 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | bin\Release\Library.xml 34 | 35 | 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | bin\Debug\Library.xml 44 | 45 | 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | bin\Release\Library.xml 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceFromGac/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ClassLibrary1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ClassLibrary1")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("80472081-bc7f-43a9-af72-dc02c677c2c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPath/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPath/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPath/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPath/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | ..\Dependency\$(OutputPath)\Dependency.dll 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathNoWarn/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathNoWarn/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathNoWarn/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathNoWarn/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | ..\Dependency\$(OutputPath)\Dependency.dll 11 | Foo; rt0001 ; Bar 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathTreatAsUsed/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathTreatAsUsed/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathTreatAsUsed/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceHintPathTreatAsUsed/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | ..\Dependency\$(OutputPath)\Dependency.dll 11 | true 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpec/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpec/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpec/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpec/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecNoWarn/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecNoWarn/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecNoWarn/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecNoWarn/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecTreatAsUsed/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecTreatAsUsed/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecTreatAsUsed/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedReferenceItemSpecTreatAsUsed/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Bar"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/TransitiveDependency/TransitiveDependency.cs: -------------------------------------------------------------------------------- 1 | namespace TransitiveDependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Baz() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedTransitiveProjectReference/TransitiveDependency/TransitiveDependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedWinSdkImportLibrary/App/App.cpp: -------------------------------------------------------------------------------- 1 | // App.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include 5 | 6 | int main() 7 | { 8 | std::cout << "Hello World!\n"; 9 | } 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedWinSdkImportLibrary/App/App.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | Win32 6 | 7 | 8 | Release 9 | Win32 10 | 11 | 12 | Debug 13 | x64 14 | 15 | 16 | Release 17 | x64 18 | 19 | 20 | 21 | 16.0 22 | {500F3F51-4D42-48DB-BA30-B8DA2864F168} 23 | Win32Proj 24 | App 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | 117 | 118 | Level3 119 | MaxSpeed 120 | true 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | 136 | 137 | Level3 138 | MaxSpeed 139 | true 140 | true 141 | true 142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | true 144 | 145 | 146 | Console 147 | true 148 | true 149 | true 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/Tests/TestData/UnusedWinSdkImportLibrary/App/util.cpp: -------------------------------------------------------------------------------- 1 | int doSomething() 2 | { 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedIndirectPackageReference/WebHost/Program.cs: -------------------------------------------------------------------------------- 1 | namespace WebHost 2 | { 3 | using System.IO; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | 10 | public class Program 11 | { 12 | public static Task Main() 13 | { 14 | return new WebHostBuilder() 15 | .UseKestrel(options => options.Listen(IPAddress.Loopback, 5001)) 16 | .UseContentRoot(Directory.GetCurrentDirectory()) 17 | .Configure(app => 18 | app.Run(async context => 19 | { 20 | await context.Response.WriteAsync("Hello World!"); 21 | })) 22 | .Build() 23 | .RunAsync(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedIndirectPackageReference/WebHost/WebHost.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | Latest 6 | true 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedPackageReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Newtonsoft.Json.JsonConvert.SerializeObject(null); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedPackageReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReference/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReference/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReference/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReference/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceNoReferenceAssembly/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceNoReferenceAssembly/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | false 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceNoReferenceAssembly/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceNoReferenceAssembly/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceProduceReferenceAssembly/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceProduceReferenceAssembly/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceProduceReferenceAssembly/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedProjectReferenceProduceReferenceAssembly/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | true 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceFromGac/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Office.Interop.Outlook; 7 | 8 | namespace ClassLibrary1 9 | { 10 | public class Class1 11 | { 12 | public Application CreateApplication() => new Application(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceFromGac/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 80472081-bc7f-43a9-af72-dc02c677c2c1 8 | Library 9 | Properties 10 | Library 11 | Library 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | bin\Debug\Library.xml 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | bin\Release\Library.xml 34 | 35 | 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | bin\Debug\Library.xml 44 | 45 | 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | bin\Release\Library.xml 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceFromGac/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ClassLibrary1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ClassLibrary1")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("80472081-bc7f-43a9-af72-dc02c677c2c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceHintPath/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceHintPath/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceHintPath/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceHintPath/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | ..\Dependency\$(OutputPath)\Dependency.dll 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceItemSpec/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceItemSpec/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceItemSpec/Library/Library.cs: -------------------------------------------------------------------------------- 1 | namespace Library 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => Dependency.Foo.Bar(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/UsedReferenceItemSpec/Library/Library.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net472 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/Dependency/Dependency.cs: -------------------------------------------------------------------------------- 1 | namespace Dependency 2 | { 3 | public static class Foo 4 | { 5 | public static string Bar() => "Baz"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/Dependency/Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using System.Data; 3 | using System.Windows; 4 | 5 | namespace WpfApp 6 | { 7 | /// 8 | /// Interaction logic for App.xaml 9 | /// 10 | public partial class App : Application 11 | { 12 | // Use the dependency 13 | public string X = Dependency.Foo.Bar(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using System.Windows.Data; 5 | using System.Windows.Documents; 6 | using System.Windows.Input; 7 | using System.Windows.Media; 8 | using System.Windows.Media.Imaging; 9 | using System.Windows.Navigation; 10 | using System.Windows.Shapes; 11 | 12 | namespace WpfApp 13 | { 14 | /// 15 | /// Interaction logic for MainWindow.xaml 16 | /// 17 | public partial class MainWindow : Window 18 | { 19 | public MainWindow() 20 | { 21 | InitializeComponent(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Tests/TestData/WpfApp/WpfApp/WpfApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows 6 | enable 7 | enable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "3.3", 4 | "assemblyVersion": "3.3", 5 | "buildNumberOffset": -1, 6 | "publicReleaseRefSpec": [ 7 | "^refs/tags/v\\d+\\.\\d+\\.\\d+" 8 | ], 9 | "cloudBuild": { 10 | "setVersionVariables": true, 11 | "buildNumber": { 12 | "enabled": true, 13 | "includeCommitId": { 14 | "when": "nonPublicReleaseOnly", 15 | "where": "buildMetadata" 16 | } 17 | } 18 | } 19 | } --------------------------------------------------------------------------------