├── .gitignore ├── LICENSE ├── README.md ├── distrib ├── Application Files │ ├── CallSharp_0_1_0_3 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ └── JetBrains.Annotations.dll.deploy │ ├── CallSharp_0_1_1_4 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ └── JetBrains.Annotations.dll.deploy │ ├── CallSharp_0_1_1_5 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ └── JetBrains.Annotations.dll.deploy │ ├── CallSharp_0_1_1_6 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ └── JetBrains.Annotations.dll.deploy │ ├── CallSharp_0_1_1_7 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ └── JetBrains.Annotations.dll.deploy │ ├── CallSharp_0_1_1_8 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ ├── Db │ │ │ └── StaticMemberDatabase.tt.deploy │ │ └── JetBrains.Annotations.dll.deploy │ └── CallSharp_0_2_0_0 │ │ ├── CallSharp.application │ │ ├── CallSharp.exe.config.deploy │ │ ├── CallSharp.exe.deploy │ │ ├── CallSharp.exe.manifest │ │ ├── Db │ │ └── StaticMemberDatabase.tt.deploy │ │ └── JetBrains.Annotations.dll.deploy ├── CallSharp.application └── setup.exe ├── site └── screenshot.png └── src ├── CallSharp.sln ├── CallSharp ├── App.config ├── App.xaml ├── App.xaml.cs ├── CallSharp.csproj ├── CallSharp.csproj.DotSettings ├── Class1.cs ├── Cuda.cs ├── Db │ ├── DynamicMemberDatabase.cs │ ├── IMemberDatabase.cs │ ├── StaticMemberDatabase.cs │ └── StaticMemberDatabase.tt ├── Empty.cs ├── EnumerableExtensions.cs ├── ExtensionMethods.cs ├── Fragmentation │ ├── FragmentationEngine.cs │ ├── IFragmentationEngine.cs │ └── NullFragmentationEngine.cs ├── MagicTextBox.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MethodCallCookie.cs ├── ObservableHashSet.cs ├── PermuteUtils.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── ScaleToWindowSizeBehavior.cs ├── TypeDatabase.cs ├── TypeToStringConverter.cs └── packages.config └── Tests ├── BasicMatchTests.cs ├── Categories.cs ├── FragTests.cs ├── OtherTests.cs ├── Properties └── AssemblyInfo.cs ├── Tests.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/csharp,visualstudio 3 | 4 | ### Csharp ### 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | 8 | # User-specific files 9 | *.suo 10 | *.user 11 | *.userosscache 12 | *.sln.docstates 13 | 14 | # User-specific files (MonoDevelop/Xamarin Studio) 15 | *.userprefs 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Dd]ebugPublic/ 20 | [Rr]elease/ 21 | [Rr]eleases/ 22 | x64/ 23 | x86/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | [Ll]og/ 28 | 29 | # Visual Studio 2015 cache/options directory 30 | .vs/ 31 | # Uncomment if you have tasks that create the project's static files in wwwroot 32 | #wwwroot/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | # NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 46 | 47 | # DNX 48 | project.lock.json 49 | project.fragment.lock.json 50 | artifacts/ 51 | 52 | *_i.c 53 | *_p.c 54 | *_i.h 55 | *.ilk 56 | *.meta 57 | *.obj 58 | *.pch 59 | *.pdb 60 | *.pgc 61 | *.pgd 62 | *.rsp 63 | *.sbr 64 | *.tlb 65 | *.tli 66 | *.tlh 67 | *.tmp 68 | *.tmp_proj 69 | *.log 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 ignoreable 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 | node_modules/ 204 | orleans.codegen.cs 205 | 206 | # Since there are multiple workflows, uncomment next line to ignore bower_components 207 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 208 | #bower_components/ 209 | 210 | # RIA/Silverlight projects 211 | Generated_Code/ 212 | 213 | # Backup & report files from converting an old project file 214 | # to a newer Visual Studio version. Backup files are not needed, 215 | # because we have git ;-) 216 | _UpgradeReport_Files/ 217 | Backup*/ 218 | UpgradeLog*.XML 219 | UpgradeLog*.htm 220 | 221 | # SQL Server files 222 | *.mdf 223 | *.ldf 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 | 239 | # Visual Studio 6 build log 240 | *.plg 241 | 242 | # Visual Studio 6 workspace options file 243 | *.opt 244 | 245 | # Visual Studio LightSwitch build output 246 | **/*.HTMLClient/GeneratedArtifacts 247 | **/*.DesktopClient/GeneratedArtifacts 248 | **/*.DesktopClient/ModelManifest.xml 249 | **/*.Server/GeneratedArtifacts 250 | **/*.Server/ModelManifest.xml 251 | _Pvt_Extensions 252 | 253 | # Paket dependency manager 254 | .paket/paket.exe 255 | paket-files/ 256 | 257 | # FAKE - F# Make 258 | .fake/ 259 | 260 | # JetBrains Rider 261 | .idea/ 262 | *.sln.iml 263 | 264 | # CodeRush 265 | .cr/ 266 | 267 | # Python Tools for Visual Studio (PTVS) 268 | __pycache__/ 269 | *.pyc 270 | 271 | # Cake - Uncomment if you are using it 272 | # tools/ 273 | 274 | 275 | ### VisualStudio ### 276 | ## Ignore Visual Studio temporary files, build results, and 277 | ## files generated by popular Visual Studio add-ons. 278 | 279 | # User-specific files 280 | *.suo 281 | *.user 282 | *.userosscache 283 | *.sln.docstates 284 | 285 | # User-specific files (MonoDevelop/Xamarin Studio) 286 | *.userprefs 287 | 288 | # Build results 289 | [Dd]ebug/ 290 | [Dd]ebugPublic/ 291 | [Rr]elease/ 292 | [Rr]eleases/ 293 | x64/ 294 | x86/ 295 | bld/ 296 | [Bb]in/ 297 | [Oo]bj/ 298 | [Ll]og/ 299 | 300 | # Visual Studio 2015 cache/options directory 301 | .vs/ 302 | # Uncomment if you have tasks that create the project's static files in wwwroot 303 | #wwwroot/ 304 | 305 | # MSTest test Results 306 | [Tt]est[Rr]esult*/ 307 | [Bb]uild[Ll]og.* 308 | 309 | # NUNIT 310 | *.VisualState.xml 311 | TestResult.xml 312 | 313 | # Build Results of an ATL Project 314 | [Dd]ebugPS/ 315 | [Rr]eleasePS/ 316 | dlldata.c 317 | 318 | # DNX 319 | project.lock.json 320 | project.fragment.lock.json 321 | artifacts/ 322 | 323 | *_i.c 324 | *_p.c 325 | *_i.h 326 | *.ilk 327 | *.meta 328 | *.obj 329 | *.pch 330 | *.pdb 331 | *.pgc 332 | *.pgd 333 | *.rsp 334 | *.sbr 335 | *.tlb 336 | *.tli 337 | *.tlh 338 | *.tmp 339 | *.tmp_proj 340 | *.log 341 | *.vspscc 342 | *.vssscc 343 | .builds 344 | *.pidb 345 | *.svclog 346 | *.scc 347 | 348 | # Chutzpah Test files 349 | _Chutzpah* 350 | 351 | # Visual C++ cache files 352 | ipch/ 353 | *.aps 354 | *.ncb 355 | *.opendb 356 | *.opensdf 357 | *.sdf 358 | *.cachefile 359 | *.VC.db 360 | *.VC.VC.opendb 361 | 362 | # Visual Studio profiler 363 | *.psess 364 | *.vsp 365 | *.vspx 366 | *.sap 367 | 368 | # TFS 2012 Local Workspace 369 | $tf/ 370 | 371 | # Guidance Automation Toolkit 372 | *.gpState 373 | 374 | # ReSharper is a .NET coding add-in 375 | _ReSharper*/ 376 | *.[Rr]e[Ss]harper 377 | *.DotSettings.user 378 | 379 | # JustCode is a .NET coding add-in 380 | .JustCode 381 | 382 | # TeamCity is a build add-in 383 | _TeamCity* 384 | 385 | # DotCover is a Code Coverage Tool 386 | *.dotCover 387 | 388 | # Visual Studio code coverage results 389 | *.coverage 390 | *.coveragexml 391 | 392 | # NCrunch 393 | _NCrunch_* 394 | .*crunch*.local.xml 395 | nCrunchTemp_* 396 | 397 | # MightyMoose 398 | *.mm.* 399 | AutoTest.Net/ 400 | 401 | # Web workbench (sass) 402 | .sass-cache/ 403 | 404 | # Installshield output folder 405 | [Ee]xpress/ 406 | 407 | # DocProject is a documentation generator add-in 408 | DocProject/buildhelp/ 409 | DocProject/Help/*.HxT 410 | DocProject/Help/*.HxC 411 | DocProject/Help/*.hhc 412 | DocProject/Help/*.hhk 413 | DocProject/Help/*.hhp 414 | DocProject/Help/Html2 415 | DocProject/Help/html 416 | 417 | # Click-Once directory 418 | publish/ 419 | 420 | # Publish Web Output 421 | *.[Pp]ublish.xml 422 | *.azurePubxml 423 | # TODO: Comment the next line if you want to checkin your web deploy settings 424 | # but database connection strings (with potential passwords) will be unencrypted 425 | *.pubxml 426 | *.publishproj 427 | 428 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 429 | # checkin your Azure Web App publish settings, but sensitive information contained 430 | # in these scripts will be unencrypted 431 | PublishScripts/ 432 | 433 | # NuGet Packages 434 | *.nupkg 435 | # The packages folder can be ignored because of Package Restore 436 | **/packages/* 437 | # except build/, which is used as an MSBuild target. 438 | !**/packages/build/ 439 | # Uncomment if necessary however generally it will be regenerated when needed 440 | #!**/packages/repositories.config 441 | # NuGet v3's project.json files produces more ignoreable files 442 | *.nuget.props 443 | *.nuget.targets 444 | 445 | # Microsoft Azure Build Output 446 | csx/ 447 | *.build.csdef 448 | 449 | # Microsoft Azure Emulator 450 | ecf/ 451 | rcf/ 452 | 453 | # Windows Store app package directories and files 454 | AppPackages/ 455 | BundleArtifacts/ 456 | Package.StoreAssociation.xml 457 | _pkginfo.txt 458 | 459 | # Visual Studio cache files 460 | # files ending in .cache can be ignored 461 | *.[Cc]ache 462 | # but keep track of directories ending in .cache 463 | !*.[Cc]ache/ 464 | 465 | # Others 466 | ClientBin/ 467 | ~$* 468 | *~ 469 | *.dbmdl 470 | *.dbproj.schemaview 471 | *.jfm 472 | *.pfx 473 | *.publishsettings 474 | node_modules/ 475 | orleans.codegen.cs 476 | 477 | # Since there are multiple workflows, uncomment next line to ignore bower_components 478 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 479 | #bower_components/ 480 | 481 | # RIA/Silverlight projects 482 | Generated_Code/ 483 | 484 | # Backup & report files from converting an old project file 485 | # to a newer Visual Studio version. Backup files are not needed, 486 | # because we have git ;-) 487 | _UpgradeReport_Files/ 488 | Backup*/ 489 | UpgradeLog*.XML 490 | UpgradeLog*.htm 491 | 492 | # SQL Server files 493 | *.mdf 494 | *.ldf 495 | 496 | # Business Intelligence projects 497 | *.rdl.data 498 | *.bim.layout 499 | *.bim_*.settings 500 | 501 | # Microsoft Fakes 502 | FakesAssemblies/ 503 | 504 | # GhostDoc plugin setting file 505 | *.GhostDoc.xml 506 | 507 | # Node.js Tools for Visual Studio 508 | .ntvs_analysis.dat 509 | 510 | # Visual Studio 6 build log 511 | *.plg 512 | 513 | # Visual Studio 6 workspace options file 514 | *.opt 515 | 516 | # Visual Studio LightSwitch build output 517 | **/*.HTMLClient/GeneratedArtifacts 518 | **/*.DesktopClient/GeneratedArtifacts 519 | **/*.DesktopClient/ModelManifest.xml 520 | **/*.Server/GeneratedArtifacts 521 | **/*.Server/ModelManifest.xml 522 | _Pvt_Extensions 523 | 524 | # Paket dependency manager 525 | .paket/paket.exe 526 | paket-files/ 527 | 528 | # FAKE - F# Make 529 | .fake/ 530 | 531 | # JetBrains Rider 532 | .idea/ 533 | *.sln.iml 534 | 535 | # CodeRush 536 | .cr/ 537 | 538 | # Python Tools for Visual Studio (PTVS) 539 | __pycache__/ 540 | *.pyc 541 | 542 | # Cake - Uncomment if you are using it 543 | # tools/ 544 | 545 | ### VisualStudio Patch ### 546 | build/ 547 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Dmitri Nesteruk 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CallSharp 2 | Helper tool for inferring function call chains dependent on input and expected output. 3 | 4 | This is a self-updating app; to install it, click here. 5 | 6 | 7 | 8 | ## Very tentative roadmap 9 | 10 | **0.1** Initial release; search works but takes an atrocious amount of time. 11 | 12 | **0.2** Search speed improvements (static API search). 13 | 14 | ** WE ARE HERE ** 15 | 16 | **0.3** Omission fixes: operators, properties, indexers, verification of constructor calls, support for generics. 17 | 18 | tbc. 19 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_0_3/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | CiVIOUmEL7OJqib8B6WQJ/J3zKfd32aZP+63RqmLqeU= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_0_3/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_0_3/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_0_3/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_0_3/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | B/rf2DkXctTqUbAgKt7DnAwh4frgHxssA+lXkBX0Q0c= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_0_3/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_0_3/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_4/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | u2AI3Y+Rh8ewSWHTU9ieJgSj5cx9SElobTyXAFmfKpU= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_4/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_4/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_4/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_4/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | FTjeFMEmAN0+tqc552JOycklt8EeVQvuLYFqnRkrIYM= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_4/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_4/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_5/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | b6YAOBxDg2/akiyYlSJgllRWWEv9KWaMbpCAJZS/dr4= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_5/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_5/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_5/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_5/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | jez0CSgvV2Hyf+K0ec+8U2WiIGdw2hCQMIHKsPdwzAs= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_5/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_5/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_6/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 9MySKrbJjsCXXJdA5LHVOZ4kXg+g1ZtoQKAnJ38oqQk= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_6/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_6/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_6/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_6/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | W6RB31eMDLkOokOyJmzfZOqx6ZYcCy5S3wgsIULmwUI= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_6/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_6/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_7/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | t/xx/k4YKeSwSlpUDga3yCAmu8c+GNn3jx8JjLqeQdQ= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_7/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_7/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_7/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_7/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | hvF3tHVnYlmjYHsHK//LyKucAsWhOLgSkZoBwjburjA= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_7/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_7/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | M5SHz/d9TmAwwO63yM0/aHflw7kGaU40BJQmzY7HMkU= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_8/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | JeqtW/29Tz6y38HcftZi1TBQgsBzpxtLi2rUOFgvt9U= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | z8B1Yi7ZLQei69WU+FjuNXVIuA1c3qYamZ3EDXWExnE= 84 | 85 | 86 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/Db/StaticMemberDatabase.tt.deploy: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Reflection" #> 4 | <#@ import namespace="System.Linq" #> 5 | <#@ import namespace="System.IO" #> 6 | <#@ import namespace="System.Text" #> 7 | <#@ import namespace="System.CodeDom" #> 8 | <#@ import namespace="System.CodeDom.Compiler" #> 9 | <#@ import namespace="System.Collections.Generic" #> 10 | 11 | <#@ output extension=".cs" #> 12 | 13 | <# 14 | 15 | var allowedTypes = new HashSet 16 | { 17 | typeof(int), 18 | typeof(long), 19 | typeof(short), 20 | typeof(sbyte), 21 | typeof(uint), 22 | typeof(ulong), 23 | typeof(ushort), 24 | typeof(byte), 25 | typeof(bool), 26 | typeof(float), 27 | typeof(double), 28 | typeof(decimal), 29 | typeof(DateTime), 30 | typeof(TimeSpan), 31 | typeof(char), 32 | typeof(string), 33 | typeof(Enumerable), 34 | typeof(Math) 35 | }; 36 | 37 | Func getFriendlyName = (Type type) => 38 | { 39 | var codeDomProvider = CodeDomProvider.CreateProvider("C#"); 40 | var typeReferenceExpression = 41 | new CodeTypeReferenceExpression(new CodeTypeReference( 42 | type.Name.Contains("RuntimeType") ? type.UnderlyingSystemType : type 43 | )); 44 | using (var writer = new StringWriter()) 45 | { 46 | codeDomProvider.GenerateCodeFromExpression(typeReferenceExpression, writer, 47 | new CodeGeneratorOptions()); 48 | return writer.GetStringBuilder().Replace("System.", string.Empty).ToString(); 49 | } 50 | }; 51 | 52 | Func isParams = pi => pi.GetCustomAttribute() != null; 53 | 54 | Func isSingleParamsArgument = ps => ps.Length == 1 && isParams(ps[0]); 55 | 56 | Dictionary> conversionMap = new Dictionary 57 | > 58 | { 59 | { 60 | typeof(decimal), new HashSet 61 | { 62 | typeof(sbyte), 63 | typeof(byte), 64 | typeof(short), 65 | typeof(ushort), 66 | typeof(int), 67 | typeof(uint), 68 | typeof(long), 69 | typeof(ulong), 70 | typeof(char) 71 | } 72 | }, 73 | { 74 | typeof(double), new HashSet 75 | { 76 | typeof(sbyte), 77 | typeof(byte), 78 | typeof(short), 79 | typeof(ushort), 80 | typeof(int), 81 | typeof(uint), 82 | typeof(long), 83 | typeof(ulong), 84 | typeof(char), 85 | typeof(float) 86 | } 87 | }, 88 | { 89 | typeof(float), new HashSet 90 | { 91 | typeof(sbyte), 92 | typeof(byte), 93 | typeof(short), 94 | typeof(ushort), 95 | typeof(int), 96 | typeof(uint), 97 | typeof(long), 98 | typeof(ulong), 99 | typeof(char), 100 | typeof(float) 101 | } 102 | }, 103 | { 104 | typeof(ulong), 105 | new HashSet {typeof(byte), typeof(ushort), typeof(uint), typeof(char)} 106 | }, 107 | { 108 | typeof(long), new HashSet 109 | { 110 | typeof(sbyte), 111 | typeof(byte), 112 | typeof(short), 113 | typeof(ushort), 114 | typeof(int), 115 | typeof(uint), 116 | typeof(char) 117 | } 118 | }, 119 | {typeof(uint), new HashSet {typeof(byte), typeof(ushort), typeof(char)}}, 120 | { 121 | typeof(int), 122 | new HashSet 123 | { 124 | typeof(sbyte), 125 | typeof(byte), 126 | typeof(short), 127 | typeof(ushort), 128 | typeof(char) 129 | } 130 | }, 131 | {typeof(ushort), new HashSet {typeof(byte), typeof(char)}}, 132 | {typeof(short), new HashSet {typeof(byte)}} 133 | }; 134 | 135 | 136 | var provisionOfThisArgumentIsOptional = new Func((ParameterInfo pi) => isParams(pi) || pi.HasDefaultValue); 137 | 138 | var isConvertibleTo = new Func((Type from, Type to) => 139 | { 140 | if (from == to || to.IsAssignableFrom(from)) 141 | { 142 | return true; 143 | } 144 | if (conversionMap.ContainsKey(to) && conversionMap[to].Contains(from)) 145 | { 146 | return true; 147 | } 148 | bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static) 149 | .Any( 150 | m => m.ReturnType == to && 151 | (m.Name == "op_Implicit" || m.Name == "op_Explicit") 152 | ); 153 | return castable; 154 | }); 155 | 156 | var allMethods = new List(); 157 | var allConstructors = new List(); 158 | 159 | foreach (var ass in AppDomain.CurrentDomain.GetAssemblies()) 160 | { 161 | try 162 | { 163 | foreach (var type in ass.ExportedTypes.Where(t => allowedTypes.Contains(t))) 164 | { 165 | var name = ass.GetName().Name; 166 | if (name.Contains("VisualStudio") || name.Contains("Temporary")) continue; 167 | 168 | var methods = type.GetMethods(); 169 | 170 | allMethods.AddRange(methods); 171 | 172 | foreach ( 173 | var ctor in type.GetConstructors().Where(c => !c.ContainsGenericParameters && 174 | c.GetParameters().Length == 1 && 175 | !c.GetParameters()[0].ParameterType.IsPointer)) 176 | { 177 | allConstructors.Add(ctor); 178 | } 179 | } 180 | } 181 | catch (Exception) 182 | { 183 | #> // cannot get exported types of <#= ass.GetName().Name 184 | #> <# 185 | } 186 | 187 | } 188 | #> 189 | 190 | namespace CallSharp 191 | { 192 | using System; 193 | using System.Diagnostics; 194 | using System.Collections.Generic; 195 | 196 | class StaticMemberDatabase : IMemberDatabase 197 | { 198 | private readonly IFragmentationEngine fragEngine = new FragmentationEngine(); 199 | 200 | public IEnumerable FindCandidates(object input, object output, int depth, 201 | string callChain = "input") 202 | { 203 | Trace.WriteLine(callChain); 204 | 205 | var inputType = input.GetType(); 206 | var outputType = output.GetType(); 207 | 208 | if (input.Equals(output)) 209 | { 210 | yield return callChain; 211 | yield break; 212 | } 213 | 214 | // here we try to brute-force conversion of input to output 215 | // if it succeeds, we break as before 216 | object newValue = null; 217 | try 218 | { 219 | newValue = Convert.ChangeType(output, inputType); 220 | } catch (Exception) { } 221 | if (input.Equals(newValue)) 222 | { 223 | yield return callChain; 224 | yield break; 225 | } 226 | 227 | bool foundSomething = false; 228 | 229 | // contains all calls that didn't yield the right result 230 | var failCookies = new List(); 231 | 232 | // note: technically, we collect fail cookies. or used to. 233 | 234 | // 1) Look for all matching constructors. 235 | <# 236 | foreach (var ctor in allConstructors) 237 | { 238 | #>if (output is <#= ctor.DeclaringType.FullName #> && input is <#= ctor.GetParameters()[0].ParameterType.FullName #>) 239 | { 240 | var instance = new <#= ctor.DeclaringType.FullName #>((<#= ctor.GetParameters()[0].ParameterType.FullName #>)input); 241 | if (instance == (<#= ctor.DeclaringType.FullName #>)output) 242 | { 243 | yield return $"new <#=getFriendlyName(ctor.DeclaringType)#>({callChain})"; 244 | foundSomething = true; 245 | } 246 | } 247 | <# 248 | } 249 | #> 250 | // 2) 1-to-1 instance functions. 251 | <# 252 | foreach (var method in allMethods.Where(m => !m.IsStatic && 253 | ( 254 | m.GetParameters().Length == 0 255 | || 256 | m.GetParameters().All(p => p.IsOptional) 257 | || 258 | isSingleParamsArgument(m.GetParameters()) 259 | ))) 260 | { // TODO: group by in/out pairs 261 | #> 262 | if (input is <#= method.DeclaringType.Name #> && typeof(<#= method.ReturnType.FullName #>).IsConvertibleTo(outputType)) 263 | { 264 | // invoke! 265 | <# if (method.Name.StartsWith("get_")) 266 | { #> 267 | var result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name.Substring(4) #>; 268 | <# } 269 | else 270 | { #> 271 | var result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name #>(); 272 | <# } #> 273 | if (Equals(result, output)) 274 | { 275 | <# 276 | var cookie = new MethodCallCookie( 277 | method, 278 | new object[]{} 279 | ); 280 | #> 281 | foundSomething = true; 282 | yield return string.Format("<#= cookie.ToString() #>", callChain); 283 | } 284 | } 285 | <# 286 | } 287 | #> 288 | // 3. Search static members 289 | <# 290 | foreach (var method in allMethods.Where(m => m.IsStatic && ( 291 | !m.Name.Equals("Parse") // throws 292 | && 293 | !m.Name.Equals("Delete") // just in case 294 | && 295 | m.GetParameters().Length == 1 296 | && 297 | !m.GetParameters()[0].ParameterType.IsGenericType 298 | && 299 | !m.ReturnType.IsGenericType 300 | && 301 | !m.Name.StartsWith("op_") 302 | ))) 303 | { 304 | var parameters = method.GetParameters(); 305 | // ensure input type is convertible to first parameter 306 | // todo: ensure we are avoiding ref/out 307 | #> 308 | if (inputType.IsConvertibleTo(typeof(<#= parameters[0].ParameterType.FullName #>)) && 309 | typeof(<#= method.ReturnType.FullName #>).IsConvertibleTo(outputType)) 310 | { 311 | string retVal = null; 312 | try 313 | { 314 | var result = <#= method.DeclaringType.FullName #>.<#= method.Name #>((<#= parameters[0].ParameterType.FullName #>)input); 315 | if (result == (<#= method.ReturnType.FullName #>)output) 316 | <# 317 | var cookie = new MethodCallCookie(method, new []{ "{0}" }); 318 | #> 319 | retVal = string.Format("<#= cookie.ToString() #>", callChain); 320 | } 321 | catch {} 322 | if (retVal != null) yield return retVal; 323 | } 324 | <# 325 | } 326 | #> 327 | // 4. Single-argument fragmentation (1-to-2 instance) 328 | if (true || !foundSomething) 329 | { 330 | <# 331 | int numberOfNonOptionalArguments = 1; 332 | foreach (var method in allMethods.Where(m => 333 | !m.IsStatic 334 | && 335 | m.GetParameters().Count(p => !provisionOfThisArgumentIsOptional(p)) == 336 | numberOfNonOptionalArguments 337 | && 338 | !m.Name.StartsWith("get_") // can actually be an indexer, cannot handle those 339 | )) 340 | { 341 | // check in-out 342 | // todo: get fragmentations first for each type 343 | #>foreach (var arg in fragEngine.Frag(input, typeof(<#= method.GetParameters()[0].ParameterType.FullName #>))) 344 | { 345 | if (input is <#= method.DeclaringType.Name #> 346 | && typeof(<#= method.ReturnType.FullName #>).IsConvertibleTo(outputType)) 347 | { 348 | <#= resultDeclaration(method.ReturnType) #> 349 | try { 350 | result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name #>((<#= method.GetParameters()[0].ParameterType.FullName #>)arg); 351 | } catch {} 352 | if (<#= resultAvailableCheck(method.ReturnType) #> && <#= resultMatchesOutput(method.ReturnType) #>) 353 | { 354 | <# 355 | var cookie = new MethodCallCookie(method, new object []{"{1}"}); 356 | #>foundSomething = true; 357 | yield return string.Format("<#= cookie.ToString() #>", callChain, 358 | arg.ToLiteral()); 359 | } 360 | } 361 | } 362 | <# 363 | } 364 | #> 365 | 366 | // 5. Two-argument fragmentation; like the above but with quad the complexity. 367 | if (true || !foundSomething) 368 | { 369 | 370 | <# 371 | numberOfNonOptionalArguments = 2; 372 | foreach (var method in allMethods.Where(m => 373 | !m.IsStatic 374 | && 375 | m.GetParameters().Count(p => !provisionOfThisArgumentIsOptional(p)) == 376 | numberOfNonOptionalArguments 377 | && 378 | !m.Name.StartsWith("get_") // can actually be an indexer, cannot handle those 379 | )) 380 | { 381 | // check in-out 382 | // todo: get fragmentations first for each type 383 | #>foreach (var arg1 in fragEngine.Frag(input, typeof(<#= method.GetParameters()[0].ParameterType.FullName #>))) 384 | foreach (var arg2 in fragEngine.Frag(input, typeof(<#= method.GetParameters()[1].ParameterType.FullName #>))) 385 | { 386 | if (input is <#= method.DeclaringType.Name #> 387 | && typeof(<#= method.ReturnType.FullName #>).IsConvertibleTo(outputType)) 388 | { 389 | <#= resultDeclaration(method.ReturnType) #> 390 | try { 391 | result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name #>( 392 | (<#= method.GetParameters()[0].ParameterType.FullName #>)arg1, 393 | (<#= method.GetParameters()[1].ParameterType.FullName #>)arg2 394 | ); 395 | } catch {} 396 | if (<#= resultCheck(method.ReturnType) #>) 397 | { 398 | <# 399 | var cookie = new MethodCallCookie(method, new object []{"{1}", "{2}"}); 400 | #>foundSomething = true; 401 | yield return string.Format("<#= cookie.ToString() #>", callChain, 402 | arg1.ToLiteral(), arg2.ToLiteral()); 403 | } 404 | } 405 | } 406 | <# 407 | } 408 | #> 409 | 410 | // 5. Assuming we found nothing and aren't in too deep (any-to-1), look for 411 | // methods which do NOT yield outputType 412 | if (/* !foundSomething && */ depth < 2) 413 | { 414 | <# 415 | foreach (var method in allMethods.Where(m => 416 | !m.IsStatic 417 | && 418 | ( 419 | m.GetParameters().Length == 0 420 | || 421 | m.GetParameters().All(p => p.IsOptional) 422 | || 423 | isSingleParamsArgument(m.GetParameters()) 424 | ) 425 | )) 426 | { 427 | #>if (input is <#= method.DeclaringType.Name #> && typeof(<#= method.ReturnType.FullName #>) == outputType) 428 | { 429 | <#= resultDeclaration(method.ReturnType) #> 430 | try { 431 | // invoke in the hope it yields something useful down the line 432 | <# if (method.Name.StartsWith("get_")) 433 | { #> 434 | result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name.Substring(4) #>; 435 | <# } 436 | else 437 | { #> 438 | result = ((<#= method.DeclaringType.FullName #>)input).<#= method.Name #>(); 439 | <# } #> 440 | <# 441 | var cookie = new MethodCallCookie( 442 | method, 443 | new object[]{} 444 | ); 445 | #> 446 | } catch { /* cannot reasonably handle this */} 447 | 448 | <# if (method.ReturnType.IsValueType) { #> 449 | if (result.HasValue && !Equals(result.Value, input)) 450 | { 451 | foreach (var c in FindCandidates(result.Value, output, depth+1, 452 | string.Format("<#= cookie.ToString() #>", callChain))) 453 | { 454 | yield return c; 455 | } 456 | } 457 | <# } else { #> 458 | if (result != null && !Equals(result, input)) 459 | { 460 | foreach (var c in FindCandidates(result, output, depth+1, 461 | string.Format("<#= cookie.ToString() #>", callChain))) 462 | { 463 | foundSomething = true; 464 | yield return c; 465 | } 466 | } 467 | <# } #> 468 | 469 | } 470 | <# 471 | } 472 | #> 473 | 474 | // 6. Look for similar, but static calls. Here we go again. 475 | <# 476 | foreach (var method in allMethods.Where(m => 477 | m.IsStatic 478 | && 479 | m.GetParameters().Length == 1 480 | && 481 | !m.GetParameters()[0].ParameterType.IsGenericType 482 | && 483 | !m.ReturnType.IsGenericType 484 | && 485 | !m.Name.StartsWith("op_") 486 | )) 487 | { 488 | var paramTypeName = method.GetParameters()[0].ParameterType.FullName; 489 | #> 490 | 491 | if (inputType == typeof(<#= paramTypeName #>)) 492 | { 493 | <#= resultDeclaration(method.ReturnType) #> 494 | try 495 | { 496 | result = <#= method.DeclaringType.FullName #>.<#= method.Name #>((<#= paramTypeName #>)input); 497 | } catch {} 498 | if (<#= resultCheck(method.ReturnType) #>) 499 | { 500 | <# MethodCallCookie cookie = new MethodCallCookie(method, new object[]{}); 501 | #>foreach (var c in FindCandidates(result<#= valueIfNeeded(method.ReturnType) #>, output, depth+1, 502 | string.Format("<#= cookie.ToString() #>", callChain))) 503 | { 504 | foundSomething = true; 505 | yield return c; 506 | } 507 | } 508 | } 509 | 510 | <# 511 | } // foreach method 512 | #> 513 | } 514 | } 515 | } 516 | } 517 | } 518 | } 519 | 520 | <#+ 521 | 522 | string valueIfNeeded(Type type) 523 | { 524 | if (type.IsValueType) return ".Value"; 525 | return String.Empty; 526 | } 527 | 528 | string resultDeclaration(Type type) 529 | { 530 | return type.IsValueType ? 531 | string.Format("{0}? result = new {0}?();", type.FullName) : 532 | $"{type.FullName} result = null;"; 533 | } 534 | 535 | string resultAvailableCheck(Type type) 536 | { 537 | if (type.IsValueType) return "result.HasValue"; 538 | else return "result != null"; 539 | } 540 | 541 | string resultMatchesOutput(Type type) 542 | { 543 | if (type.IsValueType) return $"result.Value == (({type.FullName})output)"; 544 | else return $"result == ({type.FullName})output"; 545 | } 546 | 547 | string resultCheck(Type type) 548 | { 549 | return $"{resultAvailableCheck(type)} && {resultMatchesOutput(type)}"; 550 | } 551 | 552 | #> 553 | 554 | <#+ 555 | 556 | /// 557 | /// This class contains all the information about an attempt to call 558 | /// a particular function on an input object. It contains information 559 | /// about the function called, the arguments that were applied and 560 | /// the resulting return value. 561 | /// 562 | public class MethodCallCookie 563 | { 564 | public MethodInfo MethodCalled; 565 | public object[] Arguments; 566 | public object ReturnValue; 567 | 568 | public MethodCallCookie(MethodInfo methodCalled, object[] arguments) 569 | { 570 | MethodCalled = methodCalled; 571 | Arguments = arguments; 572 | } 573 | 574 | /// 575 | /// The type of the return value. 576 | /// 577 | //public Type ReturnType => ReturnValue.GetType(); 578 | 579 | Func getFriendlyName = (Type type) => 580 | { 581 | var codeDomProvider = CodeDomProvider.CreateProvider("C#"); 582 | var typeReferenceExpression = 583 | new CodeTypeReferenceExpression(new CodeTypeReference( 584 | type.Name.Contains("RuntimeType") ? type.UnderlyingSystemType : type 585 | )); 586 | using (var writer = new StringWriter()) 587 | { 588 | codeDomProvider.GenerateCodeFromExpression(typeReferenceExpression, writer, 589 | new CodeGeneratorOptions()); 590 | return writer.GetStringBuilder().Replace("System.", string.Empty).ToString(); 591 | } 592 | }; 593 | 594 | static Func isParams = pi => pi.GetCustomAttribute() != null; 595 | 596 | static Func isSingleParamsArgument = ps => ps.Length == 1 && isParams(ps[0]); 597 | 598 | public string ToString(string subject = "{0}") 599 | { 600 | var sb = new StringBuilder(); 601 | var methodParams = MethodCalled.GetParameters(); 602 | 603 | // we either called it on a member . or on static X. 604 | if (MethodCalled.IsStatic) 605 | sb.Append(getFriendlyName(MethodCalled.DeclaringType)); 606 | else 607 | sb.Append(subject); 608 | sb.Append("."); 609 | 610 | if (MethodCalled.Name.StartsWith("get_")) 611 | { 612 | // just a property 613 | sb.Append(MethodCalled.Name.Substring(4)); 614 | } 615 | else 616 | { 617 | sb.Append(MethodCalled.Name).Append("("); 618 | 619 | int start = MethodCalled.IsStatic ? 1 : 0; 620 | for (int i = start; i < Arguments.Length; i++) 621 | { 622 | var arg = Arguments[i]; 623 | bool ip = isParams(methodParams[i]); 624 | 625 | // caveat: calling a params[] really passes in a single 626 | // 0-sized array :( need special handling 627 | var arr = arg as Array; 628 | if (arr != null && arr.Length == 0) 629 | break; 630 | 631 | // todo: literalize argument into code 632 | if (arg is string) 633 | { 634 | string s = (string) arg; 635 | if (s.Length == 0) 636 | sb.Append("string.Empty"); 637 | else if (s.StartsWith("{") && s.EndsWith("}")) 638 | sb.Append(arg); 639 | else 640 | sb.AppendFormat("\"{0}\"", arg); 641 | } 642 | else if (arg is char) 643 | { 644 | sb.AppendFormat("\'{0}'", arg); 645 | } 646 | else if (arg is char[]) 647 | { 648 | if (!ip) sb.Append("new char[]{"); 649 | sb.Append(string.Join(",", ((char[]) arg).Select(c => "'" + c + "'"))); 650 | if (!ip) sb.Append("}"); 651 | } 652 | else 653 | { 654 | sb.Append(arg); 655 | } 656 | 657 | if (i+1 != Arguments.Length) 658 | sb.Append(", "); 659 | } 660 | 661 | // on the other hand, a static call has NO arguments, so... 662 | if (MethodCalled.IsStatic) 663 | sb.Append(subject); 664 | 665 | sb.Append(")"); 666 | } 667 | return sb.ToString(); 668 | } 669 | } 670 | 671 | #> 672 | 673 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_1_1_8/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_1_1_8/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_2_0_0/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | kNzZyAezxFRFDBcb88NSo7X9BopefUopgyHeWVZTttU= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_2_0_0/CallSharp.exe.config.deploy: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_2_0_0/CallSharp.exe.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_2_0_0/CallSharp.exe.deploy -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_2_0_0/CallSharp.exe.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | qwrJ8Tyirm3OWHwWJ5M5ZSFWYlFa9OYskCk3Xie6FBw= 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | hMyfsqhG/5mgv9CScV0dLn7fKWMQ66404QBg2MF6cnA= 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xm4bo26HQ0LNVwz1vdPYtzhkpMnp2AI5i+f0b+OahTI= 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | z8B1Yi7ZLQei69WU+FjuNXVIuA1c3qYamZ3EDXWExnE= 84 | 85 | 86 | -------------------------------------------------------------------------------- /distrib/Application Files/CallSharp_0_2_0_0/JetBrains.Annotations.dll.deploy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/Application Files/CallSharp_0_2_0_0/JetBrains.Annotations.dll.deploy -------------------------------------------------------------------------------- /distrib/CallSharp.application: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | kNzZyAezxFRFDBcb88NSo7X9BopefUopgyHeWVZTttU= 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /distrib/setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/distrib/setup.exe -------------------------------------------------------------------------------- /site/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesteruk/CallSharp/accdfd681dd2c91127863bf9b6f688d669b6a842/site/screenshot.png -------------------------------------------------------------------------------- /src/CallSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CallSharp", "CallSharp\CallSharp.csproj", "{CC273AEA-10C3-4AA6-A8BF-A2437D6AB716}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{C12A3423-CFB5-4540-95C8-E5833A911C98}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CC273AEA-10C3-4AA6-A8BF-A2437D6AB716}.Debug|x64.ActiveCfg = Debug|x64 17 | {CC273AEA-10C3-4AA6-A8BF-A2437D6AB716}.Debug|x64.Build.0 = Debug|x64 18 | {CC273AEA-10C3-4AA6-A8BF-A2437D6AB716}.Release|x64.ActiveCfg = Release|x64 19 | {CC273AEA-10C3-4AA6-A8BF-A2437D6AB716}.Release|x64.Build.0 = Release|x64 20 | {C12A3423-CFB5-4540-95C8-E5833A911C98}.Debug|x64.ActiveCfg = Debug|x64 21 | {C12A3423-CFB5-4540-95C8-E5833A911C98}.Debug|x64.Build.0 = Debug|x64 22 | {C12A3423-CFB5-4540-95C8-E5833A911C98}.Release|x64.ActiveCfg = Release|x64 23 | {C12A3423-CFB5-4540-95C8-E5833A911C98}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/CallSharp/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/CallSharp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/CallSharp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace CallSharp 4 | { 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/CallSharp/CallSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CC273AEA-10C3-4AA6-A8BF-A2437D6AB716} 8 | WinExe 9 | Properties 10 | CallSharp 11 | CallSharp 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | true 17 | ..\..\distrib\ 18 | true 19 | Web 20 | true 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | https://raw.githubusercontent.com/nesteruk/CallSharp/master/distrib/ 28 | https://raw.githubusercontent.com/nesteruk/CallSharp/master/distrib/ 29 | https://github.com/nesteruk/CallSharp 30 | CallSharp 31 | ActiveMesa 32 | false 33 | 1 34 | 0.2.0.%2a 35 | false 36 | true 37 | true 38 | 39 | 40 | 268759745171C45051A7D18A70BB4A794A003153 41 | 42 | 43 | CallSharp_TemporaryKey.pfx 44 | 45 | 46 | true 47 | 48 | 49 | false 50 | 51 | 52 | true 53 | ..\..\bin\ 54 | DEBUG;TRACE 55 | full 56 | x64 57 | prompt 58 | MinimumRecommendedRules.ruleset 59 | true 60 | latest 61 | 62 | 63 | ..\bin\ 64 | TRACE 65 | true 66 | pdbonly 67 | x64 68 | prompt 69 | MinimumRecommendedRules.ruleset 70 | true 71 | 72 | 73 | 74 | ..\packages\JetBrains.Annotations.10.1.5\lib\net\JetBrains.Annotations.dll 75 | True 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 4.0 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | MSBuild:Compile 95 | Designer 96 | 97 | 98 | 99 | 100 | True 101 | True 102 | StaticMemberDatabase.tt 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | MSBuild:Compile 117 | Designer 118 | 119 | 120 | App.xaml 121 | Code 122 | 123 | 124 | 125 | 126 | MainWindow.xaml 127 | Code 128 | 129 | 130 | 131 | 132 | 133 | 134 | Code 135 | 136 | 137 | True 138 | True 139 | Resources.resx 140 | 141 | 142 | True 143 | Settings.settings 144 | True 145 | 146 | 147 | ResXFileCodeGenerator 148 | Resources.Designer.cs 149 | 150 | 151 | 152 | SettingsSingleFileGenerator 153 | Settings.Designer.cs 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | False 163 | Microsoft .NET Framework 4.5 %28x86 and x64%29 164 | true 165 | 166 | 167 | False 168 | .NET Framework 3.5 SP1 169 | false 170 | 171 | 172 | 173 | 174 | TextTemplatingFileGenerator 175 | StaticMemberDatabase.cs 176 | 177 | 178 | 179 | 180 | 181 | 182 | 189 | -------------------------------------------------------------------------------- /src/CallSharp/CallSharp.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /src/CallSharp/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Collections.Specialized; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Threading; 9 | 10 | namespace CallSharp 11 | { 12 | public class MyObservableCollection : ObservableCollection 13 | { 14 | public override event NotifyCollectionChangedEventHandler CollectionChanged; 15 | protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 16 | { 17 | NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged; 18 | if (CollectionChanged != null) 19 | foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList()) 20 | { 21 | DispatcherObject dispObj = nh.Target as DispatcherObject; 22 | if (dispObj != null) 23 | { 24 | Dispatcher dispatcher = dispObj.Dispatcher; 25 | if (dispatcher != null && !dispatcher.CheckAccess()) 26 | { 27 | dispatcher.BeginInvoke( 28 | (Action)(() => nh.Invoke(this, 29 | new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))), 30 | DispatcherPriority.DataBind); 31 | continue; 32 | } 33 | } 34 | nh.Invoke(this, e); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CallSharp/Cuda.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace CallSharp 4 | { 5 | /// 6 | /// This file is used to proxy certain calls into CUDA kernels that speed up certain calculations. 7 | /// 8 | public abstract class Cuda 9 | { 10 | [DllImport("CallSharp.Cuda.dll")] 11 | public static extern void foo(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/CallSharp/Db/DynamicMemberDatabase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading; 8 | using JetBrains.Annotations; 9 | 10 | namespace CallSharp 11 | { 12 | [Obsolete("This is far too slow, use StaticMemberDatabase", true)] 13 | public class DynamicMemberDatabase : IMemberDatabase 14 | { 15 | private readonly HashSet staticMethods = new HashSet(); 16 | private readonly HashSet instanceMethods = new HashSet(); 17 | private readonly HashSet constructors = new HashSet(); 18 | private readonly IFragmentationEngine fragEngine = new FragmentationEngine(); 19 | 20 | public DynamicMemberDatabase() 21 | { 22 | // get each loaded assembly 23 | foreach (var ass in AppDomain.CurrentDomain.GetAssemblies()) 24 | { 25 | // we only care about publicly visible types, right? 26 | foreach (var type in ass.ExportedTypes) 27 | { 28 | Trace.WriteLine(type.FullName + " from " + ass.FullName); 29 | var methods = type.GetMethods(); 30 | foreach (var m in methods) 31 | m.AddTo(m.IsStatic ? staticMethods : instanceMethods); 32 | 33 | // we index single-argument constructors only 34 | type.GetConstructors().Where(c => 35 | !c.ContainsGenericParameters // nor this 36 | && c.GetParameters().Length == 1 // the argument type is unconstrained 37 | ).AddTo(constructors); 38 | } 39 | } 40 | } 41 | 42 | 43 | 44 | /// 45 | /// Locates any non-static method of inputType that yields a 46 | /// value that is expressly not of ignoreOutputType. 47 | /// 48 | /// The type on which to search for member functions. 49 | /// Optional return type to avoid including in the results. 50 | /// 51 | /// The reason why ignoreOutputType exists is that when making the primary search, 52 | /// we search explicitly for f:A->B and already have cookies from those searches. We want 53 | /// to avoid performing the search again, so we search for f:A->Z where Z != B. 54 | /// 55 | public IEnumerable FindAnyToOneInstance(Type inputType, Type ignoreThisOutputType) 56 | { 57 | foreach (var method in instanceMethods.AsParallel().Where(m => 58 | m.DeclaringType == inputType && 59 | m.ReturnType != ignoreThisOutputType && 60 | m.ReturnType != typeof(void) 61 | // warn: return value can be of any type 62 | )) 63 | { 64 | var pars = method.GetParameters(); 65 | 66 | if (!method.IsStatic && 67 | (pars.Length == 0 68 | || pars.AllAreOptional() 69 | || pars.IsSingleParamsArgument())) 70 | { 71 | yield return method; 72 | } 73 | } 74 | } 75 | 76 | /// 77 | /// This search ought to locate non-void extension methods available in extraneous types, such as 78 | /// IEnumerable extension methods. 79 | /// 80 | /// 81 | /// 82 | /// 83 | public IEnumerable FindAnyToOneStatic(Type inputType, 84 | Type ignoreThisOutputType) 85 | { 86 | foreach (var method in staticMethods.Where(m => 87 | m.DeclaringType != null 88 | && ( 89 | m.DeclaringType.IsIn(TypeDatabase.CoreTypes) 90 | || 91 | m.DeclaringType.GetInterfaces().Any(i => i.IsGenericType && // no more hack ;) 92 | i.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 93 | ) 94 | && m.ReturnType != ignoreThisOutputType 95 | && m.IsStatic)) 96 | { 97 | var pars = method.GetParameters(); 98 | 99 | // accept just 1 argument of required type 100 | if (pars.Length == 1 && pars[0].ParameterType == inputType) 101 | yield return method; 102 | } 103 | } 104 | 105 | public IEnumerable FindConstructorFor(Type inputType, Type outputType) 106 | { 107 | return constructors.Where(c => 108 | c.DeclaringType == outputType 109 | && c.GetParameters()[0].ParameterType == inputType 110 | ); 111 | } 112 | 113 | /// 114 | /// Locate any non-static method of inputType that takes no parameters and 115 | /// returns a value of outputType. 116 | /// 117 | /// 118 | /// 119 | /// 120 | public IEnumerable FindOneToOneInstance(Type inputType, Type outputType) 121 | { 122 | foreach (var method in instanceMethods.AsParallel().Where(m => 123 | m.DeclaringType == inputType && 124 | m.ReturnType.IsConvertibleTo(outputType))) 125 | { 126 | var pars = method.GetParameters(); 127 | 128 | if (!method.IsStatic && 129 | (pars.Length == 0 130 | || pars.AllAreOptional() 131 | || pars.IsSingleParamsArgument())) 132 | { 133 | yield return method; 134 | } 135 | } 136 | } 137 | 138 | private IEnumerable FindOneToXInstance(Type inputType, Type outputType, 139 | int numberOfNonOptionalArguments) 140 | { 141 | foreach (var method in instanceMethods.AsParallel().Where(m => 142 | !m.IsStatic 143 | && m.DeclaringType == inputType 144 | && m.ReturnType.IsConvertibleTo(outputType))) 145 | { 146 | var pars = method.GetParameters(); 147 | if (pars.Count(p => !p.ProvisionOfThisArgumentIsOptional()) == 148 | numberOfNonOptionalArguments) 149 | { 150 | yield return method; 151 | } 152 | } 153 | } 154 | 155 | public IEnumerable FindOneToThreeInstance(Type inputType, Type outputType) 156 | { 157 | return FindOneToXInstance(inputType, outputType, 2); 158 | } 159 | 160 | /// 161 | /// Locate any non-static method of inputType that takes a single parameter or 162 | /// a params[]. 163 | /// 164 | /// 165 | /// 166 | /// 167 | public IEnumerable FindOneToTwoInstance(Type inputType, Type outputType) 168 | { 169 | return FindOneToXInstance(inputType, outputType, 1); 170 | } 171 | 172 | /// 173 | /// Locates all static methods of any type that is in 174 | /// that takes an argument of inputType and returns a value of outputType. 175 | /// 176 | /// 177 | /// 178 | /// 179 | public IEnumerable FindOneToOneStatic(Type inputType, Type outputType) 180 | { 181 | // search in ALL core types :) 182 | // warning: allowing other types is NOT SAFE because you might call File.Delete or something 183 | foreach (var method in staticMethods.AsParallel().Where(m => 184 | m.ReturnType.IsConvertibleTo(outputType) 185 | && TypeDatabase.CoreTypes.Contains(m.DeclaringType) // a core type 186 | && !m.Name.Equals("Parse") // it throws 187 | )) 188 | { 189 | if (method.Name.Contains("Delete")) 190 | throw new Exception("Just in case!"); 191 | 192 | if (method.ToString().Contains("System.Math") && method.Name.Contains("Sqrt")) 193 | { 194 | Debugger.Break(); 195 | } 196 | 197 | var pars = method.GetParameters(); 198 | 199 | if (method.IsStatic && 200 | pars.Length == 1 && 201 | inputType.IsConvertibleTo(pars[0].ParameterType) 202 | //pars[0].ParameterType == inputType 203 | ) 204 | { 205 | yield return method; 206 | } 207 | } 208 | } 209 | 210 | 211 | 212 | [Pure] 213 | public void FindCandidates(Action visitor, object origin, object input, 214 | object output, int depth, CancellationToken token, string callChain = "input") 215 | { 216 | Trace.WriteLine(callChain); 217 | 218 | // if inputs are completely identical, we have no further work to do 219 | if (input.Equals(output)) 220 | { 221 | visitor(callChain); 222 | return; 223 | } 224 | 225 | // here we try to brute-force conversion of input to output 226 | // if it succeeds, we break as before 227 | object newValue = null; 228 | try 229 | { 230 | newValue = Convert.ChangeType(output, input.GetType()); 231 | } catch (Exception) { } 232 | if (input.Equals(newValue)) 233 | { 234 | visitor(callChain); 235 | return; 236 | } 237 | 238 | bool foundSomething = false; 239 | 240 | // contains all calls that didn't yield the right result 241 | var failCookies = new List(); 242 | 243 | foreach ( 244 | var ctor in FindConstructorFor(input.GetType(), output.GetType())) 245 | { 246 | // construct exactly this type of object 247 | object instance = ctor.Invoke(new[] { input }); 248 | if (instance.Equals(output)) 249 | { 250 | visitor($"new {ctor.ReflectedType.GetFriendlyName()}({callChain})"); 251 | foundSomething = true; 252 | } 253 | } 254 | 255 | foreach (var m in FindOneToOneInstance(input.GetType(), output.GetType())) 256 | { 257 | var cookie = m.InvokeWithNoArgument(input); 258 | if (cookie != null && output.Equals(cookie.ReturnValue)) 259 | { 260 | visitor(cookie.ToString(callChain)); 261 | foundSomething = true; 262 | } 263 | else 264 | { 265 | failCookies.Add(cookie); 266 | } 267 | } 268 | 269 | 270 | foreach (var m in FindOneToOneStatic(input.GetType(), output.GetType())) 271 | { 272 | var cookie = m.InvokeStaticWithSingleArgument(input); 273 | if (output.Equals(cookie?.ReturnValue)) 274 | { 275 | if (cookie != null && !Equals(cookie.ReturnValue, input)) 276 | { 277 | visitor(cookie.ToString(callChain)); 278 | foundSomething = true; 279 | } 280 | } 281 | else 282 | { 283 | failCookies.Add(cookie); 284 | } 285 | } 286 | 287 | // look for single-argument fragmentation 288 | if (!foundSomething) 289 | { 290 | foreach (var m in FindOneToTwoInstance(input.GetType(), output.GetType())) 291 | { 292 | // generate a set of values to invoke on 293 | foreach (var arg in fragEngine.Frag(input, m.GetParameters()[0].ParameterType)) 294 | { 295 | var cookie = m.InvokeWithArguments(input, arg); 296 | if (output.Equals(cookie?.ReturnValue)) 297 | { 298 | if (cookie != null && !Equals(cookie.ReturnValue, input)) 299 | { 300 | visitor(cookie.ToString(callChain)); 301 | foundSomething = true; 302 | } 303 | } 304 | else 305 | { 306 | failCookies.Add(cookie); 307 | } 308 | } 309 | } 310 | } 311 | 312 | // look for two-argument fragmentation; this is costly 313 | if (!foundSomething) 314 | { 315 | foreach (var m in FindOneToThreeInstance(input.GetType(), output.GetType())) 316 | { 317 | // generate a set of first and second arguments 318 | foreach (var arg1 in fragEngine.Frag(input, m.GetParameters()[0].ParameterType)) 319 | foreach (var arg2 in fragEngine.Frag(input, m.GetParameters()[1].ParameterType)) 320 | { 321 | var cookie = m.InvokeWithArguments(input, arg1, arg2); 322 | if (output.Equals(cookie?.ReturnValue)) 323 | { 324 | if (cookie != null && !Equals(cookie.ReturnValue, input)) 325 | { 326 | visitor(cookie.ToString(callChain)); 327 | //foundSomething = true; 328 | } 329 | } 330 | else 331 | { 332 | failCookies.Add(cookie); 333 | } 334 | } 335 | } 336 | } 337 | 338 | Action visitorWithCheck = x => 339 | { 340 | visitor(x); 341 | foundSomething = true; 342 | }; 343 | 344 | // assuming we haven't found things and not in too deep 345 | if (!foundSomething && depth < 2) 346 | { 347 | // if we found nothing of worth, try a chain 348 | foreach (var m in FindAnyToOneInstance(input.GetType(), output.GetType())) 349 | { 350 | // get the cookie for this invocation 351 | var cookie = m.InvokeWithNoArgument(input); 352 | 353 | // pass it on 354 | if (cookie != null && !Equals(cookie.ReturnValue, input)) 355 | { 356 | FindCandidates(visitorWithCheck, origin, cookie.ReturnValue, output, depth + 1, token, cookie.ToString(callChain)); 357 | } 358 | } 359 | 360 | // could be a static call of some arbitrary type 361 | foreach ( 362 | var m in FindAnyToOneStatic(input.GetType(), output.GetType())) 363 | { 364 | var cookie = m.InvokeStaticWithSingleArgument(input); 365 | if (cookie != null && !Equals(cookie.ReturnValue, input)) 366 | { 367 | FindCandidates(visitorWithCheck, origin, cookie.ReturnValue, output, depth + 1, token, cookie.ToString(callChain)); 368 | } 369 | } 370 | 371 | // we already have call results for some invocation chains, why not try those? 372 | foreach (var fc in failCookies.Where(fc => fc != null && !Equals(fc.ReturnValue, input))) 373 | { 374 | FindCandidates(visitorWithCheck, origin, fc.ReturnValue, output, depth + 1, token, fc.ToString(callChain)); 375 | } 376 | } 377 | } 378 | } 379 | } -------------------------------------------------------------------------------- /src/CallSharp/Db/IMemberDatabase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Threading; 5 | 6 | namespace CallSharp 7 | { 8 | public interface IMemberDatabase 9 | { 10 | void FindCandidates(Action visitor, object origin, object input, 11 | object output, int depth, CancellationToken token, string callChain = "input"); 12 | } 13 | } -------------------------------------------------------------------------------- /src/CallSharp/Empty.cs: -------------------------------------------------------------------------------- 1 | namespace CallSharp 2 | { 3 | public static class Empty 4 | { 5 | public static object[] ObjectArray = new object[0]; 6 | } 7 | } -------------------------------------------------------------------------------- /src/CallSharp/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace CallSharp 6 | { 7 | /// 8 | /// Provides a set of static methods for querying objects that implement IEnumerable<T>. 9 | /// 10 | /// 11 | /// These are extensions to System.Linq.Enuemrable and declared and implemented in the same fashion. 12 | /// 13 | public static class EnumerableExtensions 14 | { 15 | // This provides a useful extension-like method to find the index of and item from IEnumerable 16 | // This was based off of the Enumerable.Count extension method. 17 | /// 18 | /// Returns the index of an item in a sequence. 19 | /// 20 | /// The type of the elements of source. 21 | /// A sequence containing elements. 22 | /// The item to locate. 23 | /// The index of the entry if it was found in the sequence; otherwise, -1. 24 | public static int IndexOf(this IEnumerable source, TSource item) 25 | { 26 | return IndexOf(source, item, null); 27 | } 28 | 29 | // This provides a useful extension-like method to find the index of and item from IEnumerable 30 | // This was based off of the Enumerable.Count extension method. 31 | /// 32 | /// Returns the index of an item in a sequence. 33 | /// 34 | /// The type of the elements of source. 35 | /// A sequence containing elements. 36 | /// The item to locate. 37 | /// The item equality comparer to use. Pass null to use the default comparer. 38 | /// The index of the entry if it was found in the sequence; otherwise, -1. 39 | public static int IndexOf(this IEnumerable source, TSource item, 40 | IEqualityComparer itemComparer) 41 | { 42 | if (source == null) 43 | { 44 | throw new ArgumentNullException(nameof(source)); 45 | } 46 | 47 | var listOfT = source as IList; 48 | if (listOfT != null) 49 | { 50 | return listOfT.IndexOf(item); 51 | } 52 | 53 | var list = source as IList; 54 | if (list != null) 55 | { 56 | return list.IndexOf(item); 57 | } 58 | 59 | if (itemComparer == null) 60 | { 61 | itemComparer = EqualityComparer.Default; 62 | } 63 | 64 | int i = 0; 65 | foreach (TSource possibleItem in source) 66 | { 67 | if (itemComparer.Equals(item, possibleItem)) 68 | { 69 | return i; 70 | } 71 | i++; 72 | } 73 | return -1; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/CallSharp/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace CallSharp 4 | { 5 | using System; 6 | using System.CodeDom; 7 | using System.CodeDom.Compiler; 8 | using System.Collections.Generic; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Reflection; 12 | using System.Runtime.CompilerServices; 13 | using JetBrains.Annotations; 14 | 15 | public static class ExtensionMethods 16 | { 17 | public static string ToLiteral(this object o) 18 | { 19 | if (o is Array) 20 | { 21 | var a = o as Array; 22 | var sb = new StringBuilder(); 23 | sb.Append("new [] { "); 24 | for (int i = 0; i < a.Length; i++) 25 | { 26 | sb.Append(a.GetValue(i).ToLiteral()); 27 | if (i + 1 != a.Length) 28 | sb.Append(", "); 29 | } 30 | sb.Append(" }"); 31 | return sb.ToString(); 32 | } 33 | if (o is string) 34 | { 35 | if ((o as string).Length == 0) 36 | return "string.Empty"; 37 | return $"\"{o}\""; 38 | } 39 | if (o is char) 40 | { 41 | return $"'{o}'"; 42 | } 43 | return o.ToString(); 44 | } 45 | 46 | public static string RemoveMarkers(this string s) 47 | { 48 | return s.Replace(MagicTextBox.SpaceChar, ' '); 49 | } 50 | 51 | public static bool AllAreOptional(this ParameterInfo[] ps) 52 | { 53 | return ps.All(p => p.IsOptional); 54 | } 55 | 56 | public static bool IsParams(this ParameterInfo pi) 57 | { 58 | return pi.GetCustomAttribute() != null; 59 | } 60 | 61 | public static bool ProvisionOfThisArgumentIsOptional(this ParameterInfo pi) 62 | { 63 | return pi.IsParams() || pi.HasDefaultValue; 64 | } 65 | 66 | [CanBeNull] 67 | public static MethodCallCookie InvokeStaticWithSingleArgument(this MethodInfo mi, 68 | T arg) 69 | { 70 | MethodCallCookie result = null; 71 | try 72 | { 73 | var args = new object[] { arg }; 74 | var retval = mi.Invoke(null /*static*/, args); 75 | result = new MethodCallCookie(mi, args, retval); 76 | } 77 | catch 78 | { 79 | // we cannot reasonably catch this 80 | } 81 | return result; 82 | } 83 | 84 | public static IEnumerable Combinations(this T[] values, int k) 85 | { 86 | if (k < 0 || values.Length < k) 87 | yield break; // invalid parameters, no combinations possible 88 | 89 | // generate the initial combination indices 90 | var combIndices = new int[k]; 91 | for (var i = 0; i < k; i++) 92 | { 93 | combIndices[i] = i; 94 | } 95 | 96 | while (true) 97 | { 98 | // return next combination 99 | var combination = new T[k]; 100 | for (var i = 0; i < k; i++) 101 | { 102 | combination[i] = values[combIndices[i]]; 103 | } 104 | yield return combination; 105 | 106 | // find first index to update 107 | var indexToUpdate = k - 1; 108 | while (indexToUpdate >= 0 && combIndices[indexToUpdate] >= values.Length - k + indexToUpdate) 109 | { 110 | indexToUpdate--; 111 | } 112 | 113 | if (indexToUpdate < 0) 114 | yield break; // done 115 | 116 | // update combination indices 117 | for (var combIndex = combIndices[indexToUpdate] + 1; indexToUpdate < k; indexToUpdate++, combIndex++) 118 | { 119 | combIndices[indexToUpdate] = combIndex; 120 | } 121 | } 122 | } 123 | 124 | [CanBeNull] 125 | public static MethodCallCookie InvokeWithArguments(this MethodInfo mi, object self, 126 | params object[] args) 127 | { 128 | MethodCallCookie result = null; 129 | try 130 | { 131 | var retval = mi.Invoke(self, args); 132 | result = new MethodCallCookie(mi, args, retval); 133 | } 134 | catch 135 | { 136 | // we cannot reasonably catch this 137 | } 138 | return result; 139 | } 140 | 141 | [CanBeNull] 142 | public static MethodCallCookie InvokeWithNoArgument(this MethodInfo mi, T subject) 143 | { 144 | var pars = mi.GetParameters(); 145 | MethodCallCookie result = null; 146 | try 147 | { 148 | if (pars.IsSingleParamsArgument()) 149 | { 150 | var args = new[] 151 | { 152 | Activator.CreateInstance(pars[0].ParameterType.UnderlyingSystemType, 0) 153 | }; 154 | var retval = mi.Invoke(subject, args); 155 | result = new MethodCallCookie(mi, args, retval); 156 | } 157 | else 158 | { 159 | var retval = mi.Invoke(subject, Empty.ObjectArray); 160 | result = new MethodCallCookie(mi, Empty.ObjectArray, retval); 161 | } 162 | } 163 | catch 164 | { 165 | } 166 | return result; 167 | } 168 | 169 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 170 | public static bool IsIn(this T obj, IEnumerable collection) 171 | { 172 | return collection.Contains(obj); 173 | } 174 | 175 | public static bool IsSingleParamsArgument(this ParameterInfo[] ps) 176 | { 177 | return ps.Length == 1 && ps[0].IsParams(); 178 | } 179 | 180 | public static IList InferTypes(this string text) 181 | { 182 | var result = new List(); 183 | 184 | foreach (var m in TypeDatabase.ParseableTypesDict.Values) 185 | { 186 | // see http://stackoverflow.com/questions/569249/methodinfo-invoke-with-out-parameter 187 | object[] pars = { text, null }; 188 | bool ok = (bool) m.Invoke(null, pars); 189 | if (ok) 190 | { 191 | result.Add(pars[1]); 192 | } 193 | } 194 | 195 | //// try to decompose and see if it makes sense 196 | //var commaSeparated = text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 197 | //if (commaSeparated.Length > 1) 198 | //{ 199 | // // does every separated part parse under this model 200 | // foreach (var type in TypeDatabase.ParseableTypes) 201 | // { 202 | // foreach (var m in type.GetMethods().Where( 203 | // x => x.Name.Equals("TryParse") 204 | // && x.GetParameters().Length == 2)) 205 | // { 206 | // // see http://stackoverflow.com/questions/569249/methodinfo-invoke-with-out-parameter 207 | 208 | // // parse on every argument 209 | // var ok = commaSeparated.Select(part => (bool) m.Invoke(null, 210 | // new object[] {part, null})); 211 | 212 | // if (ok.All(x=>x)) 213 | // { 214 | // //result.Add(pars[1]); 215 | // result.Add(typeof(List<>).MakeGenericType(type)); 216 | // } 217 | // } 218 | // } 219 | //} 220 | 221 | return result; 222 | } 223 | 224 | /// Adds a single element to the end of an IEnumerable. 225 | /// Type of enumerable to return. 226 | /// IEnumerable containing all the input elements, followed by the 227 | /// specified additional element. 228 | public static IEnumerable Append(this IEnumerable source, T element) 229 | { 230 | if (source == null) 231 | throw new ArgumentNullException(nameof(source)); 232 | return concatIterator(element, source, false); 233 | } 234 | 235 | /// Adds a single element to the start of an IEnumerable. 236 | /// Type of enumerable to return. 237 | /// IEnumerable containing the specified additional element, followed by 238 | /// all the input elements. 239 | public static IEnumerable Prepend(this IEnumerable tail, T head) 240 | { 241 | if (tail == null) 242 | throw new ArgumentNullException(nameof(tail)); 243 | return concatIterator(head, tail, true); 244 | } 245 | 246 | private static IEnumerable concatIterator(T extraElement, 247 | IEnumerable source, bool insertAtStart) 248 | { 249 | if (insertAtStart) 250 | yield return extraElement; 251 | foreach (var e in source) 252 | yield return e; 253 | if (!insertAtStart) 254 | yield return extraElement; 255 | } 256 | 257 | public static string GetFriendlyName(this Type type) 258 | { 259 | var codeDomProvider = CodeDomProvider.CreateProvider("C#"); 260 | var typeReferenceExpression = 261 | new CodeTypeReferenceExpression(new CodeTypeReference( 262 | type.Name.Contains("RuntimeType") ? type.UnderlyingSystemType : type 263 | )); 264 | using (var writer = new StringWriter()) 265 | { 266 | codeDomProvider.GenerateCodeFromExpression(typeReferenceExpression, writer, 267 | new CodeGeneratorOptions()); 268 | return writer.GetStringBuilder().Replace("System.", string.Empty).ToString(); 269 | } 270 | } 271 | 272 | static readonly Dictionary> conversionMap = new Dictionary 273 | > 274 | { 275 | { 276 | typeof(decimal), new HashSet 277 | { 278 | typeof(sbyte), 279 | typeof(byte), 280 | typeof(short), 281 | typeof(ushort), 282 | typeof(int), 283 | typeof(uint), 284 | typeof(long), 285 | typeof(ulong), 286 | typeof(char) 287 | } 288 | }, 289 | { 290 | typeof(double), new HashSet 291 | { 292 | typeof(sbyte), 293 | typeof(byte), 294 | typeof(short), 295 | typeof(ushort), 296 | typeof(int), 297 | typeof(uint), 298 | typeof(long), 299 | typeof(ulong), 300 | typeof(char), 301 | typeof(float) 302 | } 303 | }, 304 | { 305 | typeof(float), new HashSet 306 | { 307 | typeof(sbyte), 308 | typeof(byte), 309 | typeof(short), 310 | typeof(ushort), 311 | typeof(int), 312 | typeof(uint), 313 | typeof(long), 314 | typeof(ulong), 315 | typeof(char), 316 | typeof(float) 317 | } 318 | }, 319 | { 320 | typeof(ulong), 321 | new HashSet {typeof(byte), typeof(ushort), typeof(uint), typeof(char)} 322 | }, 323 | { 324 | typeof(long), new HashSet 325 | { 326 | typeof(sbyte), 327 | typeof(byte), 328 | typeof(short), 329 | typeof(ushort), 330 | typeof(int), 331 | typeof(uint), 332 | typeof(char) 333 | } 334 | }, 335 | {typeof(uint), new HashSet {typeof(byte), typeof(ushort), typeof(char)}}, 336 | { 337 | typeof(int), 338 | new HashSet 339 | { 340 | typeof(sbyte), 341 | typeof(byte), 342 | typeof(short), 343 | typeof(ushort), 344 | typeof(char) 345 | } 346 | }, 347 | {typeof(ushort), new HashSet {typeof(byte), typeof(char)}}, 348 | {typeof(short), new HashSet {typeof(byte)}} 349 | }; 350 | 351 | public static void AddTo(this T item, ICollection coll) 352 | { 353 | coll.Add(item); 354 | } 355 | 356 | public static void AddTo(this IEnumerable items, ICollection coll) 357 | { 358 | foreach (var item in items) 359 | { 360 | coll.Add(item); 361 | } 362 | } 363 | 364 | public static bool IsConvertibleTo(this Type from, Type to) 365 | { 366 | return from == to || to.IsAssignableFrom(from) || 367 | (conversionMap.ContainsKey(to) && conversionMap[to].Contains(from)); 368 | 369 | //if (from == to || to.IsAssignableFrom(from)) 370 | //{ 371 | // return true; 372 | //} 373 | //if (conversionMap.ContainsKey(to) && conversionMap[to].Contains(from)) 374 | //{ 375 | // return true; 376 | //} 377 | //bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static) 378 | // .Any( 379 | // m => m.ReturnType == to && 380 | // (m.Name == "op_Implicit" || 381 | // m.Name == "op_Explicit") 382 | // ); 383 | //return castable; 384 | } 385 | } 386 | } -------------------------------------------------------------------------------- /src/CallSharp/Fragmentation/FragmentationEngine.cs: -------------------------------------------------------------------------------- 1 | namespace CallSharp 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Contains extension methods that fragment a literal into its constituent 9 | /// parts for exploratory call chains. For example, 123 can be fragged into 10 | /// 1, 2, 3, 12, 23, 13, 100 and 20. 11 | /// 12 | public class FragmentationEngine : IFragmentationEngine 13 | { 14 | /// 15 | /// Finds all constituent parts of a particular object. 16 | /// 17 | /// The object to fragment. 18 | /// The type of each of the parts after fragmentation. 19 | /// 20 | public IEnumerable Frag(object source, Type partType) 21 | { 22 | var s = source as string; 23 | if (s != null) 24 | { 25 | if (string.IsNullOrEmpty(s)) 26 | yield break; // we have nothing to do here 27 | 28 | if (partType == typeof(string)) 29 | { 30 | foreach (var part in FragToString(s)) 31 | yield return part; 32 | foreach (var part in FragToInt(s)) 33 | yield return part; 34 | } 35 | else if (partType == typeof(char)) 36 | { 37 | foreach (var c in s.ToCharArray()) 38 | yield return c; 39 | } 40 | else if (partType == typeof(char[])) 41 | { 42 | // every combination of characters in a string 43 | HashSet allChars = new HashSet(s.ToCharArray()); 44 | for (int i = 1; i < allChars.Count; ++i) 45 | foreach (var x in PermuteUtils.Permute(allChars, i)) 46 | yield return x.ToArray(); 47 | } 48 | else if (partType == typeof(int)) 49 | { 50 | for (int i = 0; i < s.Length; ++i) 51 | yield return i; 52 | } 53 | } 54 | 55 | } 56 | 57 | private IEnumerable FragToInt(string text) 58 | { 59 | return Enumerable.Range(0, text.Length); 60 | } 61 | 62 | /// 63 | /// Every substring in a string. In-order only. 64 | /// 65 | /// 66 | /// 67 | private IEnumerable FragToString(string text) 68 | { 69 | // empty string definitely included 70 | yield return string.Empty; 71 | 72 | var elements = text.ToCharArray(); 73 | for (int i = 1; i <= text.Length; ++i) 74 | { 75 | var picks = elements.Combinations(i); 76 | foreach (var pick in picks) 77 | yield return new string(pick); 78 | } 79 | } 80 | 81 | } 82 | } -------------------------------------------------------------------------------- /src/CallSharp/Fragmentation/IFragmentationEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CallSharp 5 | { 6 | public interface IFragmentationEngine 7 | { 8 | /// 9 | /// Finds all constituent parts of 10 | /// 11 | /// The object to fragment. 12 | /// The type of each of the parts after fragmentation. 13 | /// 14 | IEnumerable Frag(object source, Type partType); 15 | } 16 | } -------------------------------------------------------------------------------- /src/CallSharp/Fragmentation/NullFragmentationEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CallSharp 5 | { 6 | /// 7 | /// When you're too scared to search through combinations of strings or characters. 8 | /// 9 | class NullFragmentationEngine : IFragmentationEngine 10 | { 11 | public IEnumerable Frag(object source, Type partType) 12 | { 13 | yield break; // nothing here! 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/CallSharp/MagicTextBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | 4 | namespace CallSharp 5 | { 6 | /// 7 | /// This is a text box similar to an ordinary text box except it 8 | /// displays space as ⎵. 9 | /// 10 | public class MagicTextBox : TextBox 11 | { 12 | public const char SpaceChar = '⎵'; 13 | 14 | static MagicTextBox() 15 | { 16 | TextProperty.OverrideMetadata(typeof(MagicTextBox), 17 | new FrameworkPropertyMetadata("", TextProperty.DefaultMetadata.PropertyChangedCallback, 18 | textValueChanged)); 19 | } 20 | 21 | private static object textValueChanged(DependencyObject d, object basevalue) 22 | { 23 | return basevalue.ToString().Replace(' ', SpaceChar); 24 | } 25 | 26 | public string ActualText => Text.Replace(SpaceChar, ' '); 27 | } 28 | } -------------------------------------------------------------------------------- /src/CallSharp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | PragmataPro Mono,Consolas,Courier New 13 | 10 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 46 | 47 | Input treated as a 48 | scalar value 49 | sequence 50 | 51 | 52 | 53 | of type 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | 67 | 70 | Output treated as: 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 93 | 95 | Scale window 96 | 102 | 103 | 104 | 105 | 106 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/CallSharp/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Diagnostics; 3 | using System.Text; 4 | using System.Threading; 5 | 6 | namespace CallSharp 7 | { 8 | using System; 9 | using System.Linq; 10 | using System.Reflection; 11 | using System.Threading.Tasks; 12 | using System.Windows; 13 | using System.Windows.Documents; 14 | 15 | public partial class MainWindow : Window 16 | { 17 | private readonly IMemberDatabase dynamicMemberDatabase = new StaticMemberDatabase(); 18 | private static object[] noArgs = { }; 19 | 20 | private const string defaultPrimaryRunText = "Search!"; 21 | private const string defaultSecondaryRunText = "may take a long time"; 22 | 23 | public string PrimaryRunLabel 24 | { 25 | get { return (string)GetValue(PrimaryRunLabelProperty); } 26 | set { SetValue(PrimaryRunLabelProperty, value); } 27 | } 28 | public static readonly DependencyProperty PrimaryRunLabelProperty = 29 | DependencyProperty.Register("PrimaryRunLabel", typeof(string), typeof(MainWindow), new PropertyMetadata(defaultPrimaryRunText)); 30 | 31 | private bool busy = false; 32 | private CancellationTokenSource cts; 33 | 34 | public string SecondaryRunLabel 35 | { 36 | get { return (string)GetValue(SecondaryRunLabelProperty); } 37 | set { SetValue(SecondaryRunLabelProperty, value); } 38 | } 39 | 40 | public static readonly DependencyProperty SecondaryRunLabelProperty = 41 | DependencyProperty.Register("SecondaryRunLabel", typeof(string), typeof(MainWindow), new PropertyMetadata(defaultSecondaryRunText)); 42 | 43 | 44 | 45 | public ObservableHashSet Candidates 46 | { 47 | get => (ObservableHashSet)GetValue(CandidatesProperty); 48 | set => SetValue(CandidatesProperty, value); 49 | } 50 | 51 | public static readonly DependencyProperty CandidatesProperty = 52 | DependencyProperty.Register("Candidates", typeof(ObservableHashSet), typeof(MainWindow), 53 | new PropertyMetadata(new ObservableHashSet())); 54 | 55 | 56 | 57 | public ObservableCollection Log 58 | { 59 | get { return (ObservableCollection)GetValue(LogProperty); } 60 | set { SetValue(LogProperty, value); } 61 | } 62 | 63 | public static readonly DependencyProperty LogProperty = 64 | DependencyProperty.Register("Log", typeof(ObservableCollection), typeof(MainWindow), new PropertyMetadata(new ObservableCollection())); 65 | 66 | 67 | 68 | 69 | public string InputText 70 | { 71 | get => (string) GetValue(InputTextProperty); 72 | set => SetValue(InputTextProperty, value); 73 | } 74 | 75 | public static readonly DependencyProperty InputTextProperty = 76 | DependencyProperty.Register("InputText", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, InputChanged)); 77 | 78 | public Type InputType 79 | { 80 | get => (Type)GetValue(InputTypeProperty); 81 | set => SetValue(InputTypeProperty, value); 82 | } 83 | 84 | public static readonly DependencyProperty InputTypeProperty = 85 | DependencyProperty.Register("InputType", typeof(Type), typeof(MainWindow), new PropertyMetadata(typeof(string))); 86 | 87 | public Type OutputType 88 | { 89 | get => (Type)GetValue(OutputTypeProperty); 90 | set => SetValue(OutputTypeProperty, value); 91 | } 92 | 93 | public static readonly DependencyProperty OutputTypeProperty = 94 | DependencyProperty.Register("OutputType", typeof(Type), typeof(MainWindow), new PropertyMetadata(typeof(string))); 95 | 96 | 97 | 98 | public bool? ScaleWindow 99 | { 100 | get => (bool?)GetValue(ScaleWindowProperty); 101 | set => SetValue(ScaleWindowProperty, value); 102 | } 103 | 104 | // Using a DependencyProperty as the backing store for ScaleWindow. This enables animation, styling, binding, etc... 105 | public static readonly DependencyProperty ScaleWindowProperty = 106 | DependencyProperty.Register("ScaleWindow", typeof(bool?), typeof(MainWindow), new PropertyMetadata(false)); 107 | 108 | private object parsedInputValue = string.Empty, parsedOutputValue = string.Empty; 109 | 110 | private static void InputChanged(DependencyObject d, DependencyPropertyChangedEventArgs _) 111 | { 112 | InputChanged(d); 113 | } 114 | 115 | private static void InputChanged(DependencyObject d) 116 | { 117 | var self = (MainWindow) d; 118 | 119 | var parsedValues = self.InputText.RemoveMarkers().InferTypes(); 120 | parsedValues.Add(self.InputText.RemoveMarkers()); 121 | if (parsedValues.Any()) 122 | { 123 | self.parsedInputValue = parsedValues[0]; 124 | self.InputType = self.parsedInputValue.GetType(); 125 | 126 | self.AlternateInputValues.Inlines.Clear(); 127 | foreach (var i in parsedValues) 128 | { 129 | if (self.InputType != i.GetType()) 130 | { 131 | var h = new Hyperlink(); 132 | h.Inlines.Add(i.GetType().GetFriendlyName()); 133 | h.Tag = i; 134 | h.Click += (sender, args) => 135 | { 136 | var me = (Hyperlink) sender; 137 | // cache the current type 138 | Type currentType = self.InputType; 139 | // set the new type 140 | self.InputType = me.Tag.GetType(); 141 | self.parsedInputValue = me.Tag; 142 | // restore my type and name 143 | me.Inlines.Clear(); 144 | var friendlyName = currentType.GetFriendlyName(); 145 | if (friendlyName == "RuntimeType") 146 | Debugger.Break(); 147 | me.Inlines.Add(friendlyName); 148 | me.Tag = currentType; 149 | }; 150 | Span s = new Span(h); 151 | s.Inlines.Add(" "); 152 | self.AlternateInputValues.Inlines.Add(s); 153 | } 154 | } 155 | } 156 | } 157 | 158 | public string OutputText 159 | { 160 | get => (string)GetValue(OutputTextProperty); 161 | set => SetValue(OutputTextProperty, value); 162 | } 163 | 164 | public static readonly DependencyProperty OutputTextProperty = 165 | DependencyProperty.Register("OutputText", 166 | typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, OutputChanged)); 167 | 168 | 169 | 170 | public string Separator 171 | { 172 | get { return (string)GetValue(SeparatorProperty); } 173 | set { SetValue(SeparatorProperty, value); } 174 | } 175 | 176 | // Using a DependencyProperty as the backing store for Separator. This enables animation, styling, binding, etc... 177 | public static readonly DependencyProperty SeparatorProperty = 178 | DependencyProperty.Register("Separator", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty, SeparatorChanged)); 179 | 180 | private static void SeparatorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 181 | { 182 | // when the separator is changed, we need to reevaluate both input and output 183 | var window = d as MainWindow; 184 | InputChanged(d); 185 | OutputChanged(d, window.InputText); 186 | } 187 | 188 | private static void OutputChanged(DependencyObject d, 189 | DependencyPropertyChangedEventArgs e) 190 | { 191 | OutputChanged(d, (string)e.NewValue); 192 | } 193 | 194 | 195 | private static void OutputChanged(DependencyObject d, string parsed) 196 | { 197 | var self = (MainWindow) d; 198 | 199 | var parsedValues = parsed.InferTypes(); // scalar types 200 | parsedValues.Add(parsed); 201 | if (parsedValues.Any()) 202 | { 203 | self.parsedOutputValue = parsedValues[0]; 204 | self.OutputType = self.parsedOutputValue.GetType(); 205 | 206 | self.AlternateOutputValues.Inlines.Clear(); 207 | foreach (var i in parsedValues) 208 | { 209 | if (self.OutputType != i.GetType()) 210 | { 211 | Hyperlink h = new Hyperlink(); 212 | h.Inlines.Add(i.GetType().GetFriendlyName()); 213 | h.Tag = i; 214 | h.Click += (sender, args) => 215 | { 216 | var me = (Hyperlink)sender; 217 | // cache the current type 218 | Type currentType = self.InputType; 219 | // set the new type 220 | self.OutputType = me.Tag.GetType(); 221 | self.parsedOutputValue = me.Tag; 222 | // restore my type and name 223 | me.Inlines.Clear(); 224 | me.Inlines.Add(currentType.GetFriendlyName()); 225 | me.Tag = currentType; 226 | }; 227 | Span s = new Span(h); 228 | s.Inlines.Add(" "); 229 | self.AlternateOutputValues.Inlines.Add(s); 230 | } 231 | } 232 | } 233 | } 234 | 235 | public MainWindow() 236 | { 237 | InitializeComponent(); 238 | 239 | Title += " v" + Assembly.GetEntryAssembly().GetName().Version.ToString(3); 240 | } 241 | 242 | private void BtnSearch_OnClick(object sender, RoutedEventArgs e) 243 | { 244 | if (busy) 245 | { 246 | LogInfo("Cancellation requested. Should not have anything here."); 247 | cts.Cancel(); 248 | busy = false; 249 | } 250 | else 251 | { 252 | busy = true; 253 | // do the search 254 | Candidates.Clear(); 255 | Log.Clear(); 256 | cts = new CancellationTokenSource(); 257 | 258 | PrimaryRunLabel = "Cancel"; 259 | SecondaryRunLabel = "search in progress"; 260 | 261 | Task.Factory.StartNew(() => 262 | dynamicMemberDatabase.FindCandidates( 263 | x => Dispatcher.Invoke(() => 264 | { 265 | LogInfo("Found a candidate: " + x); 266 | Candidates.Add(x); 267 | }), 268 | parsedInputValue, parsedInputValue, parsedOutputValue, 0, cts.Token), 269 | cts.Token) 270 | .ContinueWith(t => 271 | { 272 | PrimaryRunLabel = defaultPrimaryRunText; 273 | SecondaryRunLabel = "search " + (t.IsCanceled ? "canceled" : "completed"); 274 | }, TaskScheduler.FromCurrentSynchronizationContext()); 275 | } 276 | } 277 | 278 | private void LogInfo(string msg) 279 | { 280 | Log.Add($"{DateTime.Now.ToLongTimeString()}: {msg}"); 281 | } 282 | 283 | private void BtnCopy_OnClick(object sender, RoutedEventArgs e) 284 | { 285 | if (LbCandidates.SelectedIndex >= 0) 286 | { 287 | Clipboard.SetText(LbCandidates.SelectedItem.ToString()); 288 | TbInfo.Text = "Text copied to clipboard."; 289 | } 290 | } 291 | 292 | private void ToggleButton_OnChecked(object sender, RoutedEventArgs e) 293 | { 294 | ScaleWindow = CbScaleWindow.IsChecked; 295 | } 296 | 297 | private void BtnCopyAllCandidates_OnClick(object sender, RoutedEventArgs e) 298 | { 299 | var sb = new StringBuilder(); 300 | foreach (var c in LbCandidates.Items) 301 | { 302 | sb.AppendLine(c.ToString()); 303 | } 304 | Clipboard.SetText(sb.ToString()); 305 | } 306 | } 307 | } -------------------------------------------------------------------------------- /src/CallSharp/MethodCallCookie.cs: -------------------------------------------------------------------------------- 1 | namespace CallSharp 2 | { 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | 8 | /// 9 | /// This class contains all the information about an attempt to call 10 | /// a particular function on an input object. It contains information 11 | /// about the function called, the arguments that were applied and 12 | /// the resulting return value. 13 | /// 14 | public class MethodCallCookie 15 | { 16 | public MethodInfo MethodCalled; 17 | public object[] Arguments; 18 | public object ReturnValue; 19 | 20 | public MethodCallCookie(MethodInfo methodCalled, object[] arguments, object returnValue) 21 | { 22 | MethodCalled = methodCalled; 23 | Arguments = arguments; 24 | ReturnValue = returnValue; 25 | } 26 | 27 | /// 28 | /// The type of the return value. 29 | /// 30 | public Type ReturnType => ReturnValue.GetType(); 31 | 32 | public override string ToString() 33 | { 34 | return "x"; 35 | } 36 | 37 | /// 38 | /// Renders the function call on subject. The rendering is different depending 39 | /// on whether or not the function is static. 40 | /// 41 | /// 42 | /// 43 | public string ToString(string subject) 44 | { 45 | var sb = new StringBuilder(); 46 | var methodParams = MethodCalled.GetParameters(); 47 | 48 | // we either called it on a member . or on static X. 49 | if (MethodCalled.IsStatic) 50 | sb.Append(MethodCalled.DeclaringType.GetFriendlyName()); 51 | else 52 | sb.Append(subject); 53 | sb.Append("."); 54 | 55 | if (MethodCalled.Name.StartsWith("get_")) 56 | { 57 | // just a property 58 | sb.Append(MethodCalled.Name.Substring(4)); 59 | } 60 | else 61 | { 62 | sb.Append(MethodCalled.Name).Append("("); 63 | 64 | int start = MethodCalled.IsStatic ? 1 : 0; 65 | for (var i = start; i < Arguments.Length; i++) 66 | { 67 | var arg = Arguments[i]; 68 | bool isParams = methodParams[i].IsParams(); 69 | 70 | // caveat: calling a params[] really passes in a single 71 | // 0-sized array :( need special handling 72 | if (arg is Array arr && arr.Length == 0) 73 | break; 74 | 75 | // todo: literalize argument into code 76 | if (arg is string) 77 | { 78 | string s = (string) arg; 79 | if (s.Length == 0) 80 | sb.Append("string.Empty"); 81 | else 82 | sb.AppendFormat("\"{0}\"", arg); 83 | } 84 | else if (arg is char) 85 | { 86 | sb.AppendFormat("\'{0}'", arg); 87 | } 88 | else if (arg is char[]) 89 | { 90 | if (!isParams) 91 | sb.Append("new char[]{"); 92 | 93 | sb.Append(string.Join(",", ((char[]) arg).Select(c => "'" + c + "'"))); 94 | 95 | if (!isParams) 96 | sb.Append("}"); 97 | } 98 | else 99 | { 100 | sb.Append(arg); 101 | } 102 | 103 | if (i + 1 != Arguments.Length) 104 | sb.Append(", "); 105 | } 106 | 107 | // on the other hand, a static call has NO arguments, so... 108 | if (MethodCalled.IsStatic) 109 | sb.Append(subject); 110 | 111 | sb.Append(")"); 112 | } 113 | return sb.ToString(); 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /src/CallSharp/ObservableHashSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Collections.Specialized; 5 | using System.ComponentModel; 6 | using System.Diagnostics.CodeAnalysis; 7 | using System.Linq; 8 | 9 | namespace CallSharp 10 | { 11 | /// 12 | /// Represents an observable set of values. 13 | /// 14 | /// The type of elements in the hash set. 15 | public sealed class ObservableHashSet : ISet, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable 16 | { 17 | private SimpleMonitor monitor = new SimpleMonitor(); 18 | private HashSet hashSet; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | public ObservableHashSet() 24 | { 25 | hashSet = new HashSet(); 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The collection whose elements are copied to the new set. 32 | public ObservableHashSet(IEnumerable collection) 33 | { 34 | hashSet = new HashSet(collection); 35 | } 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | /// The IEqualityComparer<T> implementation to use when comparing values in the set, or null to use the default EqualityComparer<T> implementation for the set type. 41 | public ObservableHashSet(IEqualityComparer comparer) 42 | { 43 | hashSet = new HashSet(comparer); 44 | } 45 | 46 | /// 47 | /// Initializes a new instance of the class. 48 | /// 49 | /// The collection whose elements are copied to the new set. 50 | /// The IEqualityComparer<T> implementation to use when comparing values in the set, or null to use the default EqualityComparer<T> implementation for the set type. 51 | public ObservableHashSet(IEnumerable collection, IEqualityComparer comparer) 52 | { 53 | hashSet = new HashSet(collection, comparer); 54 | } 55 | 56 | /// 57 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 58 | /// 59 | public void Dispose() 60 | { 61 | if (monitor != null) 62 | { 63 | monitor.Dispose(); 64 | monitor = null; 65 | } 66 | } 67 | 68 | #region Properties 69 | 70 | /// 71 | /// The property names used with INotifyPropertyChanged. 72 | /// 73 | [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "A container for constants used with INotifyPropertyChanged.")] 74 | public static class PropertyNames 75 | { 76 | public const string Count = "Count"; 77 | public const string IsReadOnly = "IsReadOnly"; 78 | } 79 | 80 | 81 | /// 82 | /// Gets the IEqualityComparer<T> object that is used to determine equality for the values in the set. 83 | /// 84 | public IEqualityComparer Comparer => hashSet.Comparer; 85 | 86 | /// 87 | /// Gets the number of elements contained in the . 88 | /// 89 | /// 90 | /// The number of elements contained in the . 91 | /// 92 | public int Count => hashSet.Count; 93 | 94 | /// 95 | /// Gets a value indicating whether the is read-only. 96 | /// 97 | /// true if the is read-only; otherwise, false. 98 | /// 99 | bool ICollection.IsReadOnly => ((ICollection)hashSet).IsReadOnly; 100 | 101 | #endregion 102 | 103 | #region Events 104 | 105 | /// 106 | /// Raised when the collection changes. 107 | /// 108 | public event NotifyCollectionChangedEventHandler CollectionChanged; 109 | 110 | private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) 111 | { 112 | if (CollectionChanged != null) 113 | { 114 | using (BlockReentrancy()) 115 | { 116 | CollectionChanged(this, e); 117 | } 118 | } 119 | } 120 | 121 | /// 122 | /// Raised when a property value changes. 123 | /// 124 | public event PropertyChangedEventHandler PropertyChanged; 125 | 126 | private void RaisePropertyChanged(string propertyName) 127 | { 128 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 129 | } 130 | 131 | #endregion 132 | 133 | #region Methods 134 | 135 | /// 136 | /// Adds the specified element to a set. 137 | /// 138 | /// The element to add to the set. 139 | /// true if the element is added to the object; false if the element is already present. 140 | public bool Add(T item) 141 | { 142 | CheckReentrancy(); 143 | 144 | bool wasAdded = hashSet.Add(item); 145 | 146 | if (wasAdded) 147 | { 148 | int index = hashSet.IndexOf(item); 149 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); 150 | RaisePropertyChanged(PropertyNames.Count); 151 | } 152 | 153 | return wasAdded; 154 | } 155 | 156 | /// 157 | /// Adds an item to the . 158 | /// 159 | /// The object to add to the . 160 | /// 161 | /// The is read-only. 162 | /// 163 | void ICollection.Add(T item) 164 | { 165 | Add(item); 166 | } 167 | 168 | /// 169 | /// Removes all elements from a object. 170 | /// 171 | public void Clear() 172 | { 173 | CheckReentrancy(); 174 | 175 | if (hashSet.Count > 0) 176 | { 177 | hashSet.Clear(); 178 | 179 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 180 | RaisePropertyChanged(PropertyNames.Count); 181 | } 182 | } 183 | 184 | /// 185 | /// Determines whether a object contains the specified element. 186 | /// 187 | /// The element to locate in the object. 188 | /// true if the object contains the specified element; otherwise, false. 189 | public bool Contains(T item) 190 | { 191 | return hashSet.Contains(item); 192 | } 193 | 194 | 195 | /// 196 | /// Copies the elements of a collection to an array. 197 | /// 198 | /// The one-dimensional array that is the destination of the elements copied from the object. The array must have zero-based indexing. 199 | public void CopyTo(T[] array) 200 | { 201 | hashSet.CopyTo(array); 202 | } 203 | 204 | /// 205 | /// Copies the elements of a collection to an array. 206 | /// 207 | /// The one-dimensional array that is the destination of the elements copied from the object. The array must have zero-based indexing. 208 | /// The zero-based index in array at which copying begins. 209 | public void CopyTo(T[] array, int arrayIndex) 210 | { 211 | hashSet.CopyTo(array, arrayIndex); 212 | } 213 | 214 | /// 215 | /// Copies the elements of a collection to an array. 216 | /// 217 | /// The one-dimensional array that is the destination of the elements copied from the object. The array must have zero-based indexing. 218 | /// The zero-based index in array at which copying begins. 219 | /// The number of elements to copy to array. 220 | public void CopyTo(T[] array, int arrayIndex, int count) 221 | { 222 | hashSet.CopyTo(array, arrayIndex, count); 223 | } 224 | 225 | /// 226 | /// Removes all elements in the specified collection from the current object. 227 | /// 228 | /// The collection of items to remove from the object. 229 | public void ExceptWith(IEnumerable other) 230 | { 231 | //VerifyArgument.IsNotNull("other", other); 232 | 233 | CheckReentrancy(); 234 | 235 | // I locate items in other that are in the hashset 236 | var removedItems = other.Where(x => hashSet.Contains(x)).ToList(); 237 | 238 | hashSet.ExceptWith(other); 239 | 240 | if (removedItems.Count > 0) 241 | { 242 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItems)); 243 | RaisePropertyChanged(PropertyNames.Count); 244 | } 245 | } 246 | 247 | /// 248 | /// Returns an enumerator that iterates through a . 249 | /// 250 | /// A .Enumerator object for the object. 251 | public IEnumerator GetEnumerator() 252 | { 253 | return hashSet.GetEnumerator(); 254 | } 255 | 256 | /// 257 | /// Modifies the current object to contain only elements that are present in that object and in the specified collection. 258 | /// 259 | /// The collection to compare to the current object. 260 | public void IntersectWith(IEnumerable other) 261 | { 262 | //VerifyArgument.IsNotNull("other", other); 263 | 264 | CheckReentrancy(); 265 | 266 | // I locate the items in the hashset that are not in other 267 | var removedItems = hashSet.Where(x => !other.Contains(x)).ToList(); 268 | 269 | hashSet.IntersectWith(other); 270 | 271 | if (removedItems.Count > 0) 272 | { 273 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItems)); 274 | RaisePropertyChanged(PropertyNames.Count); 275 | } 276 | } 277 | 278 | /// 279 | /// Determines whether a object is a proper subset of the specified collection. 280 | /// 281 | /// The collection to compare to the current object. 282 | /// true if the object is a proper subset of other; otherwise, false. 283 | public bool IsProperSubsetOf(IEnumerable other) 284 | { 285 | return hashSet.IsProperSubsetOf(other); 286 | } 287 | 288 | /// 289 | /// Determines whether a object is a proper subset of the specified collection. 290 | /// 291 | /// The collection to compare to the current object. 292 | /// true if the object is a proper superset of other; otherwise, false. 293 | public bool IsProperSupersetOf(IEnumerable other) 294 | { 295 | return hashSet.IsProperSupersetOf(other); 296 | } 297 | 298 | /// 299 | /// Determines whether a object is a subset of the specified collection. 300 | /// 301 | /// The collection to compare to the current object. 302 | /// true if the object is a subset of other; otherwise, false. 303 | public bool IsSubsetOf(IEnumerable other) 304 | { 305 | return hashSet.IsSubsetOf(other); 306 | } 307 | 308 | /// 309 | /// Determines whether a object is a superset of the specified collection. 310 | /// 311 | /// The collection to compare to the current object. 312 | /// true if the object is a superset of other; otherwise, false. 313 | public bool IsSupersetOf(IEnumerable other) 314 | { 315 | return hashSet.IsSupersetOf(other); 316 | } 317 | 318 | /// 319 | /// Determines whether the current object and a specified collection share common elements. 320 | /// 321 | /// The collection to compare to the current object. 322 | /// true if the object and other share at least one common element; otherwise, false. 323 | public bool Overlaps(IEnumerable other) 324 | { 325 | return hashSet.Overlaps(other); 326 | } 327 | 328 | /// 329 | /// Removes the specified element from a object. 330 | /// 331 | /// The element to remove. 332 | /// true if the element is successfully found and removed; otherwise, false. This method returns false if item is not found in the object. 333 | public bool Remove(T item) 334 | { 335 | int index = hashSet.IndexOf(item); 336 | bool wasRemoved = hashSet.Remove(item); 337 | 338 | if (wasRemoved) 339 | { 340 | 341 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); 342 | RaisePropertyChanged(PropertyNames.Count); 343 | } 344 | 345 | return wasRemoved; 346 | } 347 | 348 | /// 349 | /// Determines whether a object and the specified collection contain the same elements. 350 | /// 351 | /// The collection to compare to the current object. 352 | /// true if the object is equal to other; otherwise, false. 353 | public bool SetEquals(IEnumerable other) 354 | { 355 | return hashSet.SetEquals(other); 356 | } 357 | 358 | /// 359 | /// Modifies the current object to contain only elements that are present either in that object or in the specified collection, but not both. 360 | /// 361 | /// The collection to compare to the current object. 362 | public void SymmetricExceptWith(IEnumerable other) 363 | { 364 | //VerifyArgument.IsNotNull("other", other); 365 | CheckReentrancy(); 366 | 367 | // I locate the items in other that are not in the hashset 368 | var addedItems = other.Where(x => !hashSet.Contains(x)).ToList(); 369 | 370 | // I locate items in other that are in the hashset 371 | var removedItems = other.Where(x => hashSet.Contains(x)).ToList(); 372 | 373 | hashSet.SymmetricExceptWith(other); 374 | 375 | if (removedItems.Count > 0) 376 | { 377 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removedItems)); 378 | RaisePropertyChanged(PropertyNames.Count); 379 | } 380 | 381 | if (addedItems.Count > 0) 382 | { 383 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedItems)); 384 | } 385 | 386 | if (removedItems.Count > 0 || addedItems.Count > 0) 387 | { 388 | RaisePropertyChanged(PropertyNames.Count); 389 | } 390 | } 391 | 392 | /// 393 | /// Sets the capacity of a object to the actual number of elements it contains, rounded up to a nearby, implementation-specific value. 394 | /// 395 | public void TrimExcess() 396 | { 397 | hashSet.TrimExcess(); 398 | } 399 | 400 | /// 401 | /// Modifies the current object to contain all elements that are present in itself, the specified collection, or both. 402 | /// 403 | /// The collection to compare to the current object. 404 | public void UnionWith(IEnumerable other) 405 | { 406 | //VerifyArgument.IsNotNull("other", other); 407 | CheckReentrancy(); 408 | 409 | // I locate the items in other that are not in the hashset 410 | var addedItems = other.Where(x => !hashSet.Contains(x)).ToList(); 411 | 412 | hashSet.UnionWith(other); 413 | 414 | if (addedItems.Count > 0) 415 | { 416 | RaiseCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedItems)); 417 | RaisePropertyChanged(PropertyNames.Count); 418 | } 419 | } 420 | 421 | /// 422 | /// Returns an enumerator that iterates through a collection. 423 | /// 424 | /// 425 | /// An object that can be used to iterate through the collection. 426 | /// 427 | IEnumerator IEnumerable.GetEnumerator() 428 | { 429 | return ((IEnumerable)hashSet).GetEnumerator(); 430 | } 431 | 432 | #endregion 433 | 434 | #region Reentrancy Methods 435 | 436 | private IDisposable BlockReentrancy() 437 | { 438 | monitor.Enter(); 439 | return monitor; 440 | } 441 | 442 | private void CheckReentrancy() 443 | { 444 | if ((monitor.Busy && (CollectionChanged != null)) && (CollectionChanged.GetInvocationList().Length > 1)) 445 | { 446 | throw new InvalidOperationException("There are additional attempts to change this hash set during a CollectionChanged event."); 447 | } 448 | } 449 | 450 | #endregion 451 | 452 | #region Private Classes 453 | 454 | private class SimpleMonitor : IDisposable 455 | { 456 | private int _busyCount; 457 | 458 | public void Dispose() 459 | { 460 | _busyCount--; 461 | } 462 | 463 | public void Enter() 464 | { 465 | _busyCount++; 466 | } 467 | 468 | public bool Busy => (_busyCount > 0); 469 | } 470 | 471 | 472 | #endregion 473 | } 474 | } -------------------------------------------------------------------------------- /src/CallSharp/PermuteUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace CallSharp 4 | { 5 | public static class PermuteUtils 6 | { 7 | // Returns an enumeration of enumerators, one for each permutation 8 | // of the input. 9 | public static IEnumerable> Permute(IEnumerable list, int count) 10 | { 11 | if (count == 0) 12 | { 13 | yield return new T[0]; 14 | } 15 | else 16 | { 17 | var startingElementIndex = 0; 18 | foreach (var startingElement in list) 19 | { 20 | var remainingItems = AllExcept(list, startingElementIndex); 21 | 22 | foreach ( 23 | var permutationOfRemainder in Permute(remainingItems, count - 1)) 24 | { 25 | yield return Concat( 26 | new[] {startingElement}, 27 | permutationOfRemainder); 28 | } 29 | startingElementIndex += 1; 30 | } 31 | } 32 | } 33 | 34 | // Enumerates over contents of both lists. 35 | public static IEnumerable Concat(IEnumerable a, IEnumerable b) 36 | { 37 | foreach (var item in a) 38 | { 39 | yield return item; 40 | } 41 | foreach (var item in b) 42 | { 43 | yield return item; 44 | } 45 | } 46 | 47 | // Enumerates over all items in the input, skipping over the item 48 | // with the specified offset. 49 | public static IEnumerable AllExcept(IEnumerable input, int indexToSkip) 50 | { 51 | var index = 0; 52 | foreach (var item in input) 53 | { 54 | if (index != indexToSkip) yield return item; 55 | index += 1; 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/CallSharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 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("CallSharp")] 9 | [assembly: AssemblyDescription("Input/Output Matching in .NET")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ActiveMesa")] 12 | [assembly: AssemblyProduct("CallSharp")] 13 | [assembly: AssemblyCopyright("Copyright © ActiveMesa, 2016-2019")] 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 | //In order to begin building localizable applications, set 23 | //CultureYouAreCodingWith in your .csproj file 24 | //inside a . For example, if you are using US english 25 | //in your source files, set the to en-US. Then uncomment 26 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 27 | //the line below to match the UICulture setting in the project file. 28 | 29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 30 | 31 | 32 | [assembly: ThemeInfo( 33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 34 | //(used if a resource is not found in the page, 35 | // or application resource dictionaries) 36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 37 | //(used if a resource is not found in the page, 38 | // app, or any theme specific resource dictionaries) 39 | )] 40 | 41 | 42 | // Version information for an assembly consists of the following four values: 43 | // 44 | // Major Version 45 | // Minor Version 46 | // Build Number 47 | // Revision 48 | // 49 | // You can specify all the values or you can default the Build and Revision Numbers 50 | // by using the '*' as shown below: 51 | // [assembly: AssemblyVersion("1.0.*")] 52 | [assembly: AssemblyVersion("0.2.2.0")] 53 | [assembly: AssemblyFileVersion("0.2.2.0")] 54 | 55 | // 0.2.1 changes: 56 | // - Removed identity calls (e.g., input.ToUpper().ToLower()) 57 | // (only takes care of origin-matching since storing the entire chain might be expensive) -------------------------------------------------------------------------------- /src/CallSharp/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System.CodeDom.Compiler; 12 | using System.ComponentModel; 13 | using System.Diagnostics; 14 | using System.Diagnostics.CodeAnalysis; 15 | using System.Globalization; 16 | using System.Resources; 17 | using System.Runtime.CompilerServices; 18 | 19 | namespace CallSharp.Properties 20 | { 21 | 22 | 23 | /// 24 | /// A strongly-typed resource class, for looking up localized strings, etc. 25 | /// 26 | // This class was auto-generated by the StronglyTypedResourceBuilder 27 | // class via a tool like ResGen or Visual Studio. 28 | // To add or remove a member, edit your .ResX file then rerun ResGen 29 | // with the /str option, or rebuild your VS project. 30 | [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 31 | [DebuggerNonUserCode()] 32 | [CompilerGenerated()] 33 | internal class Resources 34 | { 35 | 36 | private static ResourceManager resourceMan; 37 | 38 | private static CultureInfo resourceCulture; 39 | 40 | [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 41 | internal Resources() 42 | { 43 | } 44 | 45 | /// 46 | /// Returns the cached ResourceManager instance used by this class. 47 | /// 48 | [EditorBrowsable(EditorBrowsableState.Advanced)] 49 | internal static ResourceManager ResourceManager 50 | { 51 | get 52 | { 53 | if ((resourceMan == null)) 54 | { 55 | ResourceManager temp = new ResourceManager("CallSharp.Properties.Resources", typeof(Resources).Assembly); 56 | resourceMan = temp; 57 | } 58 | return resourceMan; 59 | } 60 | } 61 | 62 | /// 63 | /// Overrides the current thread's CurrentUICulture property for all 64 | /// resource lookups using this strongly typed resource class. 65 | /// 66 | [EditorBrowsable(EditorBrowsableState.Advanced)] 67 | internal static CultureInfo Culture 68 | { 69 | get 70 | { 71 | return resourceCulture; 72 | } 73 | set 74 | { 75 | resourceCulture = value; 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/CallSharp/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /src/CallSharp/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System.CodeDom.Compiler; 12 | using System.Configuration; 13 | using System.Runtime.CompilerServices; 14 | 15 | namespace CallSharp.Properties 16 | { 17 | 18 | 19 | [CompilerGenerated()] 20 | [GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 21 | internal sealed partial class Settings : ApplicationSettingsBase 22 | { 23 | 24 | private static Settings defaultInstance = ((Settings)(Synchronized(new Settings()))); 25 | 26 | public static Settings Default 27 | { 28 | get 29 | { 30 | return defaultInstance; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/CallSharp/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/CallSharp/ScaleToWindowSizeBehavior.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Data; 4 | using System.Windows.Media; 5 | 6 | namespace CallSharp 7 | { 8 | /// 9 | /// Attached behavior for scaling the window components proportionally. 10 | /// To be used only for demonstrations. 11 | /// 12 | public static class ScaleToWindowSizeBehavior 13 | { 14 | public static readonly DependencyProperty ParentWindowProperty = 15 | DependencyProperty.RegisterAttached("ParentWindow", 16 | typeof(Window), 17 | typeof(ScaleToWindowSizeBehavior), 18 | new FrameworkPropertyMetadata(null, OnParentWindowChanged)); 19 | 20 | public static void SetParentWindow(FrameworkElement element, Window value) 21 | { 22 | element.SetValue(ParentWindowProperty, value); 23 | } 24 | 25 | public static Window GetParentWindow(FrameworkElement element) 26 | { 27 | return (Window) element.GetValue(ParentWindowProperty); 28 | } 29 | 30 | private static void OnParentWindowChanged(DependencyObject target, 31 | DependencyPropertyChangedEventArgs e) 32 | { 33 | FrameworkElement mainElement = target as FrameworkElement; 34 | MainWindow window = e.NewValue as MainWindow; 35 | 36 | ScaleTransform scaleTransform = new ScaleTransform(); 37 | scaleTransform.CenterX = 0; 38 | scaleTransform.CenterY = 0; 39 | Binding scaleValueBinding = new Binding 40 | { 41 | Source = window, 42 | Path = new PropertyPath(ScaleValueProperty) 43 | }; 44 | BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleXProperty, 45 | scaleValueBinding); 46 | BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleYProperty, 47 | scaleValueBinding); 48 | mainElement.LayoutTransform = scaleTransform; 49 | mainElement.SizeChanged += mainElement_SizeChanged; 50 | } 51 | 52 | public static readonly DependencyProperty ScaleValueProperty = 53 | DependencyProperty.RegisterAttached("ScaleValue", 54 | typeof(double), 55 | typeof(ScaleToWindowSizeBehavior), 56 | new UIPropertyMetadata(1.0, OnScaleValueChanged, OnCoerceScaleValue)); 57 | 58 | public static double GetScaleValue(DependencyObject target) 59 | { 60 | return (double) target.GetValue(ScaleValueProperty); 61 | } 62 | 63 | public static void SetScaleValue(DependencyObject target, double value) 64 | { 65 | target.SetValue(ScaleValueProperty, value); 66 | } 67 | 68 | private static void OnScaleValueChanged(DependencyObject target, 69 | DependencyPropertyChangedEventArgs e) 70 | { 71 | } 72 | 73 | private static object OnCoerceScaleValue(DependencyObject d, object baseValue) 74 | { 75 | if (baseValue is double doubleValue) 76 | { 77 | if (double.IsNaN(doubleValue)) 78 | { 79 | return 1.0f; 80 | } 81 | doubleValue = Math.Max(0.1, doubleValue); 82 | return doubleValue; 83 | } 84 | return 1.0f; 85 | } 86 | 87 | private static void mainElement_SizeChanged(object sender, SizeChangedEventArgs e) 88 | { 89 | FrameworkElement mainElement = sender as FrameworkElement; 90 | Window window = GetParentWindow(mainElement); 91 | CalculateScale(window, mainElement); 92 | } 93 | 94 | private static void CalculateScale(Window window, FrameworkElement mainElement) 95 | { 96 | Size denominators = GetDenominators(mainElement); 97 | double xScale = window.ActualWidth/denominators.Width; 98 | double yScale = window.ActualHeight/denominators.Height; 99 | double value = Math.Min(xScale, yScale); 100 | SetScaleValue(window, value); 101 | } 102 | 103 | public static readonly DependencyProperty DenominatorsProperty = 104 | DependencyProperty.RegisterAttached("Denominators", 105 | typeof(Size), 106 | typeof(ScaleToWindowSizeBehavior), 107 | new UIPropertyMetadata(new Size(1000.0, 700.0))); 108 | 109 | public static Size GetDenominators(DependencyObject target) 110 | { 111 | return (Size) target.GetValue(DenominatorsProperty); 112 | } 113 | 114 | public static void SetDenominators(DependencyObject target, Size value) 115 | { 116 | target.SetValue(DenominatorsProperty, value); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /src/CallSharp/TypeDatabase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace CallSharp 7 | { 8 | static class TypeDatabase 9 | { 10 | private static readonly HashSet signedIntegralTypes = new HashSet 11 | { 12 | typeof(int), 13 | typeof(long), 14 | typeof(short), 15 | typeof(sbyte) 16 | }; 17 | 18 | private static readonly HashSet unsignedIntegralTypes = new HashSet 19 | { 20 | typeof(uint), 21 | typeof(ulong), 22 | typeof(ushort), 23 | typeof(byte) 24 | }; 25 | 26 | public static HashSet integralTypes = new HashSet(signedIntegralTypes.Concat(unsignedIntegralTypes)); 27 | 28 | private static readonly HashSet floatingPointTypes = new HashSet 29 | { 30 | typeof(float), 31 | typeof(double), 32 | typeof(decimal) 33 | }; 34 | 35 | private static readonly HashSet dateTimeTypes = new HashSet 36 | { 37 | typeof(DateTime), 38 | typeof(TimeSpan) 39 | }; 40 | 41 | // finds all types from `mscorlib` that contains TryParse(string, out T) method 42 | /*public static Dictionary ParseableTypes = Assembly.Load("mscorlib").GetTypes() 43 | .ToDictionary(m => m, t => t.GetMethods(BindingFlags.Static | BindingFlags.Public) 44 | .FirstOrDefault(m => m.Name == "TryParse" && m.GetParameters().Length == 2)) 45 | .Where(pair => pair.Value != null && pair.Key.FullName != "System.Enum") 46 | .ToDictionary(pair => pair.Key, pair => pair.Value);*/ 47 | 48 | 49 | //all types from `mscorlib` that contains TryParse(string, out T) method 50 | public static readonly Dictionary ParseableTypesDict = integralTypes 51 | .Prepend(typeof(bool)) 52 | .Concat(floatingPointTypes) 53 | .Concat(dateTimeTypes).Append(typeof(char)) 54 | /*.Append(typeof(string))*/.ToDictionary(t => t, 55 | t => t.GetMethods(BindingFlags.Static | BindingFlags.Public) 56 | .FirstOrDefault(m => m.Name == "TryParse" && 57 | m.GetParameters().Length == 2)); 58 | 59 | public static HashSet SequenceTypes = new HashSet 60 | { 61 | typeof(Array), 62 | typeof(List<>) 63 | }; 64 | 65 | public static readonly HashSet CoreTypes = new HashSet( 66 | ParseableTypesDict.Keys 67 | .Append(typeof(Enumerable)) 68 | .Append(typeof(Math)) 69 | .Append(typeof(ExtensionMethods)) 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/CallSharp/TypeToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace CallSharp 6 | { 7 | public class TypeToStringConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | return ((Type) value).GetFriendlyName(); 12 | } 13 | 14 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | throw new NotImplementedException(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/CallSharp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Tests/BasicMatchTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using NUnit.Framework; 5 | using CallSharp; 6 | 7 | namespace Tests 8 | { 9 | [TestFixture] 10 | public class BasicMatchTests 11 | { 12 | private static readonly IMemberDatabase mdb = new StaticMemberDatabase(); 13 | private static CancellationToken token = new CancellationToken(); 14 | 15 | [Test, Category(Categories.LongRunning)] 16 | [TestCase("foo ", "foo", "input.TrimEnd()")] 17 | [TestCase(" a b c ", "abc", "string.Concat(input.Split())")] 18 | [TestCase("xxyy", "xx", "input.TrimEnd('y')")] 19 | public void StringCalls(string input, string output, string requiredCandidate) 20 | { 21 | var candidates = new List(); 22 | mdb.FindCandidates(x => { candidates.Add(x); }, input, input, output, 2, token); 23 | Assert.That(candidates, Contains.Item(requiredCandidate)); 24 | } 25 | 26 | [Test, Category(Categories.LongRunning)] 27 | [TestCase("abc", 3, "input.Length")] 28 | public void StringTransformations(string input, object output, 29 | string requiredCandidate) 30 | { 31 | var candidates = new List(); 32 | mdb.FindCandidates(x => candidates.Add(x), input, input, output, 2, token); 33 | Assert.That(candidates, Contains.Item(requiredCandidate)); 34 | } 35 | 36 | [Test] 37 | public void FloatToIntImplicitTest() 38 | { 39 | var candidates = new List(); 40 | mdb.FindCandidates(x => candidates.Add(x), 1.0f, 1.0f, 1, 2, token); 41 | Assert.That(candidates, Contains.Item("input")); 42 | } 43 | 44 | [Test] 45 | public void IntToDoubleImplicitTest() 46 | { 47 | Assert.That(typeof(int).IsConvertibleTo(typeof(double))); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Tests/Categories.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 Tests 8 | { 9 | public class Categories 10 | { 11 | public const string LongRunning = "Long running"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Tests/FragTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using CallSharp; 7 | using NUnit.Framework; 8 | 9 | namespace Tests 10 | { 11 | [TestFixture] 12 | public class FragTests 13 | { 14 | private FragmentationEngine fe; 15 | 16 | [SetUp] 17 | public void SetUp() 18 | { 19 | fe = new FragmentationEngine(); 20 | } 21 | 22 | [Test] 23 | [TestCase("abc", 'a', 'b', 'c')] 24 | public void StringToCharFragmentationTests(string input, params char[] expectedOutputs) 25 | { 26 | var items = fe.Frag(input, typeof(char)); 27 | foreach (var eo in expectedOutputs) 28 | Assert.That(items.Contains(eo), $"expected the result set [{string.Join(",", items)}] to contain [{eo}]"); 29 | } 30 | 31 | [Test] 32 | [TestCase("a b c", " ", "a", " b ")] 33 | public void StringToStringFragmentationTest(string input, params string[] expectedOutputs) 34 | { 35 | var items = fe.Frag(input, typeof(string)); 36 | foreach (var eo in expectedOutputs) 37 | Assert.That(items.Contains(eo), $"expected the result set [{string.Join(",", items)}] to contain [{eo}]"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Tests/OtherTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using CallSharp; 7 | using NUnit.Framework; 8 | 9 | namespace Tests 10 | { 11 | [TestFixture] 12 | public class OtherTests 13 | { 14 | [Test] 15 | public void Test() 16 | { 17 | var l = new[] {'x', 'y', 'z'}.ToLiteral(); 18 | Assert.That(l, Is.EqualTo("new [] { 'x', 'y', 'z' }")); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Tests/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("Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 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("c12a3423-cfb5-4540-95c8-e5833a911c98")] 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/Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C12A3423-CFB5-4540-95C8-E5833A911C98} 8 | Library 9 | Properties 10 | Tests 11 | Tests 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | bin\x64\Debug\ 18 | DEBUG;TRACE 19 | full 20 | x64 21 | prompt 22 | MinimumRecommendedRules.ruleset 23 | 24 | 25 | bin\x64\Release\ 26 | TRACE 27 | true 28 | pdbonly 29 | x64 30 | prompt 31 | MinimumRecommendedRules.ruleset 32 | 33 | 34 | 35 | ..\packages\NUnit.3.4.1\lib\net45\nunit.framework.dll 36 | True 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {cc273aea-10c3-4aa6-a8bf-a2437d6ab716} 60 | CallSharp 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /src/Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------