diff --git a/.gitignore b/.gitignore index ee88d51d..7e619a34 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ vdextensions/obj /msbuild/dbuild/.vs /test .vs +/msbuild/dbuild/assemblies +/vdextensions/assembly diff --git a/.gitmodules b/.gitmodules index 73521abf..8f0419da 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vdc/abothe/Parser"] path = vdc/abothe/Parser url = https://github.com/rainers/D_Parser.git +[submodule "vdc/dmdserver/dmd"] + path = vdc/dmdserver/dmd + url = https://github.com/rainers/dmd.git diff --git a/CHANGES b/CHANGES index c125eda5..ae0d0bea 100644 --- a/CHANGES +++ b/CHANGES @@ -1174,3 +1174,21 @@ Version history * don't highlight asm keywords/mnemonics/registers from semantic information * VS 2019 16.2: command line options no longer read correctly from the VC project for Compile and Run/Debug/Disassemble, dbuild refactored to not rely on msbuild DLLs for that + +unreleased Version 0.51.0 + * Ctrl+Click goto definition added for VS2017+ + * experimental: semantic server built from dmd frontend + * VS2017+: syntax highlighted tool tips + * mago: + - new option "hide reference pointers" + - new option: "remove leading zeroes from hex values" + - fix crash expanding pointer to empty dynamic array + - large arrays: show growing index, fix omitting last element + * installer: add sections for "Build Tools VS2017/2019"" + * dparser: now creates server process per Visual Studio instance + * added option to not show error squiggles and markers + * added tooltip to collapsed region + * fix function signature tool tips + * error list now filled with intellisense errors + * basic DUB support: upgrade and refresh if project contains dub.json or dub.sdl + * msbuild: pass original variable LinkToolExe to pipelink.exe through environment \ No newline at end of file diff --git a/Makefile b/Makefile index 5370280a..b555abb5 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,12 @@ visuald_test: vdserver: devenv /Project "vdserver" /Build "$(CONFIG)|Win32" visuald_vs10.sln +dmdserver: + devenv /Project "dmdserver" /Build "$(CONFIG)|x64" visuald_vs10.sln + +dmdserver_test: + devenv /Project "dmdserver" /Build "TestDebug|x64" visuald_vs10.sln + dparser: cd vdc\abothe && $(MSBUILD15) vdserver.sln /p:Configuration=Release;Platform="Any CPU" /p:TargetFrameworkVersion=4.5.2 /p:DefineConstants=NET40 /t:Rebuild editbin /STACK:0x800000 bin\Release\DParserCOMServer\DParserCOMServer.exe @@ -81,6 +87,9 @@ fake_dparser: vdextension: cd vdextensions && $(MSBUILD) vdextensions.csproj /p:Configuration=Release;Platform=x86 /t:Rebuild +vdext15: + cd vdextensions && $(MSBUILD) vdext15.csproj /p:Configuration=Release;Platform=x86 /t:Rebuild + visualdwizard: cd vdwizard && $(MSBUILD) VisualDWizard.csproj /p:Configuration=Release;Platform=AnyCPU /t:Rebuild @@ -163,7 +172,7 @@ install_vs_no_vs2017: install_modules fake_dparser cv2pdb mago dbuild12 dbuild install_vs_only_vs2017: install_modules dparser dparser_test cv2pdb_vs15 mago_vs15 fake_dbuild12 fake_dbuild14 dbuild15 install_only -install_modules: prerequisites visuald_vs vdserver vdextension visualdwizard dcxxfilt +install_modules: prerequisites visuald_vs vdserver dmdserver vdextension vdext15 visualdwizard dcxxfilt install_only: if not exist ..\downloads\nul md ..\downloads diff --git a/TODO b/TODO index 915dcb4b..92d6fd92 100644 --- a/TODO +++ b/TODO @@ -229,7 +229,86 @@ Unsorted - dparser: doesn't support qualified name in catch(fqn) +- dpp support + 0.45.0 ====== - exception on vdextensions: The Visual Studio component cache is out of date +0.49.0 +====== +- DParser: + + static if (is(__traits(parent, target) : __traits(parent, rest[0]))) + + static if (is(T == __vector) ) + - needs too much CPU +- Documentation: + - installation (VC required) + - move newer VS versions to top ++ colors +- tooltips +- exceptions while VC project loaded? +- VS2019: + - new project: D templates hardly accessible + + vcxproj: DCompiler not selectable +- mago: + - toDebug + - context 'this' and members of 'this' shown +- pasting large code snippet is slow with auto-indent + +0.50.0 +====== ++ VS 16.2: pdb newer than exe ++ Deprecation shown as error + +- search files/symbols sometimes blank: columns have width 0 +- new D module: adjust module name + ++ VC project: simpler opt-in for -mixin, per package filename ++ -extern-std= + +- dark scheme: colors wrong after install (also happens for C#?), colors still too dark +- reference highlight: wrong color, not shown in scroll margin +- download: no update for the status bar in VS2017 ++ display html error ++ update message "DMD 2.086.1 Goto Page"? ++ VC projects: DMD/LDC switch not visible in non-english? + ++ vtbl for C++ classes +- mago: call update in VS2019 ++ mago: VS2019, dragging a variable from the autos, locals, or watches copies the whole line (C++, too?) ++ mago: breakpoint conditions no longer supported? +- mago: debug info with different cased filenames opened twice in VS ++ mago: limit array exansions ++ mago: AA with impl, but without elements? +- mago: start class expansions for derived type + ++ support -lowmem ++ show message if compiler path wrong + +- LDC: options for debug-lib and LTO + +- HiDPI: + + edit line in search dialog + + edit line in profiler dialog + + search and replace token dialog + + C++ conversion wizard + - toolbar bitmaps don't scale +- adapt tool window color to theme + +- semantic coloring: + - x in foreach(x; range) + - x in if(auto x = ptr) + - goto labels + - exit in scope(exit) + - x in extern(x) + - public imports in imports + + +0.50.1 +====== ++ reset settings to default ++ msbuild doesn't work after first full instllation, still needs to open+close settings +- vd reported as "unresponsive" when loading project (> 7 sec) ++ VC parallel build + +- compile & disassemble: VC projects output dir always Win32/Debug \ No newline at end of file diff --git a/VERSION b/VERSION index c4e5d5d5..a70f9852 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ #define VERSION_MAJOR 0 -#define VERSION_MINOR 50 -#define VERSION_REVISION 1 -#define VERSION_BETA -#define VERSION_BUILD 0 +#define VERSION_MINOR 51 +#define VERSION_REVISION 0 +#define VERSION_BETA -beta +#define VERSION_BUILD 1 diff --git a/appveyor.yml b/appveyor.yml index 77779a32..5e868b5f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,18 +18,18 @@ environment: - os: Visual Studio 2017 VS: 15 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - - os: Visual Studio 2015 - VS: 14 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - os: Visual Studio 2015 +# VS: 14 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 # - os: Visual Studio 2013 # VS: 12 # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 # cache relative to C:\projects\visuald cache: - - C:\projects\cache\dmd2083_0.7z + - C:\projects\cache\dmd2088_0.7z - C:\projects\cache\cd851.zip - - C:\projects\cache\VisualD-v0.47.0.exe + - C:\projects\cache\VisualD-v0.50.1.exe - C:\projects\cache\binutils-2.25.tar.gz #matrix: @@ -50,10 +50,10 @@ install: # Download & extract D compiler - ps: | If ($Env:D_COMPILER -eq 'dmd') { - If (-not (Test-Path 'cache\dmd2083_0.7z')) { - Start-FileDownload 'http://downloads.dlang.org/releases/2.x/2.083.0/dmd.2.083.0.windows.7z' -FileName 'cache\dmd2083_0.7z' + If (-not (Test-Path 'cache\dmd2088_0.7z')) { + Start-FileDownload 'http://downloads.dlang.org/releases/2.x/2.088.0/dmd.2.088.0.windows.7z' -FileName 'cache\dmd2088_0.7z' } - 7z x cache\dmd2083_0.7z > $null + 7z x cache\dmd2088_0.7z > $null Set-Item -path env:DMD -value c:\projects\dmd2\windows\bin\dmd.exe c:\projects\dmd2\windows\bin\dmd.exe --version } ElseIf ($Env:D_COMPILER -eq 'dmd-nightly') { @@ -77,10 +77,10 @@ install: copy c:\projects\dm\bin\coffimplib.exe c:\projects\dmd2\windows\bin # Download & install Visual D - ps: | - If (-not (Test-Path 'cache\VisualD-v0.47.0.exe')) { - Start-FileDownload 'https://github.com/dlang/visuald/releases/download/v0.47.0/VisualD-v0.47.0.exe' -FileName 'cache\VisualD-v0.47.0.exe' + If (-not (Test-Path 'cache\VisualD-v0.50.1.exe')) { + Start-FileDownload 'https://github.com/dlang/visuald/releases/download/v0.50.1/VisualD-v0.50.1.exe' -FileName 'cache\VisualD-v0.50.1.exe' } - - cache\VisualD-v0.47.0.exe /S + - cache\VisualD-v0.50.1.exe /S # configure DMD path - reg add "HKLM\SOFTWARE\DMD" /v InstallationFolder /t REG_SZ /d c:\projects /reg:32 /f # disable link dependencies monitoring, fails on AppVeyor server @@ -104,14 +104,14 @@ before_build: build_script: - cd c:\projects - cd visuald + # Fetch submodules + - git submodule update --init --recursive # ignore failure once, in case it needs reloading the sdk project - nmake prerequisites || nmake prerequisites # build Visual D - nmake visuald_vs # build and run Visual D unittests - - nmake visuald_test - # Fetch submodules - - git submodule update --init --recursive + - nmake visuald_test dmdserver_test - cd .. # Clone mago/cv2pdb (need to be two levels up) - cd .. diff --git a/build/build.visualdproj b/build/build.visualdproj index 65156fb1..cf1695c2 100644 --- a/build/build.visualdproj +++ b/build/build.visualdproj @@ -628,6 +628,7 @@ dmd -map "$(IntDir)\$(InputName).map" "-of$(OutDir)\$(InputName). + +dmd -map $(OutDir)\$(InputName).map -of$(OutDir)\$(InputName).exe $(InputPath) ..\tools\nostacktrace.d" dependencies="..\tools\nostacktrace.d" outfile="$(OutDir)\$(InputName).exe" name="Release|Win32" /> m:\s\d\rainers\windows\bin\dmd.exe .. .. - ..\bin\$(ConfigurationName)64 + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1397,10 +1397,10 @@ $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1884,7 +1884,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) diff --git a/c2d/cpp2d.visualdproj b/c2d/cpp2d.visualdproj index 6fde8a9e..1a364cb3 100644 --- a/c2d/cpp2d.visualdproj +++ b/c2d/cpp2d.visualdproj @@ -32,7 +32,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -45,10 +45,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -86,10 +98,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -140,7 +153,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -153,10 +166,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -194,10 +219,11 @@ 0 $(VisualDInstallDir)cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -248,7 +274,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -261,10 +287,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 1 $(CC) -c @@ -302,10 +340,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -356,7 +395,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -369,10 +408,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -410,10 +461,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -464,7 +516,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -477,10 +529,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -518,10 +582,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -572,7 +637,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -585,10 +650,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -626,10 +703,11 @@ 0 $(VisualDInstallDir)cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -680,7 +758,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -693,10 +771,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 1 0 $(CC) -c @@ -734,10 +824,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin -lws2_32 -lkernel32 -lwsock32 -ladvapi32 -loleaut32 -lole32 @@ -788,7 +879,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -801,10 +892,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -813,7 +916,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. .. - ..\bin\$(ConfigurationName)64 + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -842,10 +945,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin oleaut32.lib ole32.lib @@ -896,7 +1000,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -909,10 +1013,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -950,10 +1066,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1004,7 +1121,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1017,10 +1134,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1058,10 +1187,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin comctl32.lib ntstc_libcmt.lib @@ -1112,7 +1242,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1125,10 +1255,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1166,10 +1308,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1220,7 +1363,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1233,19 +1376,31 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1274,10 +1429,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1328,7 +1484,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -1341,10 +1497,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1382,10 +1550,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1436,7 +1605,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1449,10 +1618,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1490,10 +1671,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin comctl32.lib ntstc_libcmt.lib @@ -1544,7 +1726,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1557,10 +1739,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1598,10 +1792,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1652,7 +1847,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1665,10 +1860,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1677,7 +1884,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1706,10 +1913,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib diff --git a/c2d/dlist.d b/c2d/dlist.d index 81ba6ab9..75c82bc0 100644 --- a/c2d/dlist.d +++ b/c2d/dlist.d @@ -268,11 +268,21 @@ else } } - ref T opStar() + ref T opUnary(string op)() if(op == "*") { return _pos.data; } + void opUnary(string op)() if(op == "++") + { + advance(); + } + + void opUnary(string op)() if(op == "--") + { + retreat(); + } + ref T opIndex(int idx) { DListIterator!(T) it = this; @@ -280,14 +290,14 @@ else return *it; } - DListIterator!(T) opAdd(int cnt) + DListIterator!(T) opBinary(string op)(int cnt) if(op == "+") { DListIterator!(T) it = this; it += cnt; return it; } - DListIterator!(T) opSub(int cnt) + DListIterator!(T) opBinary(string op)(int cnt) if(op == "-") { DListIterator!(T) it = this; it += -cnt; @@ -314,7 +324,7 @@ else return _pos is _list.root._next; } - void opAddAssign(int cnt) + void opOpAssign(string op)(int cnt) if(op == "+") { while(cnt > 0) { @@ -327,9 +337,9 @@ else cnt++; } } - void opSubAssign(int cnt) + void opOpAssign(string op)(int cnt) if(op == "-") { - opAddAssign(-cnt); + opOpAssign!"+"(-cnt); } void insertAfter(T data) diff --git a/c2d/idl2d.d b/c2d/idl2d.d index 28f23f18..572362b7 100644 --- a/c2d/idl2d.d +++ b/c2d/idl2d.d @@ -145,6 +145,8 @@ class idl2d "enclaveapi.h", // Win SDK 10.0.14393.0 "dpa_dsa.h", + // Win SDK 10.0.18362.0 + "fileapifromapp.h", ]) win_idl_files ~= f ~ "*"; // make it optional @@ -1292,6 +1294,8 @@ version(all) replaceTokenSequence(tokens, "MEM_EXTENDED_PARAMETER_TYPE, *PMEM_EXTENDED_PARAMETER_TYPE", "*PMEM_EXTENDED_PARAMETER_TYPE", true); // win 10.0.17763.0: typedef enum MEM_SECTION_EXTENDED_PARAMETER_TYPE {} MEM_SECTION_EXTENDED_PARAMETER_TYPE, ... replaceTokenSequence(tokens, "MEM_SECTION_EXTENDED_PARAMETER_TYPE, *PMEM_SECTION_EXTENDED_PARAMETER_TYPE", "*PMEM_SECTION_EXTENDED_PARAMETER_TYPE", true); + // win 10.0.18362.0: typedef struct DECLSPEC_ALIGN(16) DECLSPEC_NOINITALL _CONTEXT ... + replaceTokenSequence(tokens, "DECLSPEC_NOINITALL", "", true); } if(currentModule == "commctrl") @@ -1360,6 +1364,10 @@ version(all) // imports inside extern(C) {} replaceTokenSequence(tokens, "extern \"C\" { $_data }", "$_data", true); } + if(currentModule == "fileapifromapp") + { + replaceTokenSequence(tokens, "WINSTORAGEAPI", "", true); + } if(currentModule == "propidlbase") { replaceTokenSequence(tokens, "_VARIANT_BOOL bool;", "/*_VARIANT_BOOL bool;*/", true); diff --git a/c2d/vsi2d.visualdproj b/c2d/vsi2d.visualdproj index bf156d9b..e19bd5c6 100644 --- a/c2d/vsi2d.visualdproj +++ b/c2d/vsi2d.visualdproj @@ -1155,10 +1155,10 @@ $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1608,7 +1608,7 @@ 0 0 0 - 1 + 0 0 0 0 @@ -1635,14 +1635,14 @@ 0 0 0 - 1 + 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) diff --git a/msbuild/dbuild/VCProjectInterop.cs b/msbuild/dbuild/VCProjectInterop.cs index b634b355..0468da5c 100644 --- a/msbuild/dbuild/VCProjectInterop.cs +++ b/msbuild/dbuild/VCProjectInterop.cs @@ -40,7 +40,7 @@ public partial class VisualCHelper : IVisualCHelper { /////////////////////////////////////////////////////////////////////// static int ConfigureFlags(bool unittestOn, bool debugOn, bool x64, bool cov, bool doc, bool nobounds, bool gdc, - int versionLevel, int debugLevel, bool noDeprecated, bool ldc) + int versionLevel, int debugLevel, bool noDeprecated, bool ldc, bool warnings) { return (unittestOn ? 1 : 0) | (debugOn ? 2 : 0) @@ -52,7 +52,8 @@ static int ConfigureFlags(bool unittestOn, bool debugOn, bool x64, bool cov, boo | (noDeprecated ? 128 : 0) | ((versionLevel & 0xff) << 8) | ((debugLevel & 0xff) << 16) - | (ldc ? 0x4000000 : 0); + | (ldc ? 0x4000000 : 0) + | (warnings ? 0x10000000 : 0); } @@ -207,11 +208,12 @@ public void GetDCompileOptions(IVsHierarchy proj, uint itemid, bool doc = vcprop.GetEvaluatedPropertyValue("DocDir") != "" || vcprop.GetEvaluatedPropertyValue("DocFile") != ""; bool nobounds = vcprop.GetEvaluatedPropertyValue("BoundsCheck") == "On"; bool noDeprecated = vcprop.GetEvaluatedPropertyValue("Deprecations") == "Error"; + bool warnings = vcprop.GetEvaluatedPropertyValue("Warnings") != "None"; bool gdc = false; int versionLevel = 0; int debugLevel = 0; flags = (uint)ConfigureFlags(unittestOn, debugOn, x64, cov, doc, nobounds, gdc, - versionLevel, debugLevel, noDeprecated, ldc); + versionLevel, debugLevel, noDeprecated, ldc, warnings); } diff --git a/msbuild/dbuild/dbuild.sln b/msbuild/dbuild/dbuild.sln index d99e23b0..1af84bda 100644 --- a/msbuild/dbuild/dbuild.sln +++ b/msbuild/dbuild/dbuild.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dbuild", "dbuild.csproj", "{45508B90-440B-46DD-82CC-178196D9794E}" EndProject @@ -10,13 +10,13 @@ Global Debug|Any CPU = Debug|Any CPU Debug-v14|Any CPU = Debug-v14|Any CPU Debug-v15|Any CPU = Debug-v15|Any CPU - Debug-v16|Any CPU = Debug-v16|Any CPU Debug-v16_1|Any CPU = Debug-v16_1|Any CPU + Debug-v16|Any CPU = Debug-v16|Any CPU Release|Any CPU = Release|Any CPU Release-v14|Any CPU = Release-v14|Any CPU Release-v15|Any CPU = Release-v15|Any CPU - Release-v16|Any CPU = Release-v16|Any CPU Release-v16_1|Any CPU = Release-v16_1|Any CPU + Release-v16|Any CPU = Release-v16|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {45508B90-440B-46DD-82CC-178196D9794E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -25,22 +25,25 @@ Global {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|Any CPU.Build.0 = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v15|Any CPU.ActiveCfg = Debug-v15|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v15|Any CPU.Build.0 = Debug-v15|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.ActiveCfg = Debug-v16|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.Build.0 = Debug-v16|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16_1|Any CPU.ActiveCfg = Debug-v16_1|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16_1|Any CPU.Build.0 = Debug-v16_1|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.ActiveCfg = Debug-v16|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.Build.0 = Debug-v16|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release|Any CPU.ActiveCfg = Release|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release|Any CPU.Build.0 = Release|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Any CPU.ActiveCfg = Release-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Any CPU.Build.0 = Release-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v15|Any CPU.ActiveCfg = Release-v15|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v15|Any CPU.Build.0 = Release-v15|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16|Any CPU.ActiveCfg = Release-v16|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16|Any CPU.Build.0 = Release-v16|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16_1|Any CPU.ActiveCfg = Release-v16_1|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16_1|Any CPU.Build.0 = Release-v16_1|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16|Any CPU.ActiveCfg = Release-v16|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Release-v16|Any CPU.Build.0 = Release-v16|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7C482A9E-BE25-4FF5-A5A0-8625D1BB01DD} + EndGlobalSection EndGlobal diff --git a/msbuild/dcompile.targets b/msbuild/dcompile.targets index ace15282..3c1170bf 100644 --- a/msbuild/dcompile.targets +++ b/msbuild/dcompile.targets @@ -18,6 +18,25 @@ + + + + + + + + + + + + + @@ -297,6 +316,8 @@ + + $(VisualDMSBuildDir) pipelink.exe diff --git a/nsis/Extensions_vs15/extension.vsixmanifest b/nsis/Extensions_vs15/extension.vsixmanifest new file mode 100644 index 00000000..10c24ecb --- /dev/null +++ b/nsis/Extensions_vs15/extension.vsixmanifest @@ -0,0 +1,36 @@ + + + + + vdlogo.ico + vdlogo.ico + Visual D + Extension to provide support for the D programming language + + + + + + + + + + + + + + + + + + + NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + NuGet.VisualStudio.TemplateWizard + + + + + + + + diff --git a/nsis/visuald.nsi b/nsis/visuald.nsi index 36666884..38ecc040 100644 --- a/nsis/visuald.nsi +++ b/nsis/visuald.nsi @@ -15,6 +15,9 @@ ; define VDSERVER to include vdserver COM server installation ; !define VDSERVER +; define DMDSERVER to include dmdserver COM server installation +!define DMDSERVER + ; define VDEXTENSIONS to include C# extensions (expected at ../bin/Release/vdextensions) !define VDEXTENSIONS @@ -26,12 +29,12 @@ ; define DMD source path to include dmd installation ; !define DMD -!define DMD_VERSION "2.087.1" +!define DMD_VERSION "2.089.0" !define DMD_SRC c:\d\dmd-${DMD_VERSION} ; define LDC to include ldc installation ; !define LDC -!define LDC_VERSION "1.17.0" +!define LDC_VERSION "1.18.0" !define LDC_SRC c:\d\ldc2-${LDC_VERSION}-windows-multilib ; define VS2019 to include VS2019 support @@ -255,8 +258,13 @@ Section "Visual Studio package" SecPackage ${File} "..\bin\${CONFIG}\" vdserver.exe !endif +!ifdef DMDSERVER + ${File} "..\bin\${CONFIG}\x64\" dmdserver.exe +!endif + !ifdef VDEXTENSIONS ${File} ..\bin\Release\vdextensions\ vdextensions.dll + ${File} ..\bin\Release\vdext15\ vdext15.dll !endif !ifdef DPARSER @@ -280,6 +288,10 @@ Section "Visual Studio package" SecPackage Call RegisterVDServer !endif +!ifdef DMDSERVER + Call RegisterDMDServer +!endif + !ifdef DPARSER Call RegisterDParser !endif @@ -548,7 +560,7 @@ ${MementoSection} "Install in VS 2017" SecVS2017 ${AddItem} "$1${EXTENSION_DIR}\visuald.pkgdef" ${SetOutPath} "$1${EXTENSION_DIR}" - ${File} ..\nsis\Extensions_vs12\ extension.vsixmanifest + ${File} ..\nsis\Extensions_vs15\ extension.vsixmanifest ${File} ..\nsis\Extensions\ vdlogo.ico ${AddItem} "$1${EXTENSION_DIR}" @@ -596,7 +608,7 @@ ${MementoSection} "Install in VS 2019" SecVS2019 ${AddItem} "$1${EXTENSION_DIR}\visuald.pkgdef" ${SetOutPath} "$1${EXTENSION_DIR}" - ${File} ..\nsis\Extensions_vs12\ extension.vsixmanifest + ${File} ..\nsis\Extensions_vs15\ extension.vsixmanifest ${File} ..\nsis\Extensions\ vdlogo.ico ${AddItem} "$1${EXTENSION_DIR}" @@ -912,6 +924,8 @@ SectionEnd LangString DESC_SecVS2015 ${LANG_ENGLISH} "Register for usage in Visual Studio 2015." LangString DESC_SecVS2017 ${LANG_ENGLISH} "Register for usage in Visual Studio 2017." LangString DESC_SecVS2019 ${LANG_ENGLISH} "Register for usage in Visual Studio 2019." + LangString DESC_SecVS2017BT ${LANG_ENGLISH} "Register for usage in Visual Studio 2017 Build Tools." + LangString DESC_SecVS2019BT ${LANG_ENGLISH} "Register for usage in Visual Studio 2019 Build Tools." !ifdef EXPRESS LangString DESC_SecVCExpress2008 ${LANG_ENGLISH} "Register for usage in Visual C++ Express 2008 (experimental and unusable)." LangString DESC_SecVCExpress2010 ${LANG_ENGLISH} "Register for usage in Visual C++ Express 2010 (experimental and unusable)." @@ -948,6 +962,8 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2015} $(DESC_SecVS2015) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2017} $(DESC_SecVS2017) !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2019} $(DESC_SecVS2019) + !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2017BT} $(DESC_SecVS2017BT) + !insertmacro MUI_DESCRIPTION_TEXT ${SecVS2019BT} $(DESC_SecVS2019BT) !ifdef EXPRESS !insertmacro MUI_DESCRIPTION_TEXT ${SecVCExpress2008} $(DESC_SecVCExpress2008) !insertmacro MUI_DESCRIPTION_TEXT ${SecVCExpress2008} $(DESC_SecVCExpress2010) @@ -1123,6 +1139,7 @@ Section "Uninstall" Call un.RegisterIVDServer Call un.RegisterVDServer + Call un.RegisterDMDServer Call un.RegisterDParser Call un.installedFiles @@ -1544,24 +1561,46 @@ Function un.RegisterVDServer FunctionEnd +;--------------------------------------- +!define DMDSERVER_REG_ROOT HKCR +!define DMDSERVER_FACTORY_NAME visuald.dmdserver.factory +!define DMDSERVER_FACTORY_CLSID {002a2de9-8bb6-484d-9906-7e4ad4084715} +; typelib and IVDServer interface inherited from vdserver.exe + +Function RegisterDMDServer + + WriteRegStr ${DMDSERVER_REG_ROOT} "${DMDSERVER_FACTORY_NAME}\CLSID" "" ${DMDSERVER_FACTORY_CLSID} + WriteRegStr ${DMDSERVER_REG_ROOT} "CLSID\${DMDSERVER_FACTORY_CLSID}\LocalServer32" "" $INSTDIR\dmdserver.exe + WriteRegStr ${DMDSERVER_REG_ROOT} "CLSID\${DMDSERVER_FACTORY_CLSID}\ProgId" "" DMDServer.VDServer + WriteRegStr ${DMDSERVER_REG_ROOT} "CLSID\${DMDSERVER_FACTORY_CLSID}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" "" "" + +FunctionEnd + +Function un.RegisterDMDServer + + DeleteRegKey ${DMDSERVER_REG_ROOT} "${DMDSERVER_FACTORY_NAME}" + DeleteRegKey ${DMDSERVER_REG_ROOT} "CLSID\${DMDSERVER_FACTORY_CLSID}" + +FunctionEnd + ;--------------------------------------- !define DPARSER_REG_ROOT HKCR !define DPARSER_FACTORY_NAME DParserCOMServer.VDServerClassFactory -!define DPARSER_FACTORY_CLSID {002a2de9-8bb6-484d-aa02-7e4ad4084715} +!define DPARSER_FACTORY_CLSID {002a2de9-8bb6-484d-aa05-7e4ad4084715} !define DPARSER_VDSERVER_CLSID {002a2de9-8bb6-484d-aa05-7e4ad4084715} ; typelib and IVDServer interface inherited from vdserver.exe Function RegisterDParser -; WriteRegStr ${DPARSER_REG_ROOT} "${DPARSER_FACTORY_NAME}\CLSID" "" ${DPARSER_FACTORY_CLSID} -; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\LocalServer32" "" $INSTDIR\DParser\DParserCOMServer.exe -; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\ProgId" "" DParserCOMServer.VDServer -; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" "" "" + WriteRegStr ${DPARSER_REG_ROOT} "${DPARSER_FACTORY_NAME}\CLSID" "" ${DPARSER_FACTORY_CLSID} + WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\LocalServer32" "" $INSTDIR\DParser\DParserCOMServer.exe + WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\ProgId" "" DParserCOMServer.VDServer + WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_FACTORY_CLSID}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" "" "" - WriteRegStr ${DPARSER_REG_ROOT} "${DPARSER_FACTORY_NAME}\CLSID" "" ${DPARSER_VDSERVER_CLSID} - WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\LocalServer32" "" $INSTDIR\DParser\DParserCOMServer.exe - WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\ProgId" "" DParserCOMServer.VDServer - WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" "" "" +; WriteRegStr ${DPARSER_REG_ROOT} "${DPARSER_FACTORY_NAME}\CLSID" "" ${DPARSER_VDSERVER_CLSID} +; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\LocalServer32" "" $INSTDIR\DParser\DParserCOMServer.exe +; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\ProgId" "" DParserCOMServer.VDServer +; WriteRegStr ${DPARSER_REG_ROOT} "CLSID\${DPARSER_VDSERVER_CLSID}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" "" "" FunctionEnd @@ -1572,6 +1611,7 @@ Function un.RegisterDParser FunctionEnd +;--------------------------------------- Function VSConfigurationChanged Exch $1 ; argument "${VS2017_INSTALL_KEY}Common7\IDE" diff --git a/sdk/vsi.visualdproj b/sdk/vsi.visualdproj index 7efb384d..5ff407d9 100644 --- a/sdk/vsi.visualdproj +++ b/sdk/vsi.visualdproj @@ -1,6 +1,6 @@ {32872753-4812-40DA-9B24-1C2114621E78} - + 0 0 1 @@ -32,7 +32,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -45,10 +45,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -86,10 +98,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -108,7 +121,7 @@ *.obj - + 0 0 1 @@ -140,7 +153,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -153,10 +166,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -194,10 +219,11 @@ 0 $(VisualDInstallDir)cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -216,7 +242,7 @@ *.obj - + 0 0 1 @@ -248,7 +274,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -261,10 +287,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -302,10 +340,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -324,7 +363,7 @@ *.obj - + 0 0 1 @@ -356,7 +395,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -369,10 +408,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -410,10 +461,11 @@ 0 $(VisualDInstallDir)cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -432,7 +484,7 @@ *.obj - + 0 0 1 @@ -464,7 +516,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -477,10 +529,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 1 0 $(CC) -c @@ -518,10 +582,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -540,7 +605,7 @@ *.obj - + 0 0 1 @@ -572,7 +637,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -585,10 +650,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 1 0 $(CC) -c @@ -626,10 +703,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -648,7 +726,7 @@ *.obj - + 0 0 1 @@ -680,7 +758,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -693,10 +771,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -734,10 +824,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -756,7 +847,7 @@ *.obj - + 0 0 1 @@ -788,7 +879,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -801,10 +892,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -813,7 +916,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -842,10 +945,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -864,7 +968,7 @@ *.obj - + 0 0 1 @@ -896,7 +1000,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -909,10 +1013,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -950,10 +1066,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -972,7 +1089,7 @@ *.obj - + 0 0 1 @@ -1004,7 +1121,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1017,10 +1134,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1058,10 +1187,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1080,7 +1210,7 @@ *.obj - + 0 0 1 @@ -1112,7 +1242,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1125,10 +1255,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1166,10 +1308,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1188,7 +1331,7 @@ *.obj - + 0 0 1 @@ -1220,7 +1363,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1233,19 +1376,31 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1274,10 +1429,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1296,7 +1452,7 @@ *.obj - + 0 0 1 @@ -1328,7 +1484,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -1341,10 +1497,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1382,10 +1550,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1404,7 +1573,7 @@ *.obj - + 0 0 1 @@ -1436,7 +1605,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1449,10 +1618,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1490,10 +1671,11 @@ 0 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1512,7 +1694,7 @@ *.obj - + 0 0 1 @@ -1544,7 +1726,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1557,10 +1739,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1598,10 +1792,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1620,7 +1815,7 @@ *.obj - + 0 0 1 @@ -1652,7 +1847,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1665,19 +1860,31 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1706,10 +1913,11 @@ 1 "$(VisualDInstallDir)cv2pdb.exe" - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1870,6 +2078,7 @@ + @@ -1939,6 +2148,9 @@ + + + @@ -1999,6 +2211,10 @@ + + + + diff --git a/stdext/container.d b/stdext/container.d index e95c766f..42619331 100644 --- a/stdext/container.d +++ b/stdext/container.d @@ -39,7 +39,7 @@ struct Queue(T) return data[idx]; } - ref Queue!T opCatAssign(ref T t) + ref Queue!T opOpAssign(string op)(ref T t) if (op == "~") { append(t); return this; diff --git a/stdext/stdext.visualdproj b/stdext/stdext.visualdproj index 2f0b6e22..8833dcf8 100644 --- a/stdext/stdext.visualdproj +++ b/stdext/stdext.visualdproj @@ -916,7 +916,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1397,10 +1397,10 @@ $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1881,10 +1881,10 @@ $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) diff --git a/tools/build_dcxxfilt.bat b/tools/build_dcxxfilt.bat index 41102a65..936615d6 100644 --- a/tools/build_dcxxfilt.bat +++ b/tools/build_dcxxfilt.bat @@ -3,7 +3,7 @@ rem unpack and configure binutils 2.25+ rem don't use spaces in path names! setlocal -if "%DMDINSTALLDIR%" == "" set DMDINSTALLDIR=c:\s\d\rainers +if "%DMDINSTALLDIR%" == "" set DMDINSTALLDIR=c:\d\dmd-2.087.0 set DMD=%DMDINSTALLDIR%\windows\bin\dmd if "%BINUTILS%" == "" set BINUTILS=c:\s\cpp\cxxfilt diff --git a/tools/pipedmd.d b/tools/pipedmd.d index 43d4cea1..4cb2034b 100644 --- a/tools/pipedmd.d +++ b/tools/pipedmd.d @@ -71,12 +71,16 @@ string eatArg(string cmd) version(pipeLink) { + import core.stdc.stdlib : getenv; extern(C) int putenv(const char*); int main(string[] argv) { + const(char)* p = getenv("dbuild_LinkToolExe"); + string link = p ? fromMBSz(cast(immutable)p) : "link.exe"; + // printf("pipelink called with: dbuild_LinkToolExe=%s\n", p); string cmd = to!string(GetCommandLineW()); //printf("pipelink called with: %.*s\n", cast(int)cmd.length, cmd.ptr); - cmd = "link.exe" ~ eatArg(cmd); + cmd = link ~ eatArg(cmd); putenv("VS_UNICODE_OUTPUT="); // disable unicode output for link.exe int exitCode = runProcess(cmd, null, true, true, false, true, false); return exitCode; @@ -155,11 +159,12 @@ int main(string[] argv) string fullexe = findExeInPath(exe); bool isX64 = isExe64bit(fullexe); if (verbose) + { if (fullexe.empty) printf ("%.*s not found in PATH, assuming %d-bit application\n", exe.length, exe.ptr, isX64 ? 64 : 32); else printf ("%.*s is a %d-bit application\n", fullexe.length, fullexe.ptr, isX64 ? 64 : 32); - + } string trackerArgs; string tracker = findTracker(isX64, trackerArgs); if (tracker.length > 0) diff --git a/tools/tracegc.d b/tools/tracegc.d new file mode 100644 index 00000000..07d8908f --- /dev/null +++ b/tools/tracegc.d @@ -0,0 +1,1299 @@ +module tracegc; + +import core.stdc.string; +import core.time; +import core.stdc.stdio; + +//version = traceGC; + +// tiny helper to clear a page of the stack below the current stack pointer to avoid false pointers there +void wipeStack() +{ + char[4096] data = void; + memset (data.ptr, 0xff, 4096); +} + +version(traceGC) { +import core.sys.windows.windows; +import gc.impl.conservative.gc; +import core.thread; + +extern(C) alias _CRT_ALLOC_HOOK = int function(int, void *, size_t, int, long, const(char) *, int); + +extern(C) _CRT_ALLOC_HOOK _CrtSetAllocHook(_CRT_ALLOC_HOOK _PfnNewHook); + +__gshared _CRT_ALLOC_HOOK _prevHook; + +extern(C) int _CRT_allocHook(int op, void *p, size_t size, int nBlockUse, long lRequest, const(char) *filename, int line) +{ + import core.sys.windows.stacktrace; + + if (!filename && op == 1) // alloc hook + { + if (StackAddrInfo* ai = traceAndResolve(4)) + { + filename = stringBuffer.ptr + ai.filenameOff; + line = ai.line; + + version(Win64) + { + // tweaked to the VC2013 debug runtime + const(char)** patchFilename = &filename + 11; + *patchFilename = filename; + + int* patchLine = &line + 22; + *patchLine = line; + } + } + } + if (_prevHook) + return _prevHook(op, p, size, nBlockUse, lRequest, filename, line); + return 1; +} + +extern(Windows) void OutputDebugStringA(LPCSTR) nothrow; + +alias RtlCaptureStackBackTraceFunc = extern(Windows) USHORT function(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) nothrow; + +private __gshared RtlCaptureStackBackTraceFunc RtlCaptureStackBackTrace; + +extern(Windows) USHORT NoCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash) nothrow +{ + return 0; +} + +void initRtlCaptureStackBackTrace() +{ + if (RtlCaptureStackBackTrace is null) + { + RtlCaptureStackBackTrace = &NoCaptureStackBackTrace; + + import core.sys.windows.dbghelp; + auto dbghelp = DbgHelp.get(); + if(dbghelp is null) + return; // dbghelp.dll not available + + if (auto kernel32Handle = LoadLibraryA("kernel32.dll")) + RtlCaptureStackBackTrace = cast(RtlCaptureStackBackTraceFunc) GetProcAddress(kernel32Handle, "RtlCaptureStackBackTrace"); + + HANDLE hProcess = GetCurrentProcess(); + + DWORD symOptions = dbghelp.SymGetOptions(); + symOptions |= SYMOPT_LOAD_LINES; + symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; + symOptions |= SYMOPT_DEFERRED_LOAD; + symOptions = dbghelp.SymSetOptions( symOptions ); + + debug(PRINTF) printf("Search paths: %s\n", generateSearchPath().ptr); + + if (!dbghelp.SymInitialize(hProcess, null, TRUE)) + return; + + //dbghelp.SymRegisterCallback64(hProcess, &FixupDebugHeader, 0); + } +} + +StackAddrInfo* traceAndResolve(size_t skip) +{ + initRtlCaptureStackBackTrace(); + + size_t[63] buffer = void; // On windows xp the sum of "frames to skip" and "frames to capture" can't be greater then 63 + auto backtraceLength = RtlCaptureStackBackTrace(cast(ULONG)skip, cast(ULONG)(buffer.length - skip), cast(void**)buffer.ptr, null); + + for (size_t p = 0; p < backtraceLength; p++) + { + StackAddrInfo* ai = resolveAddr(buffer[p]); + if (ai.line != uint.max) + return ai; + } + return null; +} + +void initTraceMalloc() +{ + version(CRuntime_Microsoft) + _prevHook = _CrtSetAllocHook(&_CRT_allocHook); +} + +__gshared char[1 << 20] stringBuffer; +__gshared size_t stringBufferPos; + +uint findOrAddString(const char* str) +{ + size_t len = strlen(str); + uint p = 0; + while (p < stringBufferPos) + { + size_t plen = strlen(stringBuffer.ptr + p); + if (plen == len && strcmp (stringBuffer.ptr + p, str) == 0) + return p; + p += plen + 1; + } + + stringBufferPos += len + 1; + assert(stringBufferPos <= stringBuffer.length); + + stringBuffer[p .. stringBufferPos] = str[0 .. len + 1]; + return p; +} + +struct StackAddrInfo +{ + size_t pc; + uint filenameOff; + uint line; +} + +__gshared StackAddrInfo[1 << 16] addrInfo; +__gshared size_t addrInfoPos; + +StackAddrInfo* findOrAddAddr(size_t pc) nothrow +{ + for (size_t p = 0; p < addrInfoPos; p++) + if (addrInfo[p].pc == pc) + return addrInfo.ptr + p; + assert(addrInfoPos < addrInfo.length); + addrInfo[addrInfoPos].pc = pc; + return addrInfo.ptr + addrInfoPos++; +} + +StackAddrInfo* resolveAddr(size_t pc) nothrow +{ + StackAddrInfo* ai = findOrAddAddr(pc); + if (ai.line) + return ai; + + ai.line = uint.max; + + try + { + import core.sys.windows.dbghelp; + auto dbghelp = DbgHelp.get(); + assert(dbghelp); + + HANDLE hProcess = GetCurrentProcess(); + + DWORD disp; + IMAGEHLP_LINEA64 line = void; + line.SizeOfStruct = IMAGEHLP_LINEA64.sizeof; + + if (dbghelp.SymGetLineFromAddr64(hProcess, pc, &disp, &line)) + { + if (validFilename(line.FileName)) + { + ai.filenameOff = findOrAddString(line.FileName); + ai.line = line.LineNumber > 0 ? line.LineNumber : 1; + } + } + } + catch(Exception) + { + } + return ai; +} + +bool validFilename(const(char)* fn) +{ + if (!fn || fn[0] == 'f') + return false; + + size_t flen = strlen(fn); + static immutable string[] excl = + [ + r"\object.d", + r"\rt\lifetime.d", + r"\rt\aaA.d", + r"\rt\util\container\common.d", + r"\rt\util\container\treap.d", + r"\gc\proxy.d", + r"\core\memory.d", + r"\std\array.d", + r"\dmd\root\rmem.d", + r"\dmd\root\array.d", + r"\dmd\root\aav.d", + r"\dmd\root\outbuffer.d", + r"\dmd\root\stringtable.d", + r"\stdext\com.d", + r"\ddmdrmem.d", + ]; + foreach (ex; excl) + if (flen > ex.length && fn[flen - ex.length .. flen] == ex) + return false; + + return true; +} + +//////////////////////////////////////////////////////////// + +import core.gc.gcinterface; +import core.gc.registry; +import gc.os; +import core.exception; + +extern (C) pragma(crt_constructor) void register_tracegc() +{ + registerGCFactory("trace", &GCTraceProxy.initialize); +} + +class GCTraceProxy : GC +{ + GC gc; + + static GC initialize() + { + __gshared ubyte[__traits(classInstanceSize, GCTraceProxy)] buf; + + initRtlCaptureStackBackTrace(); + // initTraceMalloc(); + + auto init = typeid(GCTraceProxy).initializer(); + assert(init.length == buf.length); + auto instance = cast(GCTraceProxy) memcpy(buf.ptr, init.ptr, init.length); + instance.__ctor(); + return instance; + } + + this() + { + // unfortunately, registry cannot be invoked twice, and + // initialize for ConservativeGC is private + __gshared ubyte[__traits(classInstanceSize, ConservativeGC)] buf; + + ConservativeGC.isPrecise = true; + auto init = typeid(ConservativeGC).initializer(); + assert(init.length == __traits(classInstanceSize, ConservativeGC)); + auto instance = cast(ConservativeGC) memcpy(buf.ptr, init.ptr, init.length); + instance.__ctor(); + + gc = instance; + tracer = this; + } + + ~this() + { + destroy(gc); + } + + void enable() + { + gc.enable(); + } + + void disable() + { + gc.disable(); + } + + void collect() nothrow + { + gc.collect(); + } + + void collectNoStack() nothrow + { + gc.collectNoStack(); + } + + void minimize() nothrow + { + gc.minimize(); + } + + uint getAttr(void* p) nothrow + { + return gc.getAttr(p); + } + + uint setAttr(void* p, uint mask) nothrow + { + return gc.setAttr(p, mask); + } + + uint clrAttr(void* p, uint mask) nothrow + { + return gc.clrAttr(p, mask); + } + + void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow + { + void* p = gc.malloc(size, bits, ti); + traceAlloc(p); + return p; + } + + BlkInfo qalloc(size_t size, uint bits, const TypeInfo ti) nothrow + { + BlkInfo bi = gc.qalloc(size, bits, ti); + traceAlloc(bi.base); + return bi; + } + + void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow + { + void* p = gc.calloc(size, bits, ti); + traceAlloc(p); + return p; + } + + void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow + { + void* q = gc.realloc(p, size, bits, ti); + traceAlloc(q); + return q; + } + + size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow + { + return gc.extend(p, minsize, maxsize, ti); + } + + size_t reserve(size_t size) nothrow + { + return gc.reserve(size); + } + + void free(void* p) nothrow + { + gc.free(p); + } + + void* addrOf(void* p) nothrow + { + return gc.addrOf(p); + } + + size_t sizeOf(void* p) nothrow + { + return gc.sizeOf(p); + } + + BlkInfo query(void* p) nothrow + { + return gc.query(p); + } + + core.memory.GC.Stats stats() nothrow + { + return gc.stats(); + } + + core.memory.GC.ProfileStats profileStats() nothrow + { + return gc.profileStats(); + } + + void addRoot(void* p) nothrow @nogc + { + return gc.addRoot(p); + } + + void removeRoot(void* p) nothrow @nogc + { + return gc.removeRoot(p); + } + + @property RootIterator rootIter() @nogc + { + return gc.rootIter(); + } + + void addRange(void* p, size_t sz, const TypeInfo ti) nothrow @nogc + { + return gc.addRange(p, sz, ti); + } + + void removeRange(void* p) nothrow @nogc + { + return gc.removeRange(p); + } + + @property RangeIterator rangeIter() @nogc + { + return gc.rangeIter(); + } + + //static if (__VERSION__ >= 2087) + void runFinalizers(scope const void[] segment) nothrow + { + return gc.runFinalizers(segment); + } + //else + void runFinalizers(in void[] segment) nothrow + { + return gc.runFinalizers(segment); + } + + bool inFinalizer() nothrow + { + return gc.inFinalizer(); + } + + TraceBuffer traceBuffer; +} + +/////////////////////////////////////////////////////////// +static struct TraceEntry +{ + enum eagerResolve = true; + + void* addr; + static if (eagerResolve) + { + StackAddrInfo* ai; + + StackAddrInfo* resolve() nothrow { return ai; } + } + else + { + size_t[15] buffer; + + StackAddrInfo* resolve() nothrow { return _resolve(buffer[]); } + } + + void initialize(void* addr, ref size_t[15] buf) nothrow + { + this.addr = addr; + static if (eagerResolve) + ai = _resolve(buf[]); + else + buffer[] = buf[]; + } + + StackAddrInfo* _resolve(size_t[] buf) nothrow + { + for (size_t sp = 0; sp < buf.length && buf[sp]; sp++) + { + StackAddrInfo* ai = resolveAddr(buf[sp]); + if (ai.line != uint.max) + return ai; + } + return null; + } +} + +static struct Range +{ + TraceEntry* _entries; + size_t _length; + size_t _capacity; +} + +static struct AddrTracePair +{ + void* addr; + TraceEntry* entry; +} + +size_t addrHash(void* addr, size_t mask) nothrow +{ + size_t hash = cast(size_t)addr; + hash = (hash >> 4) ^ (hash >> 20) ^ (hash >> 30); + return hash & mask; +} + +static struct TraceBuffer +{ +nothrow: + void reset() + { + _length = 0; + os_mem_unmap(_p, _cap * Range.sizeof); + _p = null; + _cap = 0; + } + + void pushEntry(ref TraceEntry te) + { + if (!_length || _p[_length-1]._length >= _p[_length-1]._capacity) + newRange(); + + _p[_length-1]._entries[_p[_length-1]._length++] = te; + } + + TraceEntry* findTraceEntry(void* addr) + { + foreach_reverse (ref rng; _p[0.._length]) + foreach_reverse (ref te; rng._entries[0..rng._length]) + if (te.addr == addr) + return &te; + return null; + } + + AddrTracePair[] createTraceMap() + { + size_t n = numEntries(); + if (!n) + return null; + // next or same power of 2 + while (n & (n - 1)) + n += (n & -n); // add lowest bit + n = n + n; + auto arr = cast(AddrTracePair*)os_mem_map(n * AddrTracePair.sizeof); + if (!arr) + onOutOfMemoryErrorNoGC(); + memset(arr, 0, n * AddrTracePair.sizeof); + + foreach_reverse (ref rng; _p[0.._length]) + foreach_reverse (ref te; rng._entries[0..rng._length]) + { + // insert with quadratic probing + size_t k = addrHash(te.addr, n - 1); + for (size_t j = 1; arr[k].addr !is te.addr; j++) + { + if (arr[k].addr is null) + { + arr[k].addr = te.addr; + arr[k].entry = &te; + break; + } + k = (k + j) & (n - 1); + } + } + return arr[0..n]; + } + + void deleteTraceMap(AddrTracePair[] arr) + { + if (arr.ptr) + os_mem_unmap(arr.ptr, arr.length * AddrTracePair.sizeof); + } + + TraceEntry* findTraceEntry(AddrTracePair[] arr, void* addr) + { + // search with quadratic probing + size_t k = addrHash(addr, arr.length - 1); + size_t j = 1; + while (arr[k].addr != addr) + { + if (arr[k].addr is null) + return null; + k = (k + j) & (arr.length - 1); + j++; + } + return arr[k].entry; + } + + void newRange() + { + if (_length == _cap) + grow(); + + enum entriesPerRange = 64 * 1024; // Windows VirtualAlloc granularity + _p[_length]._entries = cast(TraceEntry*)os_mem_map(entriesPerRange * TraceEntry.sizeof); + _p[_length]._capacity = entriesPerRange; + _p[_length]._length = 0; + if (_p[_length]._entries is null) + onOutOfMemoryErrorNoGC(); + _length++; + } + + size_t numEntries() + { + size_t sum = 0; + for (size_t r = 0; r < _length; r++) + sum += _p[r]._length; + return sum; + } + + size_t memUsage() + { + size_t sum = _cap * Range.sizeof; + for (size_t r = 0; r < _length; r++) + sum += _p[r]._capacity * TraceEntry.sizeof; + return sum; + } + +private: + void grow() + { + enum initSize = 64 * 1024; // Windows VirtualAlloc granularity + immutable ncap = _cap ? 2 * _cap : initSize / Range.sizeof; + auto p = cast(Range*)os_mem_map(ncap * Range.sizeof); + if (p is null) + onOutOfMemoryErrorNoGC(); + + p[0 .. _length] = _p[0 .. _length]; + os_mem_unmap(_p, _cap * Range.sizeof); + + _p = p; + _cap = ncap; + } + + size_t _length; + Range* _p; + size_t _cap; +} + +__gshared GCTraceProxy tracer; + +/+ +import core.demangle; +extern pragma(mangle, mangle!GC("gc.proxy.instance")) __gshared GC gc_instance; + +__gshared GCTraceProxy tracer = new GCTraceProxy; + +extern(C) void gc_init() +{ + import core.gc.config; + + config.initialize(); + ConservativeGC.initialize(gc_instance); + insertGCTracer(); + thread_init(); +} + +extern(C) void gc_term() +{ + //gc_instance.collectNoStack(); // not really a 'collect all' -- still scans static data area, roots, and ranges. + + thread_term(); + removeGCTracer(); + ConservativeGC.finalize(gc_instance); +} + +void insertGCTracer() +{ + initRtlCaptureStackBackTrace(); + + tracer.gc = gc_instance; + gc_instance = tracer; +} + +void removeGCTracer() +{ + gc_instance = tracer.gc; +} ++/ + +void traceAlloc(void* addr) nothrow +{ + size_t[15] buf; + + auto backtraceLength = RtlCaptureStackBackTrace(2, cast(ULONG)buf.length, cast(void**)buf.ptr, null); + + TraceEntry te; + te.initialize(addr, buf); + + tracer.traceBuffer.pushEntry(te); +} + +extern(C) void dumpGC() +{ + dumpGC(tracer.gc); +} + +void dumpAddr(AddrTracePair[] traceMap, void* addr, size_t size) +{ + char[256] buf; + + const(char)* filename; + int line; + if (auto te = tracer.traceBuffer.findTraceEntry(traceMap, addr)) + { + if (auto ai = te.resolve()) + { + filename = stringBuffer.ptr + ai.filenameOff; + line = ai.line; + addAddrInfoStat(ai, size); + } + else + filename = ": "; + } + else + filename = ": "; + + trace_printf("%s(%d): %p %llx\n", filename, line, addr, cast(long) size); +} + +struct AddrInfoStat +{ + @property ai() const nothrow { return cast(StackAddrInfo*) _ai; } + size_t _ai; // pretend it is not a pointer + size_t count; + size_t size; +} + +__gshared AddrInfoStat[1 << 13] addrInfoStat; + +void addAddrInfoStat(StackAddrInfo* ai, size_t size) +{ + // search with quadratic probing + size_t k = addrHash(ai, addrInfoStat.length - 1); + size_t j = 1; + while (addrInfoStat[k].ai != ai) + { + if (addrInfoStat[k].ai is null) + { + addrInfoStat[k]._ai = cast(size_t)ai; + addrInfoStat[k].count = 1; + addrInfoStat[k].size = size; + return; + } + k = (k + j) & (addrInfoStat.length - 1); + j++; + } + addrInfoStat[k].count++; + addrInfoStat[k].size += size; +} + +void dumpAddrInfoStat() +{ + char[256] buf; + + trace_printf("\nDump combined by stack location:\n"); + + foreach(ref info; addrInfoStat) + if (info.ai) + { + const(char)* filename = stringBuffer.ptr + info.ai.filenameOff; + trace_printf("%s(%d): %lld allocs %llx bytes\n", filename, info.ai.line, cast(long)info.count, cast(long)info.size); + } + + trace_printf("\n"); +} + +HashTab!(void*, void*)**pp_references; + +/////////////////////////////////////////////////////////////// +import rt.util.container.hashtab; + +alias ScanRange = Gcx.ScanRange!false; +Gcx.ToScanStack!ScanRange toscan; // dmd BUG: alignment causes bad capture! + +void collectReferences(ConservativeGC cgc, ref HashTab!(void*, void*) references, ref HashTab!(void*, size_t) objects) +{ + auto gcx = cgc.gcx; + + cgc.gcLock.lock(); + auto pooltable = gcx.pooltable; + + /** + * Search a range of memory values and mark any pointers into the GC pool. + */ + void mark(void *pbot, void *ptop) scope nothrow + { + void **p1 = cast(void **)pbot; + void **p2 = cast(void **)ptop; + + // limit the amount of ranges added to the toscan stack + enum FANOUT_LIMIT = 32; + size_t stackPos; + ScanRange[FANOUT_LIMIT] stack = void; + + import core.stdc.stdlib; + if (&references != *pp_references) + exit(1); + + Lagain: + size_t pcache = 0; + + // let dmd allocate a register for this.pools + const minAddr = pooltable.minAddr; + const maxAddr = pooltable.maxAddr; + + //printf("marking range: [%p..%p] (%#zx)\n", p1, p2, cast(size_t)p2 - cast(size_t)p1); + Lnext: + for (; p1 < p2; p1++) + { + auto p = *p1; + + //if (log) debug(PRINTF) printf("\tmark %p\n", p); + if (p >= minAddr && p < maxAddr) + { + if ((cast(size_t)p & ~cast(size_t)(PAGESIZE-1)) == pcache) + continue; + + Pool* pool = pooltable.findPool(p); + if (!pool) + continue; + + size_t offset = cast(size_t)(p - pool.baseAddr); + size_t biti = void; + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + void* base = void; + + //debug(PRINTF) printf("\t\tfound pool %p, base=%p, pn = %zd, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti); + + // Adjust bit to be at start of allocated memory block + if (bin < B_PAGE) + { + // We don't care abou setting pointsToBase correctly + // because it's ignored for small object pools anyhow. + auto offsetBase = baseOffset(offset, cast(Bins)bin); + biti = offsetBase >> pool.shiftBy; + base = pool.baseAddr + offsetBase; + //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); + + if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { + references[base] = p1; + objects[base] = binsize[bin]; + debug(COLLECT_PRINTF) printf("\t\tmark %p -> %p, off=%p\n", p1, base, p - base); + stack[stackPos++] = ScanRange(base, base + binsize[bin]); + if (stackPos == stack.length) + break; + } + } + else if (bin == B_PAGE) + { + auto offsetBase = offset & ~cast(size_t)(PAGESIZE-1); + base = pool.baseAddr + offsetBase; + biti = offsetBase >> pool.shiftBy; + //debug(PRINTF) printf("\t\tbiti = x%x\n", biti); + + pcache = cast(size_t)p & ~cast(size_t)(PAGESIZE-1); + + // For the NO_INTERIOR attribute. This tracks whether + // the pointer is an interior pointer or points to the + // base address of a block. + bool pointsToBase = (base == sentinel_sub(p)); + if(!pointsToBase && pool.nointerior.nbits && pool.nointerior.test(biti)) + continue; + + if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { + references[base] = p1; + objects[base] = pool.bPageOffsets[pn] * PAGESIZE; + debug(COLLECT_PRINTF) printf("\t\tmark %p -> %p, off=%p\n", p1, base, p - base); + stack[stackPos++] = ScanRange(base, base + pool.bPageOffsets[pn] * PAGESIZE); + if (stackPos == stack.length) + break; + } + } + else if (bin == B_PAGEPLUS) + { + pn -= pool.bPageOffsets[pn]; + base = pool.baseAddr + (pn * PAGESIZE); + biti = pn * (PAGESIZE >> pool.shiftBy); + + pcache = cast(size_t)p & ~cast(size_t)(PAGESIZE-1); + if(pool.nointerior.nbits && pool.nointerior.test(biti)) + continue; + + if (!pool.mark.set(biti) && !pool.noscan.test(biti)) { + references[base] = p1; + objects[base] = pool.bPageOffsets[pn] * PAGESIZE; + debug(COLLECT_PRINTF) printf("\t\tmark %p -> %p, off=%p\n", p1, base, p - base); + stack[stackPos++] = ScanRange(base, base + pool.bPageOffsets[pn] * PAGESIZE); + if (stackPos == stack.length) + break; + } + } + else + { + // Don't mark bits in B_FREE pages + assert(bin == B_FREE); + continue; + } + } + } + + ScanRange next=void; + if (p1 < p2) + { + // local stack is full, push it to the global stack + assert(stackPos == stack.length); + toscan.push(ScanRange(p1, p2)); + // reverse order for depth-first-order traversal + foreach_reverse (ref rng; stack[0 .. $ - 1]) + toscan.push(rng); + stackPos = 0; + next = stack[$-1]; + } + else if (stackPos) + { + // pop range from local stack and recurse + next = stack[--stackPos]; + } + else if (!toscan.empty) + { + // pop range from global stack and recurse + next = toscan.pop(); + } + else + { + // nothing more to do + return; + } + p1 = cast(void**)next.pbot; + p2 = cast(void**)next.ptop; + // printf(" pop [%p..%p] (%#zx)\n", p1, p2, cast(size_t)p2 - cast(size_t)p1); + goto Lagain; + } + + thread_suspendAll(); + gcx.prepare(); // set freebits + + foreach(root; cgc.rootIter) + mark(&root, &root + 1); + foreach(range; cgc.rangeIter) + mark(range.pbot, range.ptop); + + //thread_scanAll(&mark); + thread_resumeAll(); + + cgc.gcLock.unlock(); +} + +/////////////////////////////////////////////////////////////// +void dumpGC(GC _gc) +{ + auto cgc = cast(ConservativeGC) _gc; + assert(cgc); + auto gcx = cgc.gcx; + + core.memory.GC.Stats stats = _gc.stats(); + + cgc.gcLock.lock(); + + trace_printf("Dump of GC %p: %d pools\n", _gc, gcx.pooltable.length); + trace_printf("Trace buffer memory: %lld bytes\n", cast(long)tracer.traceBuffer.memUsage()); + + trace_printf("GC stats: %lld used, %lld free\n", cast(long)stats.usedSize, cast(long)stats.freeSize); + + AddrTracePair[] traceMap = tracer.traceBuffer.createTraceMap(); + memset(addrInfoStat.ptr, 0, addrInfoStat.sizeof); + + thread_suspendAll(); + gcx.prepare(); // set freebits + + void dumpObjectAddrs() scope + { + size_t usedSize = 0; + size_t freeSize = 0; + foreach (pool; gcx.pooltable[0 .. gcx.pooltable.length]) + { + foreach (pn, bin; pool.pagetable[0 .. pool.npages]) + { + if (bin == B_PAGE) + { + auto lpool = cast(LargeObjectPool*) pool; + size_t npages = lpool.bPageOffsets[pn]; + + void* addr = sentinel_add(pool.baseAddr + pn * PAGESIZE); + dumpAddr(traceMap, addr, npages * PAGESIZE); + usedSize += npages * PAGESIZE; + } + else if (bin == B_FREE) + { + freeSize += PAGESIZE; + } + else if (bin < B_PAGE) + { + immutable size = binsize[bin]; + void *p = pool.baseAddr + pn * PAGESIZE; + void *ptop = p + PAGESIZE; + immutable base = pn * (PAGESIZE/16); + immutable bitstride = size / 16; + + for (size_t i; p < ptop; p += size, i += bitstride) + { + immutable biti = base + i; + + if (!pool.freebits.test(biti)) + { + void* addr = sentinel_add(p); + dumpAddr(traceMap, addr, size); + usedSize += size; + } + else + freeSize += size; + } + } + } + } + + trace_printf("Sum of used memory: %lld bytes\n", cast(long)usedSize); + trace_printf("Sum of free memory: %lld bytes\n", cast(long)freeSize); + } + + dumpObjectAddrs(); + dumpAddrInfoStat(); + + foreach(root; _gc.rootIter) + { + if (auto te = tracer.traceBuffer.findTraceEntry(traceMap, root)) + { + if (StackAddrInfo* ai = te.resolve()) + { + const(char)* filename = stringBuffer.ptr + ai.filenameOff; + trace_printf("%s(%d): root %p\n", filename, ai.line, root); + } + else + trace_printf(": root %p\n", root); + } + else + trace_printf(": root %p\n", root); + } + + void dumpRange(void *pbot, void *ptop) scope nothrow + { + bool rangeShown = false; + for (void** p = cast(void**) pbot; p < ptop; p++) + { + void* root = *p; + if (root < gcx.pooltable.minAddr || root >= gcx.pooltable.maxAddr) + continue; + + Pool* pool = gcx.pooltable.findPool(root); + if (!pool) + continue; + + size_t offset = cast(size_t)(root - pool.baseAddr); + size_t biti = void; + size_t pn = offset / PAGESIZE; + Bins bin = cast(Bins)pool.pagetable[pn]; + void* base = void; + + if (bin < B_PAGE) + { + auto offsetBase = baseOffset(offset, cast(Bins)bin); + base = pool.baseAddr + offsetBase; + biti = offsetBase >> pool.shiftBy; + if (pool.freebits.test(biti)) + continue; + } + else if (bin == B_PAGE) + { + auto offsetBase = offset & ~cast(size_t)(PAGESIZE-1); + base = pool.baseAddr + offsetBase; + } + else if (bin == B_PAGEPLUS) + { + pn -= pool.bPageOffsets[pn]; + base = pool.baseAddr + (pn * PAGESIZE); + } + else + continue; // B_FREE + + if (!rangeShown) + { + trace_printf("within range %p - %p:\n", pbot, ptop); + rangeShown = true; + } + + if (auto te = tracer.traceBuffer.findTraceEntry(traceMap, base)) + { + if (StackAddrInfo* ai = te.resolve()) + { + const(char)* filename = stringBuffer.ptr + ai.filenameOff; + trace_printf("%s(%d): @range+%llx %p", filename, ai.line, cast(long)(cast(void*)p - pbot), root); + } + else + trace_printf(": @range+%llx %p", cast(long)(cast(void*)p - pbot), root); + } + else + { + trace_printf(": @range+%llx %p", cast(long)(cast(void*)p - pbot), root); + } + + if (root != base) + trace_printf(" base %p\n", base); + else + trace_printf("\n"); + } + } + foreach(range; _gc.rangeIter) + { + dumpRange(range.pbot, range.ptop); + } + + wipeStack(); // remove anything that might be left by iterating through the GC + thread_scanAll(&dumpRange); + + tracer.traceBuffer.deleteTraceMap(traceMap); + thread_resumeAll(); + + cgc.gcLock.unlock(); + + findRoot(null); +} + +shared static this() +{ + import dmd.identifier; + Identifier.anonymous(); +} + +const(char)[] dmdident(ConservativeGC cgc, void* p) +{ + import dmd.dsymbol; + import dmd.identifier; + + BlkInfo inf = cgc.queryNoSync(p); + if (inf.base is null || inf.size < Dsymbol.sizeof) + return null; + + auto dummyIdent = Identifier.anonymous(); + auto sym = cast(Dsymbol)p; + auto ident = sym.ident; + if (!ident) + return null; + BlkInfo syminf = cgc.queryNoSync(cast(void*)ident); + if (syminf.base is null || syminf.size < Identifier.sizeof) + return null; + if (*cast(void**)dummyIdent !is *cast(void**)ident) + return null; // not an Identifier + + __gshared char[256] buf; + int len = sprintf(buf.ptr, "sym %.*s", ident.toString().length, ident.toString().ptr); + return buf[0..len]; +} + +bool isInImage(void* p) +{ + import core.internal.traits : externDFunc; + alias findImageSection = externDFunc!("rt.sections_win64.findImageSection", void[] function(string) nothrow @nogc); + void[] dataSection = findImageSection(".data"); + + if (p - dataSection.ptr < dataSection.length) + return true; + return false; +} + +const(char)[] dmdtype(ConservativeGC cgc, void* p) +{ + import dmd.mtype; + import dmd.identifier; + + BlkInfo inf = cgc.queryNoSync(p); + if (inf.base is null || inf.size < Type.sizeof) + return null; + + auto vtbl = *cast(void***)p; + if (!isInImage(vtbl)) + return null; + auto func = vtbl[5]; + Type type = cast(Type)p; + if (func != (&type.dyncast).funcptr) + return null; + + __gshared char[256] buf; + int len = sprintf(buf.ptr, "type %s %s", type.kind(), type.deco); + return buf[0..len]; +} + +void findRoot(void* sobj) +{ + //sobj = cast(void*)1; + if (!sobj) + return; + + auto cgc = cast(ConservativeGC) tracer.gc; + assert(cgc); + + HashTab!(void*, void*) references; + HashTab!(void*, size_t) objects; + + HashTab!(void*, void*)* preferences = &references; + pp_references = &preferences; + + collectReferences(cgc, references, objects); + + const(void*) minAddr = cgc.gcx.pooltable.minAddr; + const(void*) maxAddr = cgc.gcx.pooltable.maxAddr; + + import core.sys.windows.dbghelp; + auto dbghelp = DbgHelp.get(); + HANDLE hProcess = GetCurrentProcess(); + + char[256] buf; +nextLoc: + for ( ; ; ) + { + TraceEntry* te = tracer.traceBuffer.findTraceEntry(sobj); + StackAddrInfo* ai; + if (te && (ai = te.resolve()) !is null) + { + const(char)* filename = stringBuffer.ptr + ai.filenameOff; + auto id = dmdident(cgc, sobj); + if (!id) + id = dmdtype(cgc, sobj); + xtrace_printf("%s(%d): %p %.*s\n", filename, ai.line, sobj, id.length, id.ptr); + } + else + xtrace_printf("no location: %p\n", sobj); + + ulong src; + if (auto psrc = sobj in references) + { + BlkInfo info = cgc.queryNoSync(*psrc); + if (info.base) + { + sobj = info.base; + continue nextLoc; + } + + for (void* base = *psrc; base >= minAddr && base <= maxAddr; ) + { + if (auto pobj = base in objects) + { + if (*psrc < base + *pobj) + { + sobj = base; + continue nextLoc; + } + } + auto ubase = cast(size_t)base; + if (ubase & 0xfff) + base = cast(void*)(ubase ^ (ubase & -ubase)); // clear lowest bit + else + base -= 0x1000; + } + xtrace_printf("%p not a heap object\n", *psrc); + + DWORD64 disp; + char[300] symbuf; + auto sym = cast(IMAGEHLP_SYMBOLA64*) symbuf.ptr; + sym.SizeOfStruct = IMAGEHLP_SYMBOLA64.sizeof; + sym.MaxNameLength = 300 - IMAGEHLP_SYMBOLA64.sizeof; + + if (dbghelp.SymGetSymFromAddr64(hProcess, cast(size_t)*psrc, &disp, sym)) + xtrace_printf(" sym %s + %lld\n", sym.Name.ptr, disp); + } + break; + } +} + +} // version(traceGC) + +//////////////////////////////////////////////////////////////// +private __gshared MonoTime gcStartTick; +private __gshared FILE* gcx_fh; +private __gshared bool hadNewline = false; + +int trace_printf(ARGS...)(const char* fmt, ARGS args) nothrow +{ + if (!gcx_fh) + gcx_fh = fopen("tracegc.log", "w"); + if (!gcx_fh) + return 0; + + int len; + if (MonoTime.ticksPerSecond == 0) + { + len = fprintf(gcx_fh, "before init: "); + } + else if (hadNewline) + { + if (gcStartTick == MonoTime.init) + gcStartTick = MonoTime.currTime; + immutable timeElapsed = MonoTime.currTime - gcStartTick; + immutable secondsAsDouble = timeElapsed.total!"hnsecs" / cast(double)convert!("seconds", "hnsecs")(1); + len = fprintf(gcx_fh, "%10.6lf: ", secondsAsDouble); + } + len += fprintf(gcx_fh, fmt, args); + fflush(gcx_fh); + import core.stdc.string; + hadNewline = fmt && fmt[0] && fmt[strlen(fmt) - 1] == '\n'; + return len; +} + +int xtrace_printf(ARGS...)(const char* fmt, ARGS args) nothrow +{ + char[1024] buf; + sprintf(buf.ptr, fmt, args); + OutputDebugStringA(buf.ptr); + + return trace_printf(fmt, args); +} + diff --git a/vdc/abothe/Parser b/vdc/abothe/Parser index 74f7f224..0cdef0ec 160000 --- a/vdc/abothe/Parser +++ b/vdc/abothe/Parser @@ -1 +1 @@ -Subproject commit 74f7f224f394cdf865b8405bdd54e0159a56e5a4 +Subproject commit 0cdef0ec17ddf955f348403a4c81c907e30e1052 diff --git a/vdc/abothe/VDServer.sln b/vdc/abothe/VDServer.sln index 6c7fe83a..bf70e853 100644 --- a/vdc/abothe/VDServer.sln +++ b/vdc/abothe/VDServer.sln @@ -70,7 +70,4 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {62BBA23E-674A-4160-8500-54A307388C95} EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = vdcomserver\vdcomserver.csproj - EndGlobalSection EndGlobal diff --git a/vdc/abothe/comserver/COM/ExeCOMServer.cs b/vdc/abothe/comserver/COM/ExeCOMServer.cs index 5162891f..af7f8b51 100644 --- a/vdc/abothe/comserver/COM/ExeCOMServer.cs +++ b/vdc/abothe/comserver/COM/ExeCOMServer.cs @@ -68,7 +68,7 @@ private void PreMessageLoop() // Register the SimpleObject class object int hResult = COMNative.CoRegisterClassObject(ref clsid, new VDServerClassFactory(), - CLSCTX.LOCAL_SERVER, REGCLS.MULTIPLEUSE | REGCLS.SUSPENDED, + CLSCTX.LOCAL_SERVER, REGCLS.SINGLEUSE | REGCLS.SUSPENDED, out _cookie); if (hResult != 0) { diff --git a/vdc/abothe/comserver/CodeSemantics/TooltipGenerator.cs b/vdc/abothe/comserver/CodeSemantics/TooltipGenerator.cs index 57a40fab..878c4aac 100644 --- a/vdc/abothe/comserver/CodeSemantics/TooltipGenerator.cs +++ b/vdc/abothe/comserver/CodeSemantics/TooltipGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; using D_Parser.Completion; using D_Parser.Dom; @@ -10,85 +11,118 @@ namespace DParserCOMServer.CodeSemantics { public class TooltipGenerator - : AbstractVDServerTask, bool> + : AbstractVDServerTask, int> { public TooltipGenerator(VDServer vdServer, EditorDataProvider editorDataProvider) : base(vdServer, editorDataProvider) { } - protected override Tuple Process( - EditorData editorData, bool evaluateUnderneathExpression) + protected override Tuple Process(EditorData editorData, int flags) { - // codeOffset+1 because otherwise it does not work on the first character - editorData.CaretOffset++; + bool evaluateUnderneathExpression = (flags & 1) != 0; + bool quoteCode = (flags & 2) != 0; + bool overloads = (flags & 4) != 0; + + // codeOffset+1 because otherwise it does not work on the first character + // editorData.CaretOffset++; var sr = DResolver.GetScopedCodeObject(editorData); if (sr == null) return Tuple.Create(CodeLocation.Empty, CodeLocation.Empty, String.Empty); - var types = LooseResolution.ResolveTypeLoosely(editorData, sr, out _, true); - + ArgumentsResolutionResult res = null; + if (overloads) + { + res = ParameterInsightResolution.ResolveArgumentContext(editorData); + } + else + { + var types = LooseResolution.ResolveTypeLoosely(editorData, sr, out _, true); + if (types != null) + { + res = new ArgumentsResolutionResult(); + res.ResolvedTypesOrMethods = new AbstractType[1] { types }; + } + } + if (editorData.CancelToken.IsCancellationRequested) return Tuple.Create(CodeLocation.Empty, CodeLocation.Empty, String.Empty); - if (types == null) + if (res == null || res.ResolvedTypesOrMethods == null) return Tuple.Create(sr.Location, sr.EndLocation, String.Empty); - var tipText = new StringBuilder(); DNode dn = null; - - foreach (var t in AmbiguousType.TryDissolve(types)) - { - var dt = t; - if (dt is AliasedType at) + var tips = new List>(); + foreach (var types in res.ResolvedTypesOrMethods) + { + foreach (var t in AmbiguousType.TryDissolve(types)) { - // jump to original definition if it is not renamed or the caret is on the import - var isRenamed = (at.Definition as ImportSymbolAlias)?.ImportBinding?.Alias != null; - if (!isRenamed || at.Definition.Location == sr.Location) - dt = at.Base; - } - tipText.Append(NodeToolTipContentGen.Instance.GenTooltipSignature(dt)); - if (dt is DSymbol symbol) - dn = symbol.Definition; - - tipText.Append("\a"); - } - - while (tipText.Length > 0 && tipText[tipText.Length - 1] == '\a') - tipText.Length--; - - if (evaluateUnderneathExpression) - { - var ctxt = editorData.GetLooseResolutionContext(LooseResolution.NodeResolutionAttempt.Normal); - ctxt.Push(editorData); - try - { - ISymbolValue v = null; - if (dn is DVariable var && var.Initializer != null && var.IsConst) - v = Evaluation.EvaluateValue(var.Initializer, ctxt); - if (v == null && sr is IExpression expression) - v = Evaluation.EvaluateValue(expression, ctxt); - if (v != null && !(v is ErrorValue)) - { - var valueStr = " = " + v; - if (tipText.Length > valueStr.Length && - tipText.ToString(tipText.Length - valueStr.Length, valueStr.Length) != valueStr) - tipText.Append(valueStr); + var tipText = new StringBuilder(); + var dt = t; + if (dt is AliasedType at) + { + // jump to original definition if it is not renamed or the caret is on the import + var isRenamed = (at.Definition as ImportSymbolAlias)?.ImportBinding?.Alias != null; + if (!isRenamed || at.Definition.Location == sr.Location) + dt = at.Base; } - } - catch (Exception e) - { - tipText.Append("\aException during evaluation = ").Append(e.Message); - } + tipText.Append(NodeToolTipContentGen.Instance.GenTooltipSignature(dt, false, -1, quoteCode)); + if (dt is DSymbol symbol) + dn = symbol.Definition; + + if (evaluateUnderneathExpression) + { + var ctxt = editorData.GetLooseResolutionContext(LooseResolution.NodeResolutionAttempt.Normal); + ctxt.Push(editorData); + try + { + ISymbolValue v = null; + if (dn is DVariable var && var.Initializer != null && var.IsConst) + v = Evaluation.EvaluateValue(var.Initializer, ctxt); + if (v == null && sr is IExpression expression) + v = Evaluation.EvaluateValue(expression, ctxt); + if (v != null && !(v is ErrorValue)) + { + var valueStr = " = " + v; + if (tipText.Length > valueStr.Length && + tipText.ToString(tipText.Length - valueStr.Length, valueStr.Length) != valueStr) + tipText.Append(valueStr); + } + } + catch (Exception e) + { + tipText.Append(" (Exception during evaluation: ").Append(e.Message).Append(")"); + } + + ctxt.Pop(); + } + var docText = new StringBuilder(); + if (dn != null) + VDServerCompletionDataGenerator.GenerateNodeTooltipBody(dn, docText); - ctxt.Pop(); + tips.Add(Tuple.Create(tipText.ToString(), docText.ToString())); + } } + var text = new StringBuilder(); + string prevDoc = ""; + bool first = true; + foreach (var tip in tips) + { + // do not emit the same doc twice + if (overloads || (tip.Item2 != "ditto" && tip.Item2 != prevDoc)) + { + if (!string.IsNullOrEmpty(prevDoc)) + text.Append("\n").Append(prevDoc); + } + if (!first) + text.Append("\a"); + first = false; + text.Append(tip.Item1); + if (tip.Item2 != "ditto") + prevDoc = tip.Item2; + } + if (!string.IsNullOrEmpty(prevDoc)) + text.Append("\n").Append(prevDoc); - if (dn != null) - VDServerCompletionDataGenerator.GenerateNodeTooltipBody(dn, tipText); - - while (tipText.Length > 0 && tipText[tipText.Length - 1] == '\a') - tipText.Length--; - - return Tuple.Create(sr.Location, sr.EndLocation, tipText.ToString()); + return Tuple.Create(sr.Location, sr.EndLocation, text.ToString()); } } } \ No newline at end of file diff --git a/vdc/abothe/comserver/VDServer.cs b/vdc/abothe/comserver/VDServer.cs index b1b632df..8f04af5d 100644 --- a/vdc/abothe/comserver/VDServer.cs +++ b/vdc/abothe/comserver/VDServer.cs @@ -110,7 +110,7 @@ public void UpdateModule(string filename, string srcText, int flags) public void GetIdentifierTypes(string filename, int startLine, int endLine, int flags) { - _identifierTypesTask.Run(filename, new CodeLocation(startLine + 1, 0), new Tuple (endLine, (flags & 1) != 0)); + _identifierTypesTask.Run(filename, new CodeLocation(0, startLine), new Tuple (endLine, (flags & 1) != 0)); } public void GetIdentifierTypesResult(out string answer) @@ -132,7 +132,7 @@ public void GetIdentifierTypesResult(out string answer) public void GetTip(string filename, int startLine, int startIndex, int endLine, int endIndex, int flags) { - _tipGenerationTask.Run(filename, new CodeLocation(startIndex + 1, startLine), (flags & 1) != 0); + _tipGenerationTask.Run(filename, new CodeLocation(startIndex + 1, startLine), flags); } public void GetTipResult(out int startLine, out int startIndex, out int endLine, out int endIndex, out string answer) diff --git a/vdc/ast/aggr.d b/vdc/ast/aggr.d index 22e3eafa..0b53ba2d 100644 --- a/vdc/ast/aggr.d +++ b/vdc/ast/aggr.d @@ -312,7 +312,7 @@ class Aggregate : Type return null; } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { if(Value v = getStaticProperty(prop)) return v; @@ -522,7 +522,7 @@ class InheritingAggregate : Aggregate return false; } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { foreach(bc; baseClasses) if(Value v = bc._interpretProperty(ctx, prop)) @@ -772,7 +772,7 @@ class BaseClass : Node writer("public ", getMember(0)); // protection diffent from C } - @disable Value _interpretProperty(Context ctx, string prop) + /*@disable*/ Value _interpretProperty(Context ctx, string prop) { if(auto clss = getClass()) return clss._interpretProperty(ctx, prop); diff --git a/vdc/ast/mod.d b/vdc/ast/mod.d index 770029da..bdbf7eb5 100644 --- a/vdc/ast/mod.d +++ b/vdc/ast/mod.d @@ -10,6 +10,7 @@ module vdc.ast.mod; import vdc.util; import vdc.semantic; +import vdc.semanticopt; import vdc.lexer; import vdc.ast.node; @@ -59,10 +60,10 @@ class Module : Node return tn.filename == filename && tn.imported == imported; } - - + + Project getProject() { return static_cast!Project(parent); } - + override void toD(CodeWriter writer) { foreach(m; members) @@ -116,7 +117,7 @@ class Module : Node writer("::", baseName(filename)); writer("::"); } - + string getModuleName() { if(auto md = cast(ModuleDeclaration) getMember(0)) @@ -158,7 +159,7 @@ class Module : Node auto imp = Import.create(objmod); // only needs module name scop.addImport(imp); } - + super.addMemberSymbols(scop); } } @@ -173,12 +174,12 @@ class Module : Node initScope(); return scop.search(ident, false, false, true); } - + override void _semantic(Scope sc) { if(imported) // no full semantic on imports return; - + // the order in which lazy semantic analysis takes place: // - evaluate/expand version/debug // - evaluate mixins and static if conditionals in lexical order @@ -192,17 +193,17 @@ class Module : Node sc = sc.push(scop); scope(exit) sc.pop(); - + foreach(m; members) { m.semantic(scop); } } - + public /* debug & version handling */ { VersionDebug debugIds; VersionDebug versionIds; - + Options getOptions() { if(options) @@ -234,7 +235,7 @@ class Module : Node return true; return false; } - + bool versionEnabled(int level) { if(Options opt = getOptions()) @@ -266,7 +267,7 @@ class Module : Node return true; return false; } - + bool debugEnabled(int level) { if(Options opt = getOptions()) @@ -284,7 +285,7 @@ class Module : Node return opt.debugOn; return false; } - + } } @@ -316,7 +317,7 @@ class PackageIdentifier : Node class ModuleFullyQualifiedName : Node { PackageIdentifier[] pkgs; - + mixin ForwardCtor!(); override void toD(CodeWriter writer) @@ -362,7 +363,7 @@ class ModuleFullyQualifiedName : Node } } } - + string getName() { string name = getMember!Identifier(0).ident; @@ -394,7 +395,7 @@ class AttributeSpecifier : Node override void toD(CodeWriter writer) { writer.writeAttributesAndAnnotations(attr, annotation); - + switch(id) { case TOK_colon: @@ -424,7 +425,7 @@ class AttributeSpecifier : Node m.attr = combineAttributes(attr, m.attr); m.annotation = combineAnnotations(annotation, m.annotation); } - + override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { switch(id) @@ -499,7 +500,7 @@ class DeclarationBlock : Node foreach(m; members) writer(m); } - + override Node[] expandNonScopeBlock(Scope sc, Node[] athis) { return removeAll(); @@ -534,7 +535,7 @@ class Pragma : Node string ident; TemplateArgumentList getTemplateArgumentList() { return getMember!TemplateArgumentList(0); } - + override Pragma clone() { Pragma n = static_cast!Pragma(super.clone()); @@ -549,7 +550,7 @@ class Pragma : Node auto tn = static_cast!(typeof(this))(n); return tn.ident == ident; } - + override void toD(CodeWriter writer) { writer("pragma(", ident, ", ", getMember(0), ")"); @@ -562,7 +563,7 @@ class Pragma : Node string msg; auto alst = getTemplateArgumentList(); alst.semantic(sc); - + foreach(m; alst.members) { Value val = m.interpretCatch(nullContext); @@ -588,7 +589,7 @@ class ImportDeclaration : Node override void toC(CodeWriter writer) { } - + override void _semantic(Scope sc) { getMember(0).annotation = annotation; // copy protection attributes @@ -637,7 +638,7 @@ class Import : Node string aliasIdent; ImportBindList getImportBindList() { return members.length > 1 ? getMember!ImportBindList(1) : null; } - + Annotation getProtection() { if(parent && parent.parent) @@ -649,7 +650,7 @@ class Import : Node Module mod; int countLookups; int countFound; - + override Import clone() { Import n = static_cast!Import(super.clone()); @@ -665,7 +666,7 @@ class Import : Node auto tn = static_cast!(typeof(this))(n); return tn.aliasIdent == aliasIdent; } - + override void toD(CodeWriter writer) { if(aliasIdent.length) @@ -680,7 +681,7 @@ class Import : Node sc.addImport(this); if(aliasIdent.length > 0) sc.addSymbol(aliasIdent, this); - + auto mfqn = getMember!ModuleFullyQualifiedName(0); mfqn.addSymbols(sc); } @@ -690,10 +691,10 @@ class Import : Node if(!mod) if(auto prj = sc.mod.getProject()) mod = prj.importModule(getModuleName(), this); - + if(!mod) return Scope.SearchSet(); - + return mod.search(ident); } @@ -702,7 +703,7 @@ class Import : Node auto mfqn = getMember!ModuleFullyQualifiedName(0); return mfqn.getName(); } - + static Import create(Module mod) { // TODO: no location info @@ -722,8 +723,8 @@ unittest verifyParseWrite(q{ import ntest = pkg.test; }); verifyParseWrite(q{ import io = std.stdio : writeln, write; }); } - - + + //ImportBindList: // ImportBind // ImportBind , ImportBindList @@ -764,7 +765,7 @@ class MixinDeclaration : Node writer("mixin(", getMember(0), ");"); writer.nl; } - + override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) { Context ctx = new Context(nullContext); diff --git a/vdc/ast/type.d b/vdc/ast/type.d index d79031ac..edc078ab 100644 --- a/vdc/ast/type.d +++ b/vdc/ast/type.d @@ -182,7 +182,7 @@ class Type : Node return v; return semanticErrorValue("cannot calculate property ", prop, " of type ", this); } - @disable Value _interpretProperty(Context ctx, string prop) + /*@disable*/ Value _interpretProperty(Context ctx, string prop) { return null; } @@ -433,7 +433,7 @@ class BasicType : Type return Category.kVoid; } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { switch(prop) { diff --git a/vdc/dmdserver/dmd b/vdc/dmdserver/dmd new file mode 160000 index 00000000..5e821dfe --- /dev/null +++ b/vdc/dmdserver/dmd @@ -0,0 +1 @@ +Subproject commit 5e821dfe2d697ffe9336c064d4536db69c6c0511 diff --git a/vdc/dmdserver/dmderrors.d b/vdc/dmdserver/dmderrors.d new file mode 100644 index 00000000..986aab4a --- /dev/null +++ b/vdc/dmdserver/dmderrors.d @@ -0,0 +1,174 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2019 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.dmdserver.dmderrors; + +import dmd.console; +import dmd.errors; +import dmd.globals; + +import std.ascii; +import std.string; + +import core.stdc.stdarg; +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.wchar_ : wcslen; + +shared(Object) gErrorSync = new Object; +private __gshared // under gErrorSync lock +{ + string gErrorFile; + string gErrorMessages; + string gOtherErrorMessages; + + private string gLastHeader; + private string[] gLastErrorMsgs; // all but first are supplemental + private Loc[] gLastErrorLocs; +} + +void flushLastError() +{ + if (gLastErrorLocs.empty) + return; + assert(gLastErrorLocs.length == gLastErrorMsgs.length); + + char[1014] buf; + char[] genErrorMessage(size_t pos) + { + char[] msg; + if (pos < gLastErrorLocs.length) + { + Loc loc = gLastErrorLocs[pos]; + int len = snprintf(buf.ptr, buf.length, "%d,%d,%d,%d:", loc.linnum, loc.charnum - 1, loc.linnum, loc.charnum); + msg ~= buf[0..len]; + } + + msg ~= gLastHeader; + for (size_t i = 0; i < gLastErrorLocs.length; i++) + { + if (i > 0) + msg ~= "\a"; + + Loc loc = gLastErrorLocs[i]; + if (i == pos) + { + if (i > 0) + msg ~= "--> "; + } + else if (loc.filename) + { + int len = snprintf(buf.ptr, buf.length, "%s(%d): ", loc.filename, loc.linnum); + msg ~= buf[0..len]; + } + msg ~= gLastErrorMsgs[i]; + } + return msg; + } + + size_t otherLocs; + foreach (loc; gLastErrorLocs) + if (!loc.filename || _stricmp(loc.filename, gErrorFile) != 0) + otherLocs++; + + if (otherLocs == gLastErrorLocs.length) + { + gOtherErrorMessages ~= genErrorMessage(size_t.max) ~ "\n"; + } + else + { + for (size_t i = 0; i < gLastErrorLocs.length; i++) + { + Loc loc = gLastErrorLocs[i]; + if (loc.filename && _stricmp(loc.filename, gErrorFile) == 0) + { + gErrorMessages ~= genErrorMessage(i) ~ "\n"; + gLastHeader = "Info: "; + } + } + } + + gLastHeader = null; + gLastErrorLocs.length = 0; + gLastErrorMsgs.length = 0; +} + +void errorPrint(const ref Loc loc, Color headerColor, const(char)* header, + const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) nothrow +{ + if (!loc.filename) + return; + + try synchronized(gErrorSync) + { + bool other = _stricmp(loc.filename, gErrorFile) != 0; + while (header && std.ascii.isWhite(*header)) + header++; + bool supplemental = !header || !*header; + + if (!supplemental) + flushLastError(); + + __gshared char[4096] buf; + int len = 0; + if (header && *header) + gLastHeader = header[0..strlen(header)].idup; + if (p1 && len < buf.length) + len += snprintf(buf.ptr + len, buf.length - len, "%s ", p1); + if (p2 && len < buf.length) + len += snprintf(buf.ptr + len, buf.length - len, "%s ", p2); + if (len < buf.length) + len += vsnprintf(buf.ptr + len, buf.length - len, format, ap); + + gLastErrorMsgs ~= buf[0..len].dup; + gLastErrorLocs ~= loc; + } + catch(Exception e) + { + // tame synchronized "throwing" + } +} + +void initErrorMessages(string fname) +{ + synchronized(gErrorSync) + { + gErrorFile = fname; + gErrorMessages = null; + gOtherErrorMessages = null; + + gLastErrorLocs = null; + gLastErrorMsgs = null; + + import std.functional; + diagnosticHandler = toDelegate(&errorPrint); + } +} + +string getErrorMessages(bool other = false) +{ + synchronized(gErrorSync) + { + flushLastError(); + return other ? gOtherErrorMessages : gErrorMessages; + } +} + +int _stricmp(const(char)*str1, string s2) nothrow +{ + const(char)[] s1 = str1[0..strlen(str1)]; + return icmp(s1, s2); +} + +int _stricmp(const(wchar)*str1, wstring s2) nothrow +{ + const(wchar)[] s1 = str1[0..wcslen(str1)]; + return icmp(s1, s2); +} + diff --git a/vdc/dmdserver/dmdicon.ico b/vdc/dmdserver/dmdicon.ico new file mode 100644 index 00000000..3ead32d9 Binary files /dev/null and b/vdc/dmdserver/dmdicon.ico differ diff --git a/vdc/dmdserver/dmdinit.d b/vdc/dmdserver/dmdinit.d new file mode 100644 index 00000000..d7b27a95 --- /dev/null +++ b/vdc/dmdserver/dmdinit.d @@ -0,0 +1,486 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2019 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.dmdserver.dmdinit; + +import dmd.arraytypes; +import dmd.builtin; +import dmd.cond; +import dmd.compiler; +import dmd.ctfeexpr; +import dmd.dclass; +import dmd.declaration; +import dmd.dimport; +import dmd.dinterpret; +import dmd.dmodule; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dtemplate; +import dmd.expression; +import dmd.func; +import dmd.globals; +import dmd.id; +import dmd.mtype; +import dmd.objc; +import dmd.target; + +import dmd.root.outbuffer; + +import std.string; +import core.stdc.string; + +//////////////////////////////////////////////////////////////// +alias countersType = uint[uint]; // actually uint[Key] + +enum string[2][] dmdStatics = +[ + ["_D3dmd5clone12buildXtoHashFCQBa7dstruct17StructDeclarationPSQCg6dscope5ScopeZ8tftohashCQDh5mtype12TypeFunction", "TypeFunction"], + ["_D3dmd7dstruct15search_toStringRCQBfQBe17StructDeclarationZ10tftostringCQCs5mtype12TypeFunction", "TypeFunction"], + ["_D3dmd13expressionsem11loadStdMathFZ10impStdMathCQBv7dimport6Import", "Import"], + ["_D3dmd4func15FuncDeclaration8genCfuncRPSQBm4root5array__T5ArrayTCQCl5mtype9ParameterZQBcCQDjQy4TypeCQDu10identifier10IdentifiermZ2stCQFb7dsymbol12DsymbolTable", "DsymbolTable"], + ["_D3dmd7typesem12typeSemanticRCQBc5mtype4TypeSQBr7globals3LocPSQCi6dscope5ScopeZ11visitAArrayMFCQDpQCn10TypeAArrayZ3feqCQEn4func15FuncDeclaration", "FuncDeclaration"], + ["_D3dmd7typesem12typeSemanticRCQBc5mtype4TypeSQBr7globals3LocPSQCi6dscope5ScopeZ11visitAArrayMFCQDpQCn10TypeAArrayZ4fcmpCQEo4func15FuncDeclaration", "FuncDeclaration"], + ["_D3dmd7typesem12typeSemanticRCQBc5mtype4TypeSQBr7globals3LocPSQCi6dscope5ScopeZ11visitAArrayMFCQDpQCn10TypeAArrayZ5fhashCQEp4func15FuncDeclaration", "FuncDeclaration"], + ["_D3dmd7typesem6dotExpFCQv5mtype4TypePSQBk6dscope5ScopeCQCb10expression10ExpressionCQDdQBc8DotIdExpiZ11visitAArrayMFCQEkQDq10TypeAArrayZ8fd_aaLenCQFn4func15FuncDeclaration", "FuncDeclaration"], + ["_D3dmd7typesem6dotExpFCQv5mtype4TypePSQBk6dscope5ScopeCQCb10expression10ExpressionCQDdQBc8DotIdExpiZ8noMemberMFQDlQDaQClCQEp10identifier10IdentifieriZ4nesti", "int"], + ["_D3dmd6dmacro10MacroTable6expandMFKSQBi4root9outbuffer9OutBufferkKkAxaZ4nesti", "int"], // x86 + ["_D3dmd7dmodule6Module19runDeferredSemanticRZ6nestedi", "int"], + ["_D3dmd10dsymbolsem22DsymbolSemanticVisitor5visitMRCQBx9dtemplate13TemplateMixinZ4nesti", "int"], + ["_D3dmd9dtemplate16TemplateInstance16tryExpandMembersMFPSQCc6dscope5ScopeZ4nesti", "int"], + ["_D3dmd9dtemplate16TemplateInstance12trySemantic3MFPSQBy6dscope5ScopeZ4nesti", "int"], + ["_D3dmd13expressionsem25ExpressionSemanticVisitor5visitMRCQCd10expression7CallExpZ4nesti", "int"], + ["_D3dmd5lexer5Lexer12stringbufferSQBf4root9outbuffer9OutBuffer", "OutBuffer"], + //["_D3dmd10expression10IntegerExp__T7literalVii0ZQnRZ11theConstantCQCkQCjQCa", "IntegerExp"], + //["_D3dmd10expression10IntegerExp__T7literalVii1ZQnRZ11theConstantCQCkQCjQCa", "IntegerExp"], + //["_D3dmd10expression10IntegerExp__T7literalViN1ZQnRZ11theConstantCQCkQCjQCa", "IntegerExp"], + ["_D3dmd10identifier10Identifier17generateIdWithLocFNbAyaKxSQCe7globals3LocZ8countersHSQDfQDeQCvQCmFNbQBwKxQBwZ3Keyk", "countersType"], + ["_D3dmd10identifier10Identifier10generateIdRNbPxaZ1ik", "size_t"], + ["_D3dmd5lexer5Lexer4scanMFNbPSQBb6tokens5TokenZ8initdoneb", "bool"], +]; + +string cmangled(string s) +{ + version (Win64) + { + if (s == "_D3dmd10identifier10Identifier10generateIdRNbPxaZ1ik") + return "_D3dmd10identifier10Identifier10generateIdRNbPxaZ1im"; // size_t + if (s == "_D3dmd6dmacro10MacroTable6expandMFKSQBi4root9outbuffer9OutBufferkKkAxaZ4nesti") + return "_D3dmd6dmacro10MacroTable6expandMFKSQBi4root9outbuffer9OutBuffermKmAxaZ4nesti"; + } + return s; +} + +string genDeclDmdStatics() +{ + string s; + foreach (decl; dmdStatics) + s ~= q{extern extern(C) __gshared } ~ decl[1] ~ " " ~ cmangled(decl[0]) ~ ";\n"; + return s; +} + +string genInitDmdStatics() +{ + string s; + foreach (decl; dmdStatics) + s ~= cmangled(decl[0]) ~ " = " ~ decl[1] ~ ".init;\n"; + return s; +} + +mixin(genDeclDmdStatics); + +pragma(mangle, "_D3dmd12statementsem24StatementSemanticVisitor5visitMRCQCb9statement16ForeachStatementZ7fdapplyPCQDr4func15FuncDeclaration") +extern __gshared FuncDeclaration* statementsem_fdapply; +pragma(mangle, "_D3dmd12statementsem24StatementSemanticVisitor5visitMRCQCb9statement16ForeachStatementZ6fldeTyPCQDq5mtype12TypeDelegate") +extern __gshared TypeDelegate* statementsem_fldeTy; + + +void clearSemanticStatics() +{ + /* + import core.demangle; + static foreach(s; dmdStatics) + pragma(msg, demangle(s[0])); + */ + mixin(genInitDmdStatics); + + // statementsem + // static __gshared FuncDeclaration* fdapply = [null, null]; + // static __gshared TypeDelegate* fldeTy = [null, null]; + statementsem_fdapply[0] = statementsem_fdapply[1] = null; + statementsem_fldeTy[0] = statementsem_fldeTy[1] = null; + + // dmd.dtemplate + emptyArrayElement = null; + TemplateValueParameter.edummies = null; + TemplateTypeParameter.tdummy = null; + TemplateAliasParameter.sdummy = null; + + VarDeclaration.nextSequenceNumber = 0; + + //entrypoint = cast(Module)&entrypoint; // disable generation of C main + + // Package.this.packageTag? + // funcDeclarationSemantic.printedMain? + /+ + Type.stringtable.reset(); + +/ +} + +// initialization that are necessary once +void dmdInit() +{ + __gshared bool initialized; + if (initialized) + return; + initialized = true; + + import dmd.root.longdouble; + // Initialization + version(CRuntime_Microsoft) + initFPU(); + + global.params.isWindows = true; + global._init(); + //Token._init(); + Id.initialize(); + Expression._init(); + builtin_init(); + + target._init(global.params); // needed by Type._init + Type._init(); +} + +struct Options +{ + string[] importDirs; + string[] stringImportDirs; + + bool unittestOn; + bool x64; + bool msvcrt; + bool warnings; + bool debugOn; + bool coverage; + bool doDoc; + bool noBoundsCheck; + bool gdcCompiler; + bool ldcCompiler; + bool noDeprecated; + bool mixinAnalysis; + bool UFCSExpansions; + + bool predefineDefaultVersions; + int versionLevel; + string[] versionIds; + int debugLevel; + string[] debugIds; + + void opAssign(const ref Options opts) + { + import std.traits; + + static foreach(i, F; typeof(this).tupleof) + static if(isDynamicArray!(typeof(F))) + this.tupleof[i] = opts.tupleof[i].dup; + else + this.tupleof[i] = opts.tupleof[i]; + } + + bool setImportDirs(string[] dirs) + { + if(dirs == importDirs) + return false; + importDirs = dirs; + return true; + } + bool setStringImportDirs(string[] dirs) + { + if(dirs == stringImportDirs) + return false; + stringImportDirs = dirs; + return true; + } + bool setVersionIds(int level, string[] ids) + { + if(versionLevel == level && versionIds == ids) + return false; + versionLevel = level; + versionIds = ids; + return true; + } + bool setDebugIds(int level, string[] ids) + { + if(debugLevel == level && debugIds == ids) + return false; + debugLevel = level; + debugIds = ids; + return true; + } +} + +void dmdSetupParams(const ref Options opts) +{ + global = global.init; + + global._init(); + global.params.isWindows = true; + global.params.errorLimit = 0; + global.params.color = false; + global.params.link = true; + global.params.useUnitTests = opts.unittestOn; + global.params.useAssert = opts.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useInvariants = opts.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useIn = opts.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useOut = opts.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useArrayBounds = opts.noBoundsCheck ? CHECKENABLE.on : CHECKENABLE.off; // set correct value later + global.params.doDocComments = opts.doDoc; + global.params.useSwitchError = CHECKENABLE.on; + global.params.useInline = false; + global.params.obj = false; + global.params.useDeprecated = opts.noDeprecated ? DiagnosticReporting.error : DiagnosticReporting.off; + global.params.warnings = opts.warnings ? DiagnosticReporting.inform : DiagnosticReporting.off; + global.params.linkswitches = Strings(); + global.params.libfiles = Strings(); + global.params.dllfiles = Strings(); + global.params.objfiles = Strings(); + global.params.ddocfiles = Strings(); + // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd + global.params.is64bit = opts.x64; + global.params.mscoff = opts.msvcrt; + global.params.cpu = CPU.baseline; + global.params.isLP64 = global.params.is64bit; + + global.params.versionlevel = opts.versionLevel; + global.params.versionids = new Strings(); + foreach(v; opts.versionIds) + global.params.versionids.push(toStringz(v)); + + global.versionids = new Identifiers(); + + // Add in command line versions + if (global.params.versionids) + foreach (charz; *global.params.versionids) + { + auto ident = charz[0 .. strlen(charz)]; + if (VersionCondition.isReserved(ident)) + VersionCondition.addPredefinedGlobalIdent(ident); + else + VersionCondition.addGlobalIdent(ident); + } + + if (opts.predefineDefaultVersions) + addDefaultVersionIdentifiers(global.params); + + // always enable for tooltips + global.params.doDocComments = true; + + global.params.debugids = new Strings(); + global.params.debuglevel = opts.debugLevel; + foreach(d; opts.debugIds) + global.params.debugids.push(toStringz(d)); + + global.debugids = new Identifiers(); + if (global.params.debugids) + foreach (charz; *global.params.debugids) + DebugCondition.addGlobalIdent(charz[0 .. strlen(charz)]); + + global.path = new Strings(); + foreach(i; opts.importDirs) + global.path.push(toStringz(i)); + + global.filePath = new Strings(); + foreach(i; opts.stringImportDirs) + global.filePath.push(toStringz(i)); +} + +// initialization that are necessary before restarting an analysis (which might run +// for another platform/architecture, different versions) +void dmdReinit() +{ + target._init(global.params); // needed by Type._init + Type._reinit(); + + // assume object.d unmodified otherwis + Module.moduleinfo = null; + + ClassDeclaration.object = null; + ClassDeclaration.throwable = null; + ClassDeclaration.exception = null; + ClassDeclaration.errorException = null; + ClassDeclaration.cpp_type_info_ptr = null; + + StructDeclaration.xerreq = null; + StructDeclaration.xerrcmp = null; + + Type.dtypeinfo = null; + Type.typeinfoclass = null; + Type.typeinfointerface = null; + Type.typeinfostruct = null; + Type.typeinfopointer = null; + Type.typeinfoarray = null; + Type.typeinfostaticarray = null; + Type.typeinfoassociativearray = null; + Type.typeinfovector = null; + Type.typeinfoenum = null; + Type.typeinfofunction = null; + Type.typeinfodelegate = null; + Type.typeinfotypelist = null; + Type.typeinfoconst = null; + Type.typeinfoinvariant = null; + Type.typeinfoshared = null; + Type.typeinfowild = null; + Type.rtinfo = null; + + Objc._init(); + + Module._init(); + Module.amodules = Module.amodules.init; + Module.deferred = Dsymbols(); // deferred Dsymbol's needing semantic() run on them + Module.deferred2 = Dsymbols(); // deferred Dsymbol's needing semantic2() run on them + Module.deferred3 = Dsymbols(); // deferred Dsymbol's needing semantic3() run on them + Module.dprogress = 0; // progress resolving the deferred list + + dinterpret_init(); + + clearSemanticStatics(); +} + +// plain copy of dmd.mars.addDefaultVersionIdentifiers +void addDefaultVersionIdentifiers(const ref Param params) +{ + VersionCondition.addPredefinedGlobalIdent("DigitalMars"); + if (params.isWindows) + { + VersionCondition.addPredefinedGlobalIdent("Windows"); + if (global.params.mscoff) + { + VersionCondition.addPredefinedGlobalIdent("CRuntime_Microsoft"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Microsoft"); + } + else + { + VersionCondition.addPredefinedGlobalIdent("CRuntime_DigitalMars"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_DigitalMars"); + } + } + else if (params.isLinux) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("linux"); + VersionCondition.addPredefinedGlobalIdent("ELFv1"); + VersionCondition.addPredefinedGlobalIdent("CRuntime_Glibc"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); + } + else if (params.isOSX) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("OSX"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang"); + // For legacy compatibility + VersionCondition.addPredefinedGlobalIdent("darwin"); + } + else if (params.isFreeBSD) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("FreeBSD"); + VersionCondition.addPredefinedGlobalIdent("ELFv1"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Clang"); + } + else if (params.isOpenBSD) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("OpenBSD"); + VersionCondition.addPredefinedGlobalIdent("ELFv1"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); + } + else if (params.isDragonFlyBSD) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("DragonFlyBSD"); + VersionCondition.addPredefinedGlobalIdent("ELFv1"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Gcc"); + } + else if (params.isSolaris) + { + VersionCondition.addPredefinedGlobalIdent("Posix"); + VersionCondition.addPredefinedGlobalIdent("Solaris"); + VersionCondition.addPredefinedGlobalIdent("ELFv1"); + VersionCondition.addPredefinedGlobalIdent("CppRuntime_Sun"); + } + else + { + assert(0); + } + VersionCondition.addPredefinedGlobalIdent("LittleEndian"); + VersionCondition.addPredefinedGlobalIdent("D_Version2"); + VersionCondition.addPredefinedGlobalIdent("all"); + + if (params.cpu >= CPU.sse2) + { + VersionCondition.addPredefinedGlobalIdent("D_SIMD"); + if (params.cpu >= CPU.avx) + VersionCondition.addPredefinedGlobalIdent("D_AVX"); + if (params.cpu >= CPU.avx2) + VersionCondition.addPredefinedGlobalIdent("D_AVX2"); + } + + if (params.is64bit) + { + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64"); + VersionCondition.addPredefinedGlobalIdent("X86_64"); + if (params.isWindows) + { + VersionCondition.addPredefinedGlobalIdent("Win64"); + } + } + else + { + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm"); //legacy + VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86"); + VersionCondition.addPredefinedGlobalIdent("X86"); + if (params.isWindows) + { + VersionCondition.addPredefinedGlobalIdent("Win32"); + } + } + + if (params.isLP64) + VersionCondition.addPredefinedGlobalIdent("D_LP64"); + if (params.doDocComments) + VersionCondition.addPredefinedGlobalIdent("D_Ddoc"); + if (params.cov) + VersionCondition.addPredefinedGlobalIdent("D_Coverage"); + static if(__traits(compiles, PIC.fixed)) + { + // dmd 2.088 + if (params.pic != PIC.fixed) + VersionCondition.addPredefinedGlobalIdent(params.pic == PIC.pic ? "D_PIC" : "D_PIE"); + } + else if (params.pic) + VersionCondition.addPredefinedGlobalIdent("D_PIC"); + + if (params.useUnitTests) + VersionCondition.addPredefinedGlobalIdent("unittest"); + if (params.useAssert == CHECKENABLE.on) + VersionCondition.addPredefinedGlobalIdent("assert"); + if (params.useArrayBounds == CHECKENABLE.off) + VersionCondition.addPredefinedGlobalIdent("D_NoBoundsChecks"); + if (params.betterC) + { + VersionCondition.addPredefinedGlobalIdent("D_BetterC"); + } + else + { + VersionCondition.addPredefinedGlobalIdent("D_ModuleInfo"); + VersionCondition.addPredefinedGlobalIdent("D_Exceptions"); + VersionCondition.addPredefinedGlobalIdent("D_TypeInfo"); + } + + VersionCondition.addPredefinedGlobalIdent("D_HardFloat"); +} + diff --git a/vdc/dmdserver/dmdlib.d b/vdc/dmdserver/dmdlib.d new file mode 100644 index 00000000..98ced22b --- /dev/null +++ b/vdc/dmdserver/dmdlib.d @@ -0,0 +1,5 @@ +module dmd.lib; + +class Library +{ +} diff --git a/vdc/dmdserver/dmdrmem.d b/vdc/dmdserver/dmdrmem.d new file mode 100644 index 00000000..539fc424 --- /dev/null +++ b/vdc/dmdserver/dmdrmem.d @@ -0,0 +1,113 @@ +module dmd.root.rmem; + +import core.memory : GC; +import core.stdc.string : strlen; + +extern (C++) struct Mem +{ + enum isGCEnabled = true; + + static char* xstrdup(const(char)* p) nothrow + { + return p[0 .. strlen(p) + 1].dup.ptr; + } + + static void xfree(void* p) nothrow pure + { + return GC.free(p); + } + + static void* xmalloc(size_t n) nothrow pure + { + if (*pcancel) + throw new Error("cancel malloc"); //*pcancelError; + return GC.malloc(n); + } + static void* xmalloc_noscan(size_t n) nothrow pure + { + if (*pcancel) + throw new Error("cancel malloc");//*pcancelError; + return GC.malloc(n, GC.BlkAttr.NO_SCAN); + } + + static void* xcalloc(size_t size, size_t n) nothrow pure + { + return GC.calloc(size * n); + } + + static void* xcalloc_noscan(size_t size, size_t n) nothrow pure + { + return GC.calloc(size * n, GC.BlkAttr.NO_SCAN); + } + + static void* xrealloc(void* p, size_t size) nothrow pure + { + return GC.realloc(p, size); + } + + static void* xrealloc_noscan(void* p, size_t size) nothrow pure + { + return GC.realloc(p, size, GC.BlkAttr.NO_SCAN); + } + + static void error() nothrow + { + __gshared static oom = new Error("out of memory"); + throw oom; + } + static void* check(void* p) nothrow + { + if (!p) + error(); + return p; + } + + extern(D) __gshared immutable cancelError = new Error("cancel malloc"); + extern(D) __gshared bool cancel; + // fake purity + enum pcancel = cast(immutable) &cancel; + enum pcancelError = cast(immutable) &cancelError; +} + +extern (C++) const __gshared Mem mem; + +/** +Makes a null-terminated copy of the given string on newly allocated memory. +The null-terminator won't be part of the returned string slice. It will be +at position `n` where `n` is the length of the input string. + +Params: + s = string to copy + +Returns: A null-terminated copy of the input array. +*/ +extern (D) char[] xarraydup(const(char)[] s) nothrow pure +{ + if (!s) + return null; + + auto p = cast(char*)mem.xmalloc(s.length + 1); + char[] a = p[0 .. s.length]; + a[] = s[0 .. s.length]; + p[s.length] = 0; // preserve 0 terminator semantics + return a; +} + +/** +Makes a copy of the given array on newly allocated memory. + +Params: + s = array to copy + +Returns: A copy of the input array. +*/ +extern (D) T[] arraydup(T)(const scope T[] s) nothrow +{ + if (!s) + return null; + + const dim = s.length; + auto p = (cast(T*)mem.xmalloc(T.sizeof * dim))[0 .. dim]; + p[] = s; + return p; +} diff --git a/vdc/dmdserver/dmdserver.d b/vdc/dmdserver/dmdserver.d new file mode 100644 index 00000000..85ac2c56 --- /dev/null +++ b/vdc/dmdserver/dmdserver.d @@ -0,0 +1,1245 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2012 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.dmdserver.dmdserver; +import vdc.dmdserver.dmdinit; +import vdc.dmdserver.dmderrors; +import vdc.dmdserver.semvisitor; +import vdc.dmdserver.semanalysis; + +version(MAIN) {} else version = noServer; + +version(noServer): +import vdc.ivdserver; + +import dmd.arraytypes; +import dmd.cond; +import dmd.dmodule; +import dmd.dsymbolsem; +import dmd.errors; +import dmd.globals; +import dmd.identifier; +import dmd.semantic2; +import dmd.semantic3; + +import dmd.root.file; +import dmd.root.rmem; + +//import vdc.util; +struct TextPos +{ + int index; + int line; +} +struct TextSpan +{ + TextPos start; + TextPos end; +} + +import sdk.port.base; +import sdk.win32.oaidl; +import sdk.win32.objbase; +import sdk.win32.oleauto; + +import stdext.com; +import stdext.string; +import stdext.array; +import stdext.path; + +version = SingleThread; + +//import std.stdio; +import std.ascii; +import std.parallelism; +import std.path; +import std.string; +import std.conv; +import std.array; + +import std.concurrency; +import std.datetime; +import core.exception; +import core.memory; +import core.thread; +import core.time; +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; +import core.stdc.wchar_; + +//version = traceGC; +version (traceGC) import tracegc; + +version = DebugServer; +//debug version = vdlog; // log through visual D logging (needs version = InProc in vdserverclient) + +shared(Object) gDMDSync = new Object; // no multi-instances/multi-threading with DMD +shared(Object) gOptSync = new Object; // no multi-instances/multi-threading with DMD + +version (traceGC) + extern(C) __gshared string[] rt_options = [ "scanDataSeg=precise", "gcopt=gc:trace disable:0" ]; +else + // precise GC doesn't help much because dmd erases most type info + extern(C) __gshared string[] rt_options = [ "scanDataSeg=precise", "gcopt=gc:precise" ]; + +/////////////////////////////////////////////////////////////////////// +version(DebugServer) +{ + import std.windows.charset; + import std.datetime; + version(vdlog) debug import visuald.logutil; + import core.stdc.stdio : fprintf, fopen, fputc, fflush, FILE; + __gshared FILE* dbgfh; + + void dbglog(const(char)[] s) + { + debug + { + version(vdlog) + logCall("DMDServer: ", s); + else + sdk.win32.winbase.OutputDebugStringA(toMBSz("DMDServer: " ~ s ~ "\n")); + } + else + { + if(!dbgfh) + dbgfh = fopen("c:/tmp/dmdserver.log", "w"); + + SysTime now = Clock.currTime(); + uint tid = sdk.win32.winbase.GetCurrentThreadId(); + auto len = fprintf(dbgfh, "%02d:%02d:%02d - %04x - ", + now.hour, now.minute, now.second, tid); + fprintf(dbgfh, "%.*s", s.length, s.ptr); + fputc('\n', dbgfh); + fflush(dbgfh); + } + } +} + +/////////////////////////////////////////////////////////////// +enum ModuleState +{ + New, + Pending, + Parsing, + Analyzing, + Done +} + +struct ModuleData +{ + string filename; + Module parsedModule; + Module analyzedModule; + + ModuleState state; + string parseErrors; + string analyzeErrors; +} + +/////////////////////////////////////////////////////////////// + +struct delegate_fake +{ + ptrdiff_t ptr; + ptrdiff_t context; +} + +class DMDServer : ComObject, IVDServer +{ + this() + { + version(unittest) {} else + version(SingleThread) mTid = spawn(&taskLoop, thisTid); + dmdInit(); + } + + override ULONG Release() + { + version(SingleThread) + if(count == 1 && mTid != mTid.init) + { + // avoid recursive calls if the object is temporarily ref-counted + // while executing Dispose() + count = 0x12345678; + + send(mTid, "stop"); + receive((string val) { assert(val == "done"); }); + + assert(count == 0x12345678); + count = 1; + } + return super.Release(); + } + + override HRESULT QueryInterface(in IID* riid, void** pvObject) + { +// MessageBoxW(null, "Object1.QueryInterface"w.ptr, "[LOCAL] message", MB_OK|MB_SETFOREGROUND); + if(queryInterface!(IVDServer) (this, riid, pvObject)) + return S_OK; + return super.QueryInterface(riid, pvObject); + } + + extern(D) static void taskLoop(Tid tid) + { + bool cont = true; + while(cont) + { + try + { + receiveTimeout(dur!"msecs"(50), + (delegate_fake dg_fake) + { + void delegate() dg = *(cast(void delegate()*)&dg_fake); + dg(); + }, + (string cmd) + { + if(cmd == "stop") + cont = false; + }, + (Variant var) + { + var = var; + } + ); + } + catch(OutOfMemoryError e) + { + exit(7); // terminate + } + catch(Throwable e) + { + version(DebugCmd) dbglog ("taskLoop exception: " ~ e.toString()); + } + } + prioritySend(tid, "done"); + } + + extern(D) void schedule(void delegate() dg) + { + version(unittest) + dg(); + else version(SingleThread) + send(mTid, *cast(delegate_fake*)&dg); + else + runTask(dg); + } + + override HRESULT ConfigureSemanticProject(in BSTR filename, in BSTR imp, in BSTR stringImp, in BSTR versionids, in BSTR debugids, DWORD flags) + { + string fname = to_string(filename); + + synchronized(gOptSync) + { + auto opts = &mOptions; + + string imports = to_string(imp); + string strImports = to_string(stringImp); + + uint oldflags = ConfigureFlags!()(opts.unittestOn, opts.debugOn, opts.x64, + opts.coverage, opts.doDoc, opts.noBoundsCheck, opts.gdcCompiler, + 0, 0, // no need to compare version levels, done in setVersionIds + opts.noDeprecated, opts.ldcCompiler, opts.msvcrt, opts.warnings, + opts.mixinAnalysis, opts.UFCSExpansions); + + opts.unittestOn = (flags & 1) != 0; + opts.debugOn = (flags & 2) != 0; + opts.x64 = (flags & 4) != 0; + opts.coverage = (flags & 8) != 0; + opts.doDoc = (flags & 16) != 0; + opts.noBoundsCheck = (flags & 32) != 0; + opts.gdcCompiler = (flags & 64) != 0; + opts.noDeprecated = (flags & 128) != 0; + opts.mixinAnalysis = (flags & 0x1_00_00_00) != 0; + opts.UFCSExpansions = (flags & 0x2_00_00_00) != 0; + opts.ldcCompiler = (flags & 0x4_00_00_00) != 0; + opts.msvcrt = (flags & 0x8_00_00_00) != 0; + opts.warnings = (flags & 0x10_00_00_00) != 0; + + int versionlevel = (flags >> 8) & 0xff; + int debuglevel = (flags >> 16) & 0xff; + + string verids = to_string(versionids); + string dbgids = to_string(debugids); + + int changed = (oldflags != (flags & 0xff0000ff)); + changed += opts.setImportDirs(splitLines(imports)); + changed += opts.setStringImportDirs(splitLines(strImports)); + changed += opts.setVersionIds(versionlevel, splitLines(verids)); + changed += opts.setDebugIds(debuglevel, splitLines(dbgids)); + } + return S_OK; + } + + override HRESULT ClearSemanticProject() + { + /+ + synchronized(mSemanticProject) + mSemanticProject.disconnectAll(); + + mSemanticProject = new vdc.semantic.Project; + mSemanticProject.saveErrors = true; + +/ + return S_OK; + } + + override HRESULT UpdateModule(in BSTR filename, in BSTR srcText, in DWORD flags) + { + string fname = makeFilenameCanonical(to_string(filename), null); + size_t len = wcslen(srcText); + string text = to_string(srcText, len + 1); // DMD parser needs trailing 0 + text = text[0..$-1]; + + ModuleData* modData; + bool doCancel = false; + synchronized(gErrorSync) + { + // cancel existing + modData = findModule(fname, false); + if (modData) + { + if (modData.state == ModuleState.Parsing || modData.state == ModuleState.Analyzing) + doCancel = true; + } + + // always create new module + modData = findModule(fname, true); + modData.state = ModuleState.Pending; + } + if (doCancel) + { + Mem.cancel = true; + synchronized(gDMDSync) + { + // wait for parsing done + Mem.cancel = false; + } + } + + void doParse() + { + version(DebugServer) dbglog(" doParse: " ~ firstLine(text)); + + string combinedErrorMessages() + { + string msgs = getErrorMessages(); + string otherMessages = getErrorMessages(true); + if (otherMessages.length) + msgs ~= "1,0,1,1: errors in imported modules: " ~ otherMessages.replace("\n", "\a"); + return msgs; + } + + synchronized(gErrorSync) + { + modData.state = ModuleState.Parsing; + } + synchronized(gDMDSync) + { + try + { + initErrorMessages(fname); + modData.parsedModule = createModuleFromText(fname, text); + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("UpdateModule.doParse: exception " ~ t.toString()); + } + modData.parseErrors = combinedErrorMessages(); + + modData.state = ModuleState.Analyzing; + try + { + initErrorMessages(fname); + // clear all other semantic modules? + analyzeModules(modData); + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("UpdateModule.doParse: exception " ~ t.toString()); + } + modData.analyzeErrors = combinedErrorMessages(); + modData.state = ModuleState.Done; + } + + if(flags & 1) + writeReadyMessage(); + } + version(DebugServer) dbglog(" scheduleParse: " ~ firstLine(text)); + schedule(&doParse); + return S_OK; + } + + override HRESULT GetParseErrors(in BSTR filename, BSTR* errors) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + if(auto md = findModule(fname, false)) + { + synchronized(gErrorSync) + { + if (md.state == ModuleState.Done) + { + string err = md.parseErrors ~ md.analyzeErrors; + version(DebugServer) + dbglog("GetParseErrors: " ~ err); + + *errors = allocBSTR(err); + return S_OK; + } + } + } + return S_FALSE; + } + + override HRESULT GetTip(in BSTR filename, int startLine, int startIndex, int endLine, int endIndex, int flags) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + mTipSpan.start.line = startLine; + mTipSpan.start.index = startIndex; + mTipSpan.end.line = endLine; + mTipSpan.end.index = endIndex; + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md) + return S_FALSE; + } + + void _getTip() + { + string txt; + synchronized(gDMDSync) + { + try + { + if (auto m = md.analyzedModule) + txt = findTip(m, startLine, startIndex + 1, endLine, endIndex + 1); + else + txt = "analyzing..."; + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("GetTip: exception " ~ t.toString()); + txt = "exception: " ~ t.msg; + } + } + mLastTip = txt; + mSemanticTipRunning = false; + } + version(DebugServer) dbglog(" schedule GetTip: " ~ fname); + mSemanticTipRunning = true; + schedule(&_getTip); + + return S_OK; + } + + override HRESULT GetTipResult(ref int startLine, ref int startIndex, ref int endLine, ref int endIndex, BSTR* answer) + { + if(mSemanticTipRunning) + { + *answer = allocBSTR("__pending__"); + return S_OK; + } + + version(DebugServer) dbglog("GetTipResult: " ~ mLastTip); + writeReadyMessage(); + startLine = mTipSpan.start.line; + startIndex = mTipSpan.start.index; + endLine = mTipSpan.end.line; + endIndex = mTipSpan.end.index; + *answer = allocBSTR(mLastTip); + return S_OK; + } + + override HRESULT GetDefinition(in BSTR filename, int startLine, int startIndex, int endLine, int endIndex) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + mDefSpan.start.line = startLine; + mDefSpan.start.index = startIndex + 1; + mDefSpan.end.line = endLine; + mDefSpan.end.index = endIndex; // last character preferred position for evaluation + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md) + return S_FALSE; + } + + void _getDefinition() + { + string deffilename; + synchronized(gDMDSync) + { + try + { + if (auto m = md.analyzedModule) + deffilename = findDefinition(m, mDefSpan.end.line, mDefSpan.end.index); + else + deffilename = "analyzing..."; + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("GetDefinition: exception " ~ t.toString()); + } + } + mLastDefFile = deffilename; + mSemanticDefinitionRunning = false; + } + version(DebugServer) dbglog(" schedule GetDefinition: " ~ fname); + mSemanticDefinitionRunning = true; + schedule(&_getDefinition); + + return S_OK; + } + + override HRESULT GetDefinitionResult(ref int startLine, ref int startIndex, ref int endLine, ref int endIndex, BSTR* answer) + { + if(mSemanticDefinitionRunning) + { + *answer = allocBSTR("__pending__"); + return S_OK; + } + + version(DebugServer) dbglog("GetDefinitionResult: " ~ mLastDefFile); + writeReadyMessage(); + startLine = mDefSpan.end.line; + startIndex = mDefSpan.end.index - 1; + endLine = mDefSpan.end.line; + endIndex = mDefSpan.end.index; + *answer = allocBSTR(mLastDefFile); + return S_OK; + } + + override HRESULT GetSemanticExpansions(in BSTR filename, in BSTR tok, uint line, uint idx, in BSTR expr) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md) + return S_FALSE; + } + + string stok = to_string(tok); + string sexpr = to_string(expr); + void _calcExpansions() + { + string[] symbols; + try + { + if (auto m = md.analyzedModule) + symbols = findExpansions(m, line, idx + 1 - cast(int) stok.length, stok); + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("calcExpansions: exception " ~ t.toString()); + } + mSemanticExpansionsRunning = false; + mLastSymbols = symbols; + } + version(DebugServer) dbglog(" schedule GetSemanticExpansions: " ~ fname); + mLastSymbols = null; + mSemanticExpansionsRunning = true; + schedule(&_calcExpansions); + + return S_OK; + } + + override HRESULT GetSemanticExpansionsResult(BSTR* stringList) + { + if(mSemanticExpansionsRunning) + return S_FALSE; + + Appender!string slist; + foreach(sym; mLastSymbols) + { + slist.put(sym); + slist.put('\n'); + } + *stringList = allocBSTR(slist.data); + + version(DebugServer) dbglog("GetSemanticExpansionsResult: " ~ slist.data); + writeReadyMessage(); + return S_OK; + } + + // obsolete, implement GetBinaryIsInLocations + override HRESULT IsBinaryOperator(in BSTR filename, uint startLine, uint startIndex, uint endLine, uint endIndex, BOOL* pIsOp) + { + if(!pIsOp) + return E_POINTER; + + *pIsOp = false; + return S_OK; + } + + override HRESULT ConfigureCommentTasks(in BSTR tasks) + { + return E_NOTIMPL; + } + + override HRESULT GetCommentTasks(in BSTR filename, BSTR* tasks) + { + return E_NOTIMPL; + } + + override HRESULT GetBinaryIsInLocations(in BSTR filename, VARIANT* locs) + { + // array of pairs of DWORD + string fname = makeFilenameCanonical(to_string(filename), null); + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md || !md.parsedModule) + return S_FALSE; + } + + Loc[] locData = findBinaryIsInLocations(md.parsedModule); + + SAFEARRAY *sa = SafeArrayCreateVector(VT_INT, 0, 2 * cast(ULONG) locData.length); + if(!sa) + return E_OUTOFMEMORY; + + for(LONG index = 0; index < locData.length; index++) + { + LONG idx = index * 2; + LONG value = locData[index].linnum; + SafeArrayPutElement(sa, &idx, &value); + idx++; + value = locData[index].charnum - 1; + SafeArrayPutElement(sa, &idx, &value); + } + + locs.vt = VT_ARRAY | VT_INT; + locs.parray = sa; + return S_OK; + } + + override HRESULT GetLastMessage(BSTR* message) + { + if(!mLastMessage.length) + { + if(mNextReadyMessage > Clock.currTime()) + return S_FALSE; + + mLastMessage = "Ready"; + mNextReadyMessage = Clock.currTime().add!"years"(1); + } + *message = allocBSTR(mLastMessage); + mLastMessage = null; + return S_OK; + } + + override HRESULT GetReferences(in BSTR filename, in BSTR tok, uint line, uint idx, in BSTR expr, in BOOL moduleOnly) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md) + return S_FALSE; + } + + void _getReferences() + { + string references; + synchronized(gDMDSync) + { + try + { + if (auto m = md.analyzedModule) + { + auto reflocs = findReferencesInModule(m, line, idx + 1); + + char[128] buf; + foreach (ref r; reflocs) + { + int llen = snprintf(buf.ptr, buf.length, "%d,%d,%d,%d:\n", + r.loc.linnum, r.loc.charnum - 1, + r.loc.linnum, r.loc.charnum - 1 + r.ident.toString().length); + references ~= buf[0..llen]; + } + } + else + references = "analyzing..."; + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("GetReferences: exception " ~ t.toString()); + } + } + mLastReferences = references; + mSemanticGetReferencesRunning = false; + } + version(DebugServer) dbglog(" schedule GetReferences: " ~ fname); + mSemanticGetReferencesRunning = true; + schedule(&_getReferences); + + return S_OK; + } + + override HRESULT GetReferencesResult(BSTR* stringList) + { + if(mSemanticGetReferencesRunning) + { + *stringList = allocBSTR("__pending__"); + return S_OK; + } + *stringList = allocBSTR(mLastReferences); + return S_OK; + } + + HRESULT GetIdentifierTypes(in BSTR filename, int startLine, int endLine, int flags) + { + string fname = makeFilenameCanonical(to_string(filename), null); + + mIdTypesSpan.start.line = startLine; // unused so far + mIdTypesSpan.start.index = 0; + mIdTypesSpan.end.line = endLine; + mIdTypesSpan.end.index = 0; + + ModuleData* md; + synchronized(gErrorSync) + { + md = findModule(fname, false); + if (!md) + return S_FALSE; + } + + void _getIdentifierTypes() + { + string identiferTypes; + synchronized(gDMDSync) + { + try + { + if (auto m = md.analyzedModule) + { + auto res = findIdentifierTypes(m); + identiferTypes = findIdentifierTypesResultToString(res); + } + else + identiferTypes = "identifying..."; + } + catch(OutOfMemoryError e) + { + throw e; // terminate + } + catch(Throwable t) + { + version(DebugServer) dbglog("GetIdentifierTypes: exception " ~ t.toString()); + } + } + mLastIdentifierTypes = identiferTypes; + mSemanticIdentifierTypesRunning = false; + } + version(DebugServer) dbglog(" schedule GetIdentifierTypes: " ~ fname); + mSemanticIdentifierTypesRunning = true; + schedule(&_getIdentifierTypes); + + return S_OK; + } + + HRESULT GetIdentifierTypesResult(BSTR* types) + { + if(mSemanticIdentifierTypesRunning) + { + *types = allocBSTR("__pending__"); + return S_OK; + } + *types = allocBSTR(mLastIdentifierTypes); + return S_OK; + } + + /////////////////////////////////////////////////////////////// + // create our own task pool to be able to destroy it (it keeps a the + // arguments to the last task, so they are never collected) + __gshared TaskPool parseTaskPool; + + void runTask(T)(T dg) + { + if(!parseTaskPool) + { + int threads = defaultPoolThreads; + if(threads < 1) + threads = 1; + parseTaskPool = new TaskPool(threads); + parseTaskPool.isDaemon = true; + parseTaskPool.priority(core.thread.Thread.PRIORITY_MIN); + } + auto task = task(dg); + parseTaskPool.put(task); + } + + void writeReadyMessage() + { + if(mHadMessage) + { + mNextReadyMessage = Clock.currTime() + dur!"seconds"(2); + mHadMessage = false; + } + } + + void analyzeModules(ModuleData* rootModule) + { + if (rootModule.parsedModule) + rootModule.analyzedModule = analyzeModule(rootModule.parsedModule, mOptions); + + version(none) { + + version(none) + { + clearDmdStatics(); + + // (de-)initialization + Type.deinitialize(); + //Id.deinitialize(); + Module.deinitialize(); + target.deinitialize(); + Expression.deinitialize(); + Objc.deinitialize(); + builtinDeinitialize(); + Token._init(); + Module._init(); + } + + Module.rootModule = null; + global = global.init; + + version(DebugServer) + { + core.memory.GC.Stats stats = GC.stats(); + dbglog(text("before collect GC stats: ", stats.usedSize, " used, ", stats.freeSize, " free\n")); + } + + version(traceGC) + { + wipeStack(); + GC.collect(); + dumpGC(); + } + else + { + GC.collect(); + } + + version(DebugServer) + { + stats = GC.stats(); + dbglog(text("after collect GC stats: ", stats.usedSize, " used, ", stats.freeSize, " free\n")); + } + + synchronized(gOptSync) + { + global._init(); + global.params.isWindows = true; + global.params.errorLimit = 0; + global.params.color = false; + global.params.link = true; + global.params.useAssert = mOptions.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useInvariants = mOptions.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useIn = mOptions.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useOut = mOptions.debugOn ? CHECKENABLE.on : CHECKENABLE.off; + global.params.useArrayBounds = mOptions.noBoundsCheck ? CHECKENABLE.on : CHECKENABLE.off; // set correct value later + global.params.doDocComments = mOptions.doDoc; + global.params.useSwitchError = CHECKENABLE.on; + global.params.useInline = false; + global.params.obj = false; + global.params.useDeprecated = mOptions.noDeprecated ? DiagnosticReporting.error : DiagnosticReporting.off; + global.params.linkswitches = Strings(); + global.params.libfiles = Strings(); + global.params.dllfiles = Strings(); + global.params.objfiles = Strings(); + global.params.ddocfiles = Strings(); + // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd + global.params.is64bit = mOptions.x64; + global.params.mscoff = mOptions.msvcrt; + global.params.cpu = CPU.baseline; + global.params.isLP64 = global.params.is64bit; + + global.params.versionlevel = mOptions.versionLevel; + global.params.versionids = new Strings(); + foreach(v; mOptions.versionIds) + global.params.versionids.push(toStringz(v)); + + global.versionids = new Identifiers(); + + // Add in command line versions + if (global.params.versionids) + foreach (charz; *global.params.versionids) + { + auto ident = charz[0 .. strlen(charz)]; + if (VersionCondition.isReserved(ident)) + VersionCondition.addPredefinedGlobalIdent(ident); + else + VersionCondition.addGlobalIdent(ident); + } + + if (mPredefineVersions) + addDefaultVersionIdentifiers(global.params); + + // always enable for tooltips + global.params.doDocComments = true; + + global.params.debugids = new Strings(); + global.params.debuglevel = mOptions.debugLevel; + foreach(d; mOptions.debugIds) + global.params.debugids.push(toStringz(d)); + + global.debugids = new Identifiers(); + if (global.params.debugids) + foreach (charz; *global.params.debugids) + DebugCondition.addGlobalIdent(charz[0 .. strlen(charz)]); + + global.path = new Strings(); + foreach(i; mOptions.importDirs) + global.path.push(toStringz(i)); + + global.filePath = new Strings(); + foreach(i; mOptions.stringImportDirs) + global.filePath.push(toStringz(i)); + } + + dmdReinit(); + + for (size_t i = 0; i < mModules.length; i++) + { + ModuleData* md = mModules[i]; + if (Module m = cloneModule(md.parsedModule)) + { + m.importedFrom = m; + m = m.resolvePackage(); + md.analyzedModule = m; + Module.modules.insert(m); + } + } + Module.rootModule = rootModule.analyzedModule; + Module.loadModuleHandler = (const ref Loc location, IdentifiersAtLoc* packages, Identifier ident) + { + return Module.loadFromFile(location, packages, ident); + }; + + for (size_t i = 0; i < mModules.length; i++) + { + if (Module m = mModules[i].analyzedModule) + m.importAll(null); + } + +version(all) +{ + if (Module.rootModule) + { + Module.rootModule.dsymbolSemantic(null); + Module.dprogress = 1; + Module.runDeferredSemantic(); + Module.rootModule.semantic2(null); + Module.runDeferredSemantic2(); + Module.rootModule.semantic3(null); + Module.runDeferredSemantic3(); + } +} +else +{ + // Do semantic analysis + for (size_t i = 0; i < modules.length; i++) + { + Module m = mModules[i].analyzedModule; + m.dsymbolSemantic(null); + } + + Module.dprogress = 1; + Module.runDeferredSemantic(); + + // Do pass 2 semantic analysis + for (size_t i = 0; i < modules.length; i++) + { + Module m = modules[i]; + m.semantic2(null); + } + Module.runDeferredSemantic2(); + + // Do pass 3 semantic analysis + for (size_t i = 0; i < modules.length; i++) + { + Module m = modules[i]; + m.semantic3(null); + } + Module.runDeferredSemantic3(); +} +} + } + +private: + ModuleData* findModule(string fname, bool createNew) + { + size_t pos = mModules.length; + foreach (i, m; mModules) + if (m.filename == fname) + { + if (createNew) + { + pos = i; + break; + } + return m; + } + + if (!createNew) + return null; + + auto md = new ModuleData; + md.filename = fname; + if (pos < mModules.length) + mModules[pos] = md; + else + mModules ~= md; + return md; + } + + version(SingleThread) Tid mTid; + + Options mOptions; + ModuleData*[] mModules; + + bool mSemanticExpansionsRunning; + bool mSemanticTipRunning; + bool mSemanticDefinitionRunning; + bool mSemanticIdentifierTypesRunning; + bool mSemanticGetReferencesRunning; + + bool mPredefineVersions; + + string mModuleToParse; + string mLastTip; + TextSpan mTipSpan; + + string mLastDefFile; + TextSpan mDefSpan; + + string mLastIdentifierTypes; + TextSpan mIdTypesSpan; + + string mLastReferences; + string[] mLastSymbols; + string mLastMessage; + string mLastError; + bool mHadMessage; + SysTime mNextReadyMessage; +} + +//////////////////////////////////////////////////////////////// + +string idPositionsToString(IdTypePos[] pos) +{ + string ids = pos[0].type.to!string(); + foreach (ref p; pos[1..$]) + ids ~= ";" ~ p.type.to!string() ~ "," ~ p.line.to!string() ~ "," ~ (p.col - 1).to!string(); + return ids; +} + +string findIdentifierTypesResultToString(FindIdentifierTypesResult res) +{ + string s; + foreach(id, pos; res) + { + string ids = id.idup ~ ":" ~ idPositionsToString(pos); + s ~= ids ~ "\n"; + } + return s; +} + +//////////////////////////////////////////////////////////////// + +extern(C) int _CrtDumpMemoryLeaks(); +extern(C) void dumpGC(); + +//////////////////////////////////////////////////////////////// +unittest +{ + //_CrtDumpMemoryLeaks(); + version(traceGC) + dumpGC(); + + DMDServer srv = newCom!DMDServer; + srv.mPredefineVersions = true; + srv.mOptions.predefineDefaultVersions = true; + addref(srv); + scope(exit) release(srv); + + auto filename = allocBSTR("source.d"); + auto imp = allocBSTR(guessImportPaths().join("\n")); + auto empty = allocBSTR(""); + uint flags = ConfigureFlags!()(false, //bool unittestOn + false, //bool debugOn, + true, //bool x64 + false, //bool cov + false, //bool doc, + false, //bool nobounds, + false, //bool gdc, + 0, //int versionLevel, + 0, //int debugLevel, + false, //bool noDeprecated, + false, //bool ldc, + true, //bool msvcrt, + false, //bool warnings, + true, //bool mixinAnalysis, + true); //bool ufcsExpansionsfalse, + + HRESULT hr; + hr = srv.ConfigureSemanticProject(filename, imp, empty, empty, empty, flags); + assert(hr == S_OK); + + void checkErrors(string src, string expected_err) + { + auto source = allocBSTR(src); + HRESULT hr = srv.UpdateModule(filename, source, false); + assert(hr == S_OK); + BSTR errors; + while (srv.GetParseErrors(filename, &errors) == S_FALSE) + Thread.sleep(10.msecs); + + string err = detachBSTR(errors); + assert(err == expected_err); + freeBSTR(source); + } + + void checkTip(int line, int col, string expected_tip) + { + HRESULT hr = srv.GetTip(filename, line, col, line, col + 1, 0); + assert(hr == S_OK); + BSTR bstrTip; + int startLine, startIndex, endLine, endIndex; + while (srv.GetTipResult(startLine, startIndex, endLine, endIndex, &bstrTip) == S_FALSE || _stricmp(bstrTip, "__pending__"w) == 0) + { + detachBSTR(bstrTip); + Thread.sleep(10.msecs); + } + + string tip = detachBSTR(bstrTip); + assert(tip == expected_tip); + } + + void checkDefinition(int line, int col, string expected_fname, int expected_line, int expected_col) + { + HRESULT hr = srv.GetDefinition(filename, line, col, line, col + 1); + assert(hr == S_OK); + BSTR bstrFile; + int startLine, startIndex, endLine, endIndex; + while (srv.GetDefinitionResult(startLine, startIndex, endLine, endIndex, &bstrFile) == S_FALSE || _stricmp(bstrFile, "__pending__"w) == 0) + { + detachBSTR(bstrFile); + Thread.sleep(10.msecs); + } + + string file = detachBSTR(bstrFile); + assert(file == expected_fname); + assert(startLine == expected_line); + assert(startIndex == expected_col); + } + + string source; +/+ + source = q{ + int main() + { + return abc; + } + }; + checkErrors(source, "4,10,4,11:undefined identifier `abc`\n"); + + GC.collect(); + + source = q{ + int main() + { + return abcd; + } + }; + checkErrors(source, "4,10,4,11:undefined identifier `abcd`\n"); ++/ + version(traceGC) + wipeStack(); + GC.collect(); + + //_CrtDumpMemoryLeaks(); + version(traceGC) + dumpGC(); + + for (int i = 0; i < 2; i++) + { + srv.mModules = null; + //clearDmdStatics (); + + source = q{ + import std.stdio; + int main(string[] args) + { + int xyz = 7; + writeln(1, 2, 3); + return xyz; + } + }; + checkErrors(source, ""); + + version(traceGC) + wipeStack(); + GC.collect(); + + //_CrtDumpMemoryLeaks(); + version(traceGC) + dumpGC(); + } + + checkTip(5, 9, "(local variable) `int xyz`"); + checkTip(6, 9, "`void std.stdio.writeln!(int, int, int)(int _param_0, int _param_1, int _param_2) @safe`"); + checkTip(7, 12, "(local variable) `int xyz`"); + + version(traceGC) + wipeStack(); + GC.collect(); + + checkDefinition(7, 12, "source.d", 5, 8); // xyz +} diff --git a/vdc/dmdserver/dmdserver.idl b/vdc/dmdserver/dmdserver.idl new file mode 100644 index 00000000..da5b50f3 --- /dev/null +++ b/vdc/dmdserver/dmdserver.idl @@ -0,0 +1,25 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2012 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +// bring in core IDL files +import "oaidl.idl"; +import "../ivdserver.idl"; + +// library statement +[uuid(002a2de9-8bb6-484d-9907-7e4ad4084715), version(1.0), + helpstring("DMD Semantic Server")] +library VDServerLib +{ + importlib("stdole32.tlb"); + [uuid(002a2de9-8bb6-484d-9906-7e4ad4084715)] + coclass VDServerClassFactory + { + [default] interface IVDServer; + }; +}; + diff --git a/vdc/dmdserver/dmdserver.rc b/vdc/dmdserver/dmdserver.rc new file mode 100644 index 00000000..8f978b4f --- /dev/null +++ b/vdc/dmdserver/dmdserver.rc @@ -0,0 +1,85 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +///////////////////////////////////////////////////////////////////////////// +// Resources for the Visual D semantic server +// +1 TYPELIB dmdserver.tlb + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#define __str(x) #x +#define _str(x) __str(x) + +#include "../../version" + +#if VERSION_BUILD > 0 +#define VERSION_POSTFIX _str(VERSION_BETA) _str(VERSION_BUILD) +#else +#define VERSION_POSTFIX +#endif + +#define VER_COMPANYNAME_STR "Rainer Schuetze" +#define VER_FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_REVISION +#define VER_FILEVERSION_STR _str(VERSION_MAJOR.VERSION_MINOR.VERSION_REVISION) VERSION_POSTFIX +#define VER_PRODUCTVERSION VER_FILEVERSION +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR +#define VER_LEGALCOPYRIGHT_STR "(c) 2017 Rainer Schuetze" + +#define VER_FILEDESCRIPTION_STR "DMD Semantic Server\0" +#define VER_PRODUCTNAME_STR "DMDServer\0" +#define VER_INTERNALNAME_STR "dmdserver.exe\0" +#define VER_ORIGINALFILENAME_STR "dmdserver.exe\0" +#define VER_LANGUAGENEUTRAL + +#define VER_FILEFLAGSMASK 0x3fL +#define VER_FILEFLAGS 0x8L +#define VER_FILEOS 0x40004L +#define VER_FILETYPE 0x1L // VS_APP +#define VER_FILESUBTYPE 0x0L // unknown + +#define VER_BLOCKHEADER "040904b0" +#define VER_TRANSLATION 0x409 + +///////////////////////////////////////////////////////////////////////////// +#define VS_VERSION_INFO 1 + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEFLAGSMASK VER_FILEFLAGSMASK +FILEFLAGS VER_FILEFLAGS +FILEOS VER_FILEOS +FILETYPE VER_FILETYPE +FILESUBTYPE VER_FILESUBTYPE +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK VER_BLOCKHEADER + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", VER_FILEDESCRIPTION_STR + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", VER_INTERNALNAME_STR + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR + VALUE "ProductName", VER_PRODUCTNAME_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", VER_TRANSLATION, 0x04B0 + END +END + +IDI_VISUALD ICON "dmdicon.ico" + +///////////////////////////////////////////////////////////////////////////// diff --git a/vdc/dmdserver/dmdserver.visualdproj b/vdc/dmdserver/dmdserver.visualdproj new file mode 100644 index 00000000..dea639c9 --- /dev/null +++ b/vdc/dmdserver/dmdserver.visualdproj @@ -0,0 +1,1627 @@ + + {34289BD7-AB7E-4264-B146-8139DDE9F0BF} + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -cpp -Isrc;src\backend;src\tk;src\root -DMARS -e -wx -DTARGET_WINDOS=1 -DDM_TARGET_CPU_X86=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend + 0 + 0 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -cpp -Isrc;src\backend;src\tk;src\root -DMARS -e -wx -DTARGET_WINDOS=1 -DDM_TARGET_CPU_X86=1 + 1 + 0 + $(DMDInstallDir)windows\bin\dmd.exe + dmd\src ..\.. + $(OutDir) ..\..\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS + 0 + 0 + 0 + 0 + + + + 0 + + 0 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 1 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -nologo -c -TP -Idmd\src -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\vcbuild -DTARGET_WINDOS=1 -FIwarnings.h + 1 + 1 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend + 0 + 1 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 2 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -nologo -c -TP -Isrc -Isrc\backend -Isrc\tk -Isrc\root -Isrc\vcbuild -DTARGET_WINDOS=1 -FIvcbuild\warnings.h + 1 + 0 + $(DMDInstallDir)windows\bin\dmd.exe + dmd\src ..\.. + $(OutDir) ..\..\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS + 0 + 0 + 0 + 0 + + + + 0 + + 0 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 1 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -nologo -c -TP -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC LanguageServer + 0 + 1 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -nologo -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + + dmd\src ..\.. $(DMDInstallDir)\src\druntime\src + dmd dmd\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC LanguageServer + 0 + 1 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 1 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 -gf + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -nologo -c -TP -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC + 0 + 2 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + $(CC) -c -nologo -c -TP -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 0 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC + 0 + 0 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -nologo -c -TP -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. + dmd dmd\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC LanguageServer + 0 + 2 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 -check=assert + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -c -nologo -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DTARGET_WINDOS=1 + 1 + 0 + c:\s\d\dlang\dmd\generated\Windows\Release\x64\dmd.exe + dmd\src ..\.. $(DMDInstallDir)\src\druntime\src + dmd dmd\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC LanguageServer + 0 + 0 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 0 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 -gf -check=assert + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + c:\l\dmc\bin\dmc -c -Idmd\src\dmd -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\dmd\vcbuild -DMARS -e -wx -DTARGET_WINDOS=1 -DDM_TARGET_CPU_X86=1 + 1 + 0 + c:\l\d\dmd2\windows\bin\dmd.exe + dmd\src ..\.. $(DMDInstallDir)\src\druntime\src + dmd dmd\res + ..\..\bin\$(ConfigurationName) + $(OutDir)\$(PlatformName)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC LanguageServer + 0 + 0 + 0 + 0 + + + + 0 + + 2 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + -s. + 1 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 1 + -L/STACK:8388608 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + $(CC) -nologo -c -Idmd\src -Idmd\src\dmd\backend -Idmd\src\dmd\tk -Idmd\src\dmd\root -Idmd\src\vcbuild -DTARGET_WINDOS=1 -FIwarnings.h + 1 + 1 + c:\s\d\rainers\windows\bin\dmd.exe + dmd\src ..\.. $(DMDInstallDir)\src\druntime\src $(DMDInstallDir)\druntime\src + dmd dmd\res + ..\..\bin\$(ConfigurationName)\$(PlatformName) + $(OutDir)\$(ProjectName) + + + 0 + + + + + 0 + + + 1 + $(IntDir)\$(TargetName).json + 0 + + 0 + MARS NoBackend GC TEST LanguageServer + 0 + 3 + 0 + 0 + + + + 0 + + 1 + $(VisualDInstallDir)cv2pdb\cv2pdb.exe + 0 + 0 + + 1 + $(IntDir)\$(SafeProjectName).mixin + + + ole32.lib oleaut32.lib + + + + $(OutDir)\$(ProjectName).exe + $(IntDir)\$(SafeProjectName).pdb + $(IntDir)\$(SafeProjectName).lib + $(IntDir)\$(SafeProjectName).map + 1 + 2 + 0 + -L/STACK:8388608 -verrors=0 + + + *.obj;*.cmd;*.build;*.json;*.dep + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vdc/dmdserver/semanalysis.d b/vdc/dmdserver/semanalysis.d new file mode 100644 index 00000000..c39d219c --- /dev/null +++ b/vdc/dmdserver/semanalysis.d @@ -0,0 +1,1203 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2012 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.dmdserver.semanalysis; + +import vdc.dmdserver.dmdinit; +import vdc.dmdserver.dmderrors; +import vdc.dmdserver.semvisitor; +import vdc.ivdserver; + +import dmd.arraytypes; +import dmd.cond; +import dmd.dmodule; +import dmd.dsymbolsem; +import dmd.errors; +import dmd.globals; +import dmd.identifier; +import dmd.semantic2; +import dmd.semantic3; + +__gshared AnalysisContext lastContext; + +struct ModuleInfo +{ + Module parsedModule; + Module semanticModule; + + Module createSemanticModule() + { + Module m = cloneModule(parsedModule); + m.importedFrom = m; + m.resolvePackage(); // adds module to Module.amodules (ignore return which could be module with same name) + semanticModule = m; + Module.modules.insert(m); + return m; + } +} + +// context is kept as long as the options don't change +class AnalysisContext +{ + Options options; + + ModuleInfo[] modules; + + int findModuleInfo(Module parsedMod) + { + foreach (ref i, inf; modules) + if (parsedMod is inf.parsedModule) + return cast(int) i; + return -1; + } + int findModuleInfo(const(char)[] filename) + { + foreach (ref i, inf; modules) + if (filename == inf.parsedModule.srcfile.toString()) + return cast(int)i; + return -1; + } +} + +// is the module already added implicitly during semantic analysis? +Module findInAllModules(const(char)[] filename) +{ + foreach(m; Module.amodules) + { + if (m.srcfile.toString() == filename) + return m; + } + return null; +} + +// +Module analyzeModule(Module parsedModule, const ref Options opts) +{ + int rootModuleIndex = -1; + bool needsReinit = true; + + if (!lastContext) + lastContext = new AnalysisContext; + AnalysisContext ctxt = lastContext; + + auto filename = parsedModule.srcfile.toString(); + int idx = ctxt.findModuleInfo(filename); + if (ctxt.options == opts) + { + if (idx >= 0) + { + if (parsedModule !is ctxt.modules[idx].parsedModule) + { + // module updated, replace it + ctxt.modules[idx].parsedModule = parsedModule; + + // TODO: only update dependent modules + } + else + { + if (!ctxt.modules[idx].semanticModule) + { + auto m = ctxt.modules[rootModuleIndex].createSemanticModule(); + m.importAll(null); + } + needsReinit = false; + } + rootModuleIndex = idx; + } + else + { + ctxt.modules ~= ModuleInfo(parsedModule); + rootModuleIndex = cast(int)(ctxt.modules.length - 1); + + // is the module already added implicitly during semantic analysis? + auto ma = findInAllModules(filename); + if (ma is null) + { + // if not, no other module depends on it, so just append + auto m = ctxt.modules[rootModuleIndex].createSemanticModule(); + m.importAll(null); + needsReinit = false; + } + else + { + // TODO: check if the same as m + auto m = ctxt.modules[rootModuleIndex].createSemanticModule(); + m.importAll(null); + // TODO: only update dependent modules + } + } + } + else + { + ctxt.options = opts; + dmdSetupParams(opts); + + if (idx >= 0) + { + ctxt.modules[idx].parsedModule = parsedModule; + rootModuleIndex = idx; + } + else + { + ctxt.modules ~= ModuleInfo(parsedModule); + rootModuleIndex = cast(int)(ctxt.modules.length - 1); + } + } + + Module.loadModuleHandler = (const ref Loc location, IdentifiersAtLoc* packages, Identifier ident) + { + // only called if module not found in Module.amodules + return Module.loadFromFile(location, packages, ident); + }; + + if (needsReinit) + { + dmdReinit(); + + foreach(ref mi; ctxt.modules) + { + mi.createSemanticModule(); + } + + version(none) // do this lazily + foreach(ref mi; ctxt.modules) + { + mi.semanticModule.importAll(null); + } + } + + Module.rootModule = ctxt.modules[rootModuleIndex].semanticModule; + Module.rootModule.importAll(null); + Module.rootModule.dsymbolSemantic(null); + Module.dprogress = 1; + Module.runDeferredSemantic(); + Module.rootModule.semantic2(null); + Module.runDeferredSemantic2(); + Module.rootModule.semantic3(null); + Module.runDeferredSemantic3(); + + return Module.rootModule; +} + +//////////////////////////////////////////////////////////////// +//version = traceGC; +//import tracegc; +extern(Windows) void OutputDebugStringA(const(char)* lpOutputString); + +string[] guessImportPaths() +{ + import std.file; + + if (std.file.exists(r"c:\s\d\dlang\druntime\import\object.d")) + return [ r"c:\s\d\dlang\druntime\import", r"c:\s\d\dlang\phobos" ]; + if (std.file.exists(r"c:\s\d\rainers\druntime\import\object.d")) + return [ r"c:\s\d\rainers\druntime\import", r"c:\s\d\rainers\phobos" ]; + return [ r"c:\d\dmd2\src\druntime\import", r"c:\s\d\rainers\src\phobos" ]; +} + +unittest +{ + import core.memory; + + dmdInit(); + dmdReinit(); + lastContext = null; + + Options opts; + opts.predefineDefaultVersions = true; + opts.x64 = true; + opts.msvcrt = true; + opts.warnings = true; + opts.unittestOn = true; + opts.importDirs = guessImportPaths(); + + auto filename = "source.d"; + + static void assert_equal(S, T)(S s, T t) + { + if (s == t) + return; + assert(false); + } + + Module checkErrors(string src, string expected_err) + { + initErrorMessages(filename); + Module parsedModule = createModuleFromText(filename, src); + assert(parsedModule); + Module m = analyzeModule(parsedModule, opts); + auto err = getErrorMessages(); + auto other = getErrorMessages(true); + assert_equal(err, expected_err); + assert_equal(other, ""); + return m; + } + + void checkTip(Module analyzedModule, int line, int col, string expected_tip) + { + string tip = findTip(analyzedModule, line, col, line, col + 1); + assert_equal(tip, expected_tip); + } + + void checkDefinition(Module analyzedModule, int line, int col, string expected_fname, int expected_line, int expected_col) + { + string file = findDefinition(analyzedModule, line, col); + assert_equal(file, expected_fname); + assert_equal(line, expected_line); + assert_equal(col, expected_col); + } + + void checkBinaryIsInLocations(string src, Loc[] locs) + { + initErrorMessages(filename); + Module parsedModule = createModuleFromText(filename, src); + auto err = getErrorMessages(); + assert(err == null); + assert(parsedModule); + Loc[] locdata = findBinaryIsInLocations(parsedModule); + assert(locdata.length == locs.length); + L_nextLoc: + foreach(i; 0 .. locdata.length) + { + // not listed twice + foreach(ref loc; locdata[i+1 .. $]) + assert(locdata[i].linnum != loc.linnum || locdata[i].charnum != loc.charnum); + // found in results + foreach(ref loc; locs) + if(locdata[i].linnum == loc.linnum && locdata[i].charnum == loc.charnum) + continue L_nextLoc; + assert(false); + } + } + + void checkExpansions(Module analyzedModule, int line, int col, string tok, string[] expected) + { + import std.algorithm, std.array; + string[] expansions = findExpansions(analyzedModule, line, col, tok); + expansions.sort(); + expected.sort(); + assert_equal(expansions.length, expected.length); + for (size_t i = 0; i < expansions.length; i++) + assert_equal(expansions[i].split(':')[0], expected[i]); + } + + void checkIdentifierTypes(Module analyzedModule, IdTypePos[][string] expected) + { + static void assert_equalPositions(IdTypePos[] s, IdTypePos[] t) + { + assert_equal(s.length, t.length); + assert_equal(s[0].type, t[0].type); + foreach (i; 1.. s.length) + assert_equal(s[i], t[i]); + } + import std.algorithm, std.array, std.string; + auto idtypes = findIdentifierTypes(analyzedModule); + assert_equal(idtypes.length, expected.length); + auto ids = idtypes.keys(); + ids.sort(); + foreach (i, id; ids) + assert_equalPositions(idtypes[id], expected[id]); + } + + static struct TextPos + { + int line; + int column; + } + void checkReferences(Module analyzedModule, int line, int col, TextPos[] expected) + { + import std.algorithm, std.array, std.string; + auto refs = findReferencesInModule(analyzedModule, line, col); + assert_equal(refs.length, expected.length); + for (size_t i = 0; i < refs.length; i++) + { + assert_equal(refs[i].loc.linnum, expected[i].line); + assert_equal(refs[i].loc.charnum, expected[i].column); + } + } + + void dumpAST(Module mod) + { + import dmd.root.outbuffer; + import dmd.hdrgen; + auto buf = OutBuffer(); + buf.doindent = 1; + moduleToBuffer(&buf, mod); + + OutputDebugStringA(buf.peekChars); + } + + string source; + Module m; + source = q{ + int main() + { + return abc; + } + }; + m = checkErrors(source, "4,10,4,11:Error: undefined identifier `abc`\n"); + + version(traceGC) + { + wipeStack(); + GC.collect(); + } + + //_CrtDumpMemoryLeaks(); + version(traceGC) + dumpGC(); + + source = q{ + import std.stdio; + int main(string[] args) + { + int xyz = 7; + writeln(1, 2, 3); + return xyz; + } + }; + + for (int i = 0; i < 1; i++) // loop for testing GC leaks + { + m = checkErrors(source, ""); + + version(traceGC) + { + wipeStack(); + GC.collect(); + + //_CrtDumpMemoryLeaks(); + //dumpGC(); + } + + //core.memory.GC.Stats stats = GC.stats(); + //trace_printf("GC stats: %lld MB used, %lld MB free\n", cast(long)stats.usedSize >> 20, cast(long)stats.freeSize >> 20); + + version(traceGC) + if (stats.usedSize > (200 << 20)) + dumpGC(); + } + + checkTip(m, 5, 8, "(local variable) `int xyz`"); + checkTip(m, 5, 10, "(local variable) `int xyz`"); + checkTip(m, 5, 11, ""); + checkTip(m, 6, 8, "`void std.stdio.writeln!(int, int, int)(int _param_0, int _param_1, int _param_2) @safe`"); + checkTip(m, 7, 11, "(local variable) `int xyz`"); + + version(traceGC) + { + wipeStack(); + GC.collect(); + } + + checkDefinition(m, 7, 11, "source.d", 5, 8); // xyz + + //checkTypeIdentifiers(source); + + source = + q{ module pkg.source; // Line 1 + int main(in string[] args) + in(args.length > 1) in{ assert(args.length > 1); } + do { + static if(is(typeof(args[0]) : string)) { // Line 5 + if (args[0] is args[1]) {} + else if (args[1] !is args[0]) {} + } + int[string] aa; + if (auto p = args[0] in aa) // Line 10 + if (auto q = args[1] !in aa) {} + return 0; + } + static if(is(bool)) + bool t = null is null; // Line 15 + else + bool f = 0 in [1:1]; + + enum EE { E1 = 3, E2 } + void foo() // Line 20 + { + auto ee = EE.E1; + } + import core.cpuid : cpu_vendor = vendor, processor; + import cpuid = core.cpuid; // Line 25 + string cpu_info() + { + return cpu_vendor ~ " " ~ processor; + } + }; + checkBinaryIsInLocations(source, [Loc(null, 6, 17), Loc(null, 7, 23), + Loc(null, 10, 25), Loc(null, 11, 26), + Loc(null, 15, 18), Loc(null, 17, 15)]); + + m = checkErrors(source, ""); + + checkTip(m, 2, 24, "(parameter) `const(string[]) args`"); // function arg + checkTip(m, 3, 6, "(parameter) `const(string[]) args`"); // in contract + checkTip(m, 3, 34, "(parameter) `const(string[]) args`"); // in contract + checkTip(m, 5, 24, "(parameter) `const(string[]) args`"); // static if is typeof expression + checkTip(m, 6, 10, "(parameter) `const(string[]) args`"); // if expression + checkTip(m, 11, 21, "(parameter) `const(string[]) args`"); // !in expression + + checkTip(m, 19, 9, "(enum) `pkg.source.EE`"); // enum EE + checkTip(m, 19, 13, "(enum value) `pkg.source.EE.E1 = 3`"); // enum E1 + checkTip(m, 19, 21, "(enum value) `pkg.source.EE.E2 = 4`"); // enum E2 + checkTip(m, 22, 14, "(enum) `pkg.source.EE`"); // enum EE + checkTip(m, 22, 17, "(enum value) `pkg.source.EE.E1 = 3`"); // enum E1 + + checkTip(m, 1, 9, "(package) `pkg`"); + checkTip(m, 1, 13, "(module) `pkg.source`"); + checkTip(m, 24, 10, "(package) `core`"); + checkTip(m, 24, 15, "(module) `core.cpuid`"); + checkTip(m, 24, 23, "(alias) `pkg.source.cpu_vendor = string core.cpuid.vendor() pure nothrow @nogc @property @trusted`"); + checkTip(m, 24, 36, "(alias) `pkg.source.cpu_vendor = string core.cpuid.vendor() pure nothrow @nogc @property @trusted`"); + checkTip(m, 24, 44, "(alias) `pkg.source.processor = string core.cpuid.processor() pure nothrow @nogc @property @trusted`"); + checkTip(m, 28, 11, "`string core.cpuid.vendor() pure nothrow @nogc @property @trusted`"); + + source = + q{ // Line 1 + struct S + { + int field1 = 3; + static long stat1 = 7; // Line 5 + int fun(int par) { return field1 + par; } + } + void foo() + { + S anS; // Line 10 + int x = anS.fun(1); + } + int fun(S s) + { + auto p = new S(1); // Line 15 + auto seven = S.stat1; + return s.field1; + } + }; + m = checkErrors(source, ""); + + checkTip(m, 2, 10, "(struct) `source.S`"); + checkTip(m, 4, 8, "(field) `int source.S.field1`"); + checkTip(m, 6, 8, "`int source.S.fun(int par)`"); + checkTip(m, 6, 16, "(parameter) `int par`"); + checkTip(m, 6, 30, "(field) `int source.S.field1`"); + checkTip(m, 6, 39, "(parameter) `int par`"); + + checkTip(m, 10, 4, "(struct) `source.S`"); + checkTip(m, 10, 6, "(local variable) `source.S anS`"); + checkTip(m, 11, 12, "(local variable) `source.S anS`"); + checkTip(m, 11, 16, "`int source.S.fun(int par)`"); + + checkTip(m, 13, 11, "(struct) `source.S`"); + checkTip(m, 16, 19, "(thread local variable) `long source.S.stat1`"); + checkTip(m, 16, 17, "(struct) `source.S`"); + + checkDefinition(m, 11, 16, "source.d", 6, 8); // fun + checkDefinition(m, 15, 17, "source.d", 2, 10); // S + + source = + q{ // Line 1 + class C + { + int field1 = 3; + static long stat1 = 7; // Line 5 + int fun(int par) { return field1 + par; } + } + void foo() + { + C aC = new C; // Line 10 + int x = aC.fun(1); + } + int fun(C c) + { + auto p = new C(); // Line 15 + auto seven = C.stat1; + return c.field1; + } + }; + m = checkErrors(source, ""); + + checkTip(m, 2, 9, "(class) `source.C`"); + checkTip(m, 4, 8, "(field) `int source.C.field1`"); + checkTip(m, 6, 8, "`int source.C.fun(int par)`"); + checkTip(m, 6, 16, "(parameter) `int par`"); + checkTip(m, 6, 30, "(field) `int source.C.field1`"); + checkTip(m, 6, 39, "(parameter) `int par`"); + + checkTip(m, 10, 4, "(class) `source.C`"); + checkTip(m, 10, 15, "(class) `source.C`"); + checkTip(m, 10, 6, "(local variable) `source.C aC`"); + checkTip(m, 11, 12, "(local variable) `source.C aC`"); + checkTip(m, 11, 16, "`int source.C.fun(int par)`"); + + checkTip(m, 13, 11, "(class) `source.C`"); + checkTip(m, 16, 19, "(thread local variable) `long source.C.stat1`"); + checkTip(m, 16, 17, "(class) `source.C`"); + + checkDefinition(m, 11, 16, "source.d", 6, 8); // fun + checkDefinition(m, 15, 17, "source.d", 2, 9); // C + + // enum value + source = + q{ // Line 1 + enum TTT = 9; + void fun() + { + int x = TTT; // Line 5 + } + }; + m = checkErrors(source, ""); + + checkTip(m, 2, 8, "(constant) `int source.TTT = 9`"); + checkTip(m, 5, 13, "(constant) `int source.TTT = 9`"); + + // template struct without instances + source = + q{ // Line 1 + struct ST(T) + { + T f; + } + }; + m = checkErrors(source, ""); + + checkTip(m, 2, 10, "(struct) `source.ST(T)`"); + checkTip(m, 4, 4, "(unresolved type) `T`"); + checkTip(m, 4, 6, "`T f`"); + + source = + q{ // Line 1 + inout(Exception) foo(inout(char)* ptr) + { + int x = 1; + try + { + x++; + } + catch(Exception e) + { // Line 10 + auto err = cast(Error) e; + Exception* pe = &e; + const(Exception*) cpe = &e; + throw new Error("unexpected"); + } + finally + { + x = 0; + } + return null; + } + }; + m = checkErrors(source, ""); + + checkTip(m, 9, 20, "(local variable) `object.Exception e`"); + checkTip(m, 9, 10, "(class) `object.Exception`"); + checkTip(m, 11, 21, "(class) `object.Error`"); + checkTip(m, 12, 5, "(class) `object.Exception`"); + checkTip(m, 13, 11, "(class) `object.Exception`"); + checkTip(m, 2, 9, "(class) `object.Exception`"); + + source = + q{ // Line 1 + struct S + { + int field1 = 1; + int field2 = 2; // Line 5 + int fun(int par) { return field1 + par; } + int more = 3; + } + void foo() + { // Line 10 + S anS; + int x = anS.f(1); + int y = anS. + } + }; + m = checkErrors(source, + "14,2,14,3:Error: identifier or `new` expected following `.`, not `}`\n" ~ + "14,2,14,3:Error: semicolon expected, not `}`\n" ~ + "12,14,12,15:Error: no property `f` for type `S`\n"); + //dumpAST(m); + checkExpansions(m, 12, 16, "f", [ "field1", "field2", "fun" ]); + checkExpansions(m, 13, 16, "", [ "field1", "field2", "fun", "more" ]); + checkExpansions(m, 13, 13, "an", [ "anS" ]); + + source = + q{ // Line 1 + struct S + { + int fun(int par) { return par; } + } // Line 5 + void fun(int rec) + { + S anS; + int x = anS.fun(1); + if (rec) // Line 10 + fun(false); + } + }; + m = checkErrors(source, ""); + + IdTypePos[][string] exp = [ + "S": [ IdTypePos(TypeReferenceKind.Struct) ], + "x": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + "anS": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + "rec": [ IdTypePos(TypeReferenceKind.ParameterVariable) ], + "par": [ IdTypePos(TypeReferenceKind.ParameterVariable) ], + "fun": [ IdTypePos(TypeReferenceKind.Method), + IdTypePos(TypeReferenceKind.Function, 6, 8), + IdTypePos(TypeReferenceKind.Method, 9, 16), + IdTypePos(TypeReferenceKind.Function, 11, 5)], + ]; + checkIdentifierTypes(m, exp); + + // references + source = + q{ // Line 1 + struct S + { + int fun(int par) { return par; } + int foo() { return fun(1); } // Line 5 + } + void fun(int rec) + { + S anS; + int x = anS.fun(1); // Line 10 + if (rec) fun(false); + } + }; + m = checkErrors(source, ""); + + checkReferences(m, 4, 8, [TextPos(4,8), TextPos(5, 23), TextPos(10, 16)]); // fun + + // foreach lowered to for + source = q{ // Line 1 + import std.range; + int fun(int rec) + { + int sum = 0; // Line 5 + foreach(i; iota(0, rec)) + sum += i; + return sum; + } + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 6, 12, "(local variable) `int i`"); + checkTip(m, 7, 5, "(local variable) `int sum`"); + checkTip(m, 7, 12, "(local variable) `int i`"); + + source = q{ // Line 1 + enum TOK : ubyte + { + reserved, + leftParentheses, // Line 5 + rightParentheses, /// right parent doc + } + void foo(TOK op) + { + if (op == TOK.leftParentheses) {} // Line 10 + } + class Base : Object + { + this(TOK op, size_t sz) {} + } // Line 15 + /// right base doc + class RightBase : Base + { + this() + { // Line 20 + super(TOK.rightParentheses, RightBase.sizeof); + } + } + TOK[Base] mapBaseTOK; + + c_long testcase(int op) + { + switch(op) + { // from object.d + case TypeInfo_Class.ClassFlags.isCOMclass: // Line 30 + case TypeInfo_Class.ClassFlags.noPointers: + default: + break; + } + return 0; + } + import core.stdc.config; + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 10, 8, "(parameter) `source.TOK op`"); + checkTip(m, 10, 14, "(enum) `source.TOK`"); + checkTip(m, 10, 18, "(enum value) `source.TOK.leftParentheses = 1`"); + checkTip(m, 21, 11, "(enum) `source.TOK`"); + checkTip(m, 21, 15, "(enum value) `source.TOK.rightParentheses = 2`"); + checkTip(m, 21, 33, "(class) `source.RightBase`\n\nright base doc"); + checkTip(m, 24, 19, "(thread local variable) `source.TOK[source.Base] source.mapBaseTOK`"); + checkTip(m, 24, 7, "(class) `source.Base`"); + checkTip(m, 24, 3, "(enum) `source.TOK`"); + checkTip(m, 30, 10, "(class) `object.TypeInfo_Class`"); + checkTip(m, 30, 25, "(enum) `object.TypeInfo_Class.ClassFlags`"); + checkTip(m, 30, 36, "(enum value) `object.TypeInfo_Class.ClassFlags.isCOMclass = 1u`"); + checkTip(m, 21, 43, "(constant) `ulong source.RightBase.sizeof = 8LU`"); + + IdTypePos[][string] exp2 = [ + "size_t": [ IdTypePos(TypeReferenceKind.BasicType) ], + "Base": [ IdTypePos(TypeReferenceKind.Class) ], + "mapBaseTOK": [ IdTypePos(TypeReferenceKind.TLSVariable) ], + "TOK": [ IdTypePos(TypeReferenceKind.Enum) ], + "testcase": [ IdTypePos(TypeReferenceKind.Function) ], + "rightParentheses": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "__ctor": [ IdTypePos(TypeReferenceKind.Method) ], + "sz": [ IdTypePos(TypeReferenceKind.ParameterVariable) ], + "RightBase": [ IdTypePos(TypeReferenceKind.Class) ], + "foo": [ IdTypePos(TypeReferenceKind.Function) ], + "leftParentheses": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "op": [ IdTypePos(TypeReferenceKind.ParameterVariable) ], + "reserved": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "noPointers": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "isCOMclass": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "TypeInfo_Class": [ IdTypePos(TypeReferenceKind.Class) ], + "ClassFlags": [ IdTypePos(TypeReferenceKind.Enum) ], + "Object": [ IdTypePos(TypeReferenceKind.Class) ], + "core": [ IdTypePos(TypeReferenceKind.Package) ], + "stdc": [ IdTypePos(TypeReferenceKind.Package) ], + "config": [ IdTypePos(TypeReferenceKind.Module) ], + "c_long": [ IdTypePos(TypeReferenceKind.BasicType) ], + "sizeof": [ IdTypePos(TypeReferenceKind.Constant) ], + ]; + checkIdentifierTypes(m, exp2); + + source = q{ + void fun() + { + string cmd = "cmd"; + bool isX86_64 = true; // Line 5 + cmd = "pushd .\n" ~ `call vcvarsall.bat ` ~ (isX86_64 ? "amd64" : "x86") ~ "\n" ~ "popd\n" ~ cmd; + } + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 6, 49, "(local variable) `bool isX86_64`"); + checkTip(m, 6, 97, "(local variable) `string cmd`"); + + source = q{ + int fun() + { + int sum; + foreach(m; object.ModuleInfo) // Line 5 + if (m) sum++; + return sum; + } + }; + m = checkErrors(source, ""); + //dumpAST(m); + checkTip(m, 6, 9, "(foreach variable) `object.ModuleInfo* m`"); + checkTip(m, 5, 12, "(foreach variable) `object.ModuleInfo* m`"); + checkTip(m, 5, 15, "(module) `object`"); + checkTip(m, 5, 22, "(struct) `object.ModuleInfo`"); + + exp2 = [ + "fun": [ IdTypePos(TypeReferenceKind.Function) ], + "sum": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + "m": [ IdTypePos(TypeReferenceKind.ParameterVariable) ], + "object": [ IdTypePos(TypeReferenceKind.Module) ], + "ModuleInfo": [ IdTypePos(TypeReferenceKind.Struct) ], + ]; + checkIdentifierTypes(m, exp2); + + source = q{ + void fun() + { + string str = "hello"; + string cmd = () // Line 5 + { + auto local = str.length; + return str; + }(); + } + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 7, 10, "(local variable) `ulong local`"); + checkTip(m, 7, 18, "(local variable) `string str`"); + + source = q{ + struct S(T) + { + T member; + } // Line 5 + S!int x; + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 6, 9, "(thread local variable) `source.S!int source.x`"); + checkTip(m, 4, 6, "(field) `int source.S!int.member`"); + + // check for conditional not producing warning "unreachable code" + source = q{ + void foo() + { + version(none) + { // Line 5 + } + int test; + } + }; + m = checkErrors(source, ""); + + // check for semantics in unittest + source = q{ + unittest + { + int var1 = 1; + int var2 = var1 + 1; // Line 5 + } + }; + m = checkErrors(source, ""); + checkTip(m, 5, 15, "(local variable) `int var1`"); + + // check position of var in AddrExp + source = q{ + void fun(int* p); + void foo() + { + int var = 1; // Line 5 + fun(&var); + } + }; + m = checkErrors(source, ""); + checkReferences(m, 5, 8, [TextPos(5,8), TextPos(6, 9)]); // var + + // check position of var in AddrExp + source = q{ + struct S { int x = 3; } + void fun(T)(T* p) {} + void foo() + { + S var; // Line 6 + fun!(S)(&var); + } + }; + m = checkErrors(source, ""); + + checkTip(m, 7, 9, "(struct) `source.S`"); + + // check template arguments + source = q{ + void fun(T)() {} + void foo() + { + fun!(object.ModuleInfo)(); // Line 5 + } + }; + m = checkErrors(source, ""); + + checkTip(m, 5, 9, "(module) `object`"); + checkTip(m, 5, 16, "(struct) `object.ModuleInfo`"); + + exp2 = [ + "fun": [ IdTypePos(TypeReferenceKind.Function) ], + "foo": [ IdTypePos(TypeReferenceKind.Function) ], + "object": [ IdTypePos(TypeReferenceKind.Module) ], + "ModuleInfo": [ IdTypePos(TypeReferenceKind.Struct) ], + ]; + checkIdentifierTypes(m, exp2); + + // check FQN types in cast + source = q{ + void foo() + { + auto e = cast(object.Exception) null; + auto p = cast(object.Exception*) null; // Line 5 + } + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 4, 18, "(module) `object`"); + checkTip(m, 4, 25, "(class) `object.Exception`"); + checkTip(m, 5, 18, "(module) `object`"); + checkTip(m, 5, 25, "(class) `object.Exception`"); + + exp2 = [ + "foo": [ IdTypePos(TypeReferenceKind.Function) ], + "object": [ IdTypePos(TypeReferenceKind.Module) ], + "Exception": [ IdTypePos(TypeReferenceKind.Class) ], + "e": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + "p": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + ]; + checkIdentifierTypes(m, exp2); + + // fqn, function call on static members + source = q{ + struct Mem + { + static Mem foo(int sz) { return Mem(); } + } // Line 5 + __gshared Mem mem; + void fun() + { + source.Mem m = source.mem.foo(1234); + } // Line 10 + }; + m = checkErrors(source, ""); + //dumpAST(m); + + checkTip(m, 9, 30, "`Mem source.Mem.foo(int sz)`"); + checkTip(m, 9, 19, "(module) `source`"); + checkTip(m, 9, 26, "(__gshared variable) `source.Mem source.mem`"); + checkTip(m, 9, 11, "(struct) `source.Mem`"); + checkTip(m, 9, 4, "(module) `source`"); + + /////////////////////////////////////////////////////////// + // check array initializer + filename = "tok.d"; + source = q{ + module tok; + enum TOK : ubyte + { + reserved, + + // Other + leftParentheses, + rightParentheses, + max_ + } + enum PREC : int + { + zero, + expr, + } + }; + m = checkErrors(source, ""); + source = q{ + import tok; + immutable PREC[TOK.max_] precedence = + [ + TOK.reserved : PREC.zero, // Line 5 + TOK.leftParentheses : PREC.expr, + ]; + }; + filename = "source.d"; + m = checkErrors(source, ""); + + // TODO: checkTip(m, 3, 18, "(enum) `tok.TOK`"); + checkTip(m, 3, 22, "(enum value) `tok.TOK.max_ = 3`"); + checkTip(m, 3, 13, "(enum) `tok.PREC`"); + checkTip(m, 5, 4, "(enum) `tok.TOK`"); + checkTip(m, 5, 8, "(enum value) `tok.TOK.reserved = cast(ubyte)0u`"); + checkTip(m, 5, 19, "(enum) `tok.PREC`"); + checkTip(m, 5, 24, "(enum value) `tok.PREC.zero = 0`"); + + IdTypePos[][string] exp4 = [ + "tok": [ IdTypePos(TypeReferenceKind.Package) ], + "zero": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "expr": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "reserved": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "leftParentheses": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "max_": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "PREC": [ IdTypePos(TypeReferenceKind.Enum) ], + "TOK": [ IdTypePos(TypeReferenceKind.Enum) ], + "precedence": [ IdTypePos(TypeReferenceKind.GSharedVariable) ], + ]; + checkIdentifierTypes(m, exp4); + + source = q{ + int[] darr = [ TypeInfo_Class.ClassFlags.isCOMclass ]; + int[int] aarr = + [ + TypeInfo_Class.ClassFlags.isCOMclass : 1, // Line 5 + 1 : TypeInfo_Class.ClassFlags.isCOMclass + ]; + int[] iarr = [ TypeInfo_Class.ClassFlags.noPointers : 1 ]; + void fun() + { // Line 10 + auto a = darr.length + aarr.length; + auto p = darr.ptr; + } + }; + m = checkErrors(source, ""); + checkTip(m, 2, 18, "(class) `object.TypeInfo_Class`"); + checkTip(m, 2, 33, "(enum) `object.TypeInfo_Class.ClassFlags`"); + checkTip(m, 2, 44, "(enum value) `object.TypeInfo_Class.ClassFlags.isCOMclass = 1u`"); + checkTip(m, 5, 4, "(class) `object.TypeInfo_Class`"); + checkTip(m, 5, 19, "(enum) `object.TypeInfo_Class.ClassFlags`"); + checkTip(m, 5, 30, "(enum value) `object.TypeInfo_Class.ClassFlags.isCOMclass = 1u`"); + checkTip(m, 6, 8, "(class) `object.TypeInfo_Class`"); + checkTip(m, 6, 23, "(enum) `object.TypeInfo_Class.ClassFlags`"); + checkTip(m, 6, 34, "(enum value) `object.TypeInfo_Class.ClassFlags.isCOMclass = 1u`"); + checkTip(m, 8, 18, "(class) `object.TypeInfo_Class`"); + checkTip(m, 8, 33, "(enum) `object.TypeInfo_Class.ClassFlags`"); + checkTip(m, 8, 44, "(enum value) `object.TypeInfo_Class.ClassFlags.noPointers = 2u`"); + checkTip(m, 11, 18, "(field) `ulong int[].length`"); + checkTip(m, 11, 32, "(field) `ulong int[int].length`"); + checkTip(m, 12, 18, "(field) `int* int[].ptr`"); + + checkReferences(m, 2, 44, [TextPos(2,44), TextPos(5, 30), TextPos(6, 34)]); // isCOMclass + + IdTypePos[][string] exp3 = [ + "isCOMclass": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "noPointers": [ IdTypePos(TypeReferenceKind.EnumValue) ], + "TypeInfo_Class": [ IdTypePos(TypeReferenceKind.Class) ], + "ClassFlags": [ IdTypePos(TypeReferenceKind.Enum) ], + "darr": [ IdTypePos(TypeReferenceKind.TLSVariable) ], + "aarr": [ IdTypePos(TypeReferenceKind.TLSVariable) ], + "iarr": [ IdTypePos(TypeReferenceKind.TLSVariable) ], + "fun": [ IdTypePos(TypeReferenceKind.Function) ], + "length": [ IdTypePos(TypeReferenceKind.MemberVariable) ], + "ptr": [ IdTypePos(TypeReferenceKind.MemberVariable) ], + "a": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + "p": [ IdTypePos(TypeReferenceKind.LocalVariable) ], + ]; + checkIdentifierTypes(m, exp3); + + // more than 7 cases translated to table + source = q{ + bool isReserved(const(char)[] ident) + { + // more than 7 cases use dup + switch (ident) + { + case "DigitalMars": + case "GNU": + case "LDC": + case "SDC": + case "Windows": + case "Win32": + case "Win64": + case "linux": + case "OSX": + case "iOS": + case "TVOS": + case "WatchOS": + case "FreeBSD": + case "OpenBSD": + case "NetBSD": + case "DragonFlyBSD": + case "BSD": + case "Solaris": + return true; + default: + return false; + } + } + }; + m = checkErrors(source, ""); + + // change settings to restart everything + opts.unittestOn = false; + filename = "source2.d"; + m = checkErrors(source, ""); + + // can object.d create reserved classes, e.g. Error? + source = q{ + module object; + alias ulong size_t; + class Object + { + } + class Throwable + { + } + class Error : Throwable + { + } + }; + m = checkErrors(source, ""); + // beware: bad object.d after this point + lastContext = null; +} + +unittest +{ + import core.memory; + import std.path; + import std.file; + + dmdInit(); + + string srcdir = "dmd/src"; + + Options opts; + opts.predefineDefaultVersions = true; + opts.x64 = true; + opts.msvcrt = true; + opts.warnings = true; + opts.importDirs = guessImportPaths() ~ srcdir; + opts.stringImportDirs ~= srcdir ~ "/../res"; + opts.versionIds ~= "MARS"; + //opts.versionIds ~= "NoBackend"; + + auto filename = std.path.buildPath(srcdir, "dmd/expressionsem.d"); + + static void assert_equal(S, T)(S s, T t) + { + if (s == t) + return; + assert(false); + } + + Module checkErrors(string src, string expected_err) + { + try + { + initErrorMessages(filename); + Module parsedModule = createModuleFromText(filename, src); + assert(parsedModule); + Module m = analyzeModule(parsedModule, opts); + auto err = getErrorMessages(); + auto other = getErrorMessages(true); + assert_equal(err, expected_err); + assert_equal(other, ""); + return m; + } + catch(Throwable t) + { + throw t; + } + } + string source = cast(string)std.file.read(filename); + Module m = checkErrors(source, ""); +} + +// https://issues.dlang.org/show_bug.cgi?id=20253 +enum TTT = 9; +void dummy() +{ + import std.file; + std.file.read(""); // no tip on std and file + auto x = TTT; + int[] arr; + auto s = arr.ptr; + auto y = arr.length; + auto my = arr.mangleof; + auto zi = size_t.init; + auto z0 = size_t.min; + auto z1 = size_t.max; + auto z2 = size_t.alignof; + auto z3 = size_t.stringof; + float flt; + auto q = [flt.sizeof, flt.init, flt.epsilon, flt.mant_dig, flt.infinity, flt.re, flt.min_normal, flt.min_10_exp]; + auto ti = Object.classinfo; +} + +struct XMem +{ + static XMem foo(int sz) { return XMem(); } +} +__gshared XMem xmem; + +void fun() +{ + vdc.dmdserver.semanalysis.XMem m = vdc.dmdserver.semanalysis.xmem.foo(1234); +} diff --git a/vdc/dmdserver/semvisitor.d b/vdc/dmdserver/semvisitor.d new file mode 100644 index 00000000..b03c99c5 --- /dev/null +++ b/vdc/dmdserver/semvisitor.d @@ -0,0 +1,1936 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2012 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.dmdserver.semvisitor; + +import vdc.ivdserver : TypeReferenceKind; + +import dmd.access; +import dmd.aggregate; +import dmd.apply; +import dmd.arraytypes; +import dmd.attrib; +import dmd.ast_node; +import dmd.builtin; +import dmd.cond; +import dmd.console; +import dmd.dclass; +import dmd.declaration; +import dmd.denum; +import dmd.dimport; +import dmd.dinterpret; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.expression; +import dmd.func; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.init; +import dmd.mtype; +import dmd.objc; +import dmd.sapply; +import dmd.semantic2; +import dmd.semantic3; +import dmd.statement; +import dmd.target; +import dmd.tokens; +import dmd.visitor; + +import dmd.root.outbuffer; +import dmd.root.file; +import dmd.root.filename; +import dmd.root.rmem; +import dmd.root.rootobject; + +import std.algorithm; +import std.string; +import std.conv; +import stdext.array; +import core.stdc.string; + +// walk the complete AST (declarations, statement and expressions) +// assumes being started on module/declaration level +extern(C++) class ASTVisitor : StoppableVisitor +{ + bool unconditional; // take both branches in conditional declarations/statements + + alias visit = StoppableVisitor.visit; + + ASTNode[] visiting; + size_t currentVisiting; + + void visitExpression(Expression expr) + { + if (stop || !expr) + return; + + if (currentVisiting >= visiting.length) + visiting ~= expr; + else + visiting[currentVisiting] = expr; + currentVisiting++; + + if (walkPostorder(expr, this)) + stop = true; + + visiting[--currentVisiting] = null; + } + + void visitStatement(Statement stmt) + { + if (stop || !stmt) + return; + + if (currentVisiting >= visiting.length) + visiting ~= stmt; + else + visiting[currentVisiting] = stmt; + currentVisiting++; + + if (walkPostorder(stmt, this)) + stop = true; + + visiting[--currentVisiting] = null; + } + + void visitDeclaration(Dsymbol sym) + { + if (stop || !sym) + return; + + sym.accept(this); + } + + // default to being permissive + override void visit(Parameter) {} + override void visit(TemplateParameter) {} + + // expressions + override void visit(Expression expr) + { + if (expr.original && expr.original != expr) + if (!visiting.contains(expr.original)) + visitExpression(expr.original); + } + + override void visit(ErrorExp errexp) + { + visit(cast(Expression)errexp); + } + + override void visit(IsExp ie) + { + // TODO: has ident + if (ie.targ) + ie.targ.accept(this); + if (ie.originaltarg && ie.originaltarg !is ie.targ) + ie.originaltarg.accept(this); + + visit(cast(Expression)ie); + } + + override void visit(DeclarationExp expr) + { + visitDeclaration(expr.declaration); + visit(cast(Expression)expr); + } + + override void visit(TypeExp expr) + { + if (expr.type) + expr.type.accept(this); + visit(cast(Expression)expr); + } + + override void visit(FuncExp expr) + { + visitDeclaration(expr.fd); + visitDeclaration(expr.td); + + visit(cast(Expression)expr); + } + + // types + override void visit(Type) {} + + override void visit(TypeTypeof t) + { + visitExpression(t.exp); + } + + // symbols + override void visit(Dsymbol) {} + + override void visit(ScopeDsymbol scopesym) + { + // optimize to only visit members in approriate source range + size_t mcnt = scopesym.members ? scopesym.members.dim : 0; + for (size_t m = 0; !stop && m < mcnt; m++) + { + Dsymbol s = (*scopesym.members)[m]; + s.accept(this); + } + } + + // declarations + override void visit(VarDeclaration decl) + { + visit(cast(Declaration)decl); + + if (!stop && decl._init) + decl._init.accept(this); + } + + override void visit(AttribDeclaration decl) + { + visit(cast(Declaration)decl); + + if (!stop) + if (unconditional) + { + if (decl.decl) + foreach(d; *decl.decl) + if (!stop) + d.accept(this); + } + else if (auto inc = decl.include(null)) + foreach(d; *inc) + if (!stop) + d.accept(this); + } + + override void visit(ConditionalDeclaration decl) + { + if (!stop && decl.condition) + decl.condition.accept(this); + + visit(cast(AttribDeclaration)decl); + + if (!stop && unconditional && decl.elsedecl) + foreach(d; *decl.elsedecl) + if (!stop) + d.accept(this); + } + + override void visit(FuncDeclaration decl) + { + visit(cast(Declaration)decl); + + if (decl.parameters) + foreach(p; *decl.parameters) + if (!stop) + p.accept(this); + + if (decl.frequires) + foreach(s; *decl.frequires) + visitStatement(s); + if (decl.fensures) + foreach(e; *decl.fensures) + visitStatement(e.ensure); // TODO: check result ident + + visitStatement(decl.frequire); + visitStatement(decl.fensure); + visitStatement(decl.fbody); + } + + // condition + override void visit(Condition) {} + + override void visit(StaticIfCondition cond) + { + visitExpression(cond.exp); + visit(cast(Condition)cond); + } + + // initializer + override void visit(Initializer) {} + + override void visit(ExpInitializer einit) + { + visitExpression(einit.exp); + } + + override void visit(VoidInitializer vinit) + { + } + + override void visit(ErrorInitializer einit) + { + if (einit.original) + einit.original.accept(this); + } + + override void visit(StructInitializer sinit) + { + foreach (i, const id; sinit.field) + if (auto iz = sinit.value[i]) + iz.accept(this); + } + + override void visit(ArrayInitializer ainit) + { + foreach (i, ex; ainit.index) + { + if (ex) + ex.accept(this); + if (auto iz = ainit.value[i]) + iz.accept(this); + } + } + + // statements + override void visit(Statement stmt) + { + if (stmt.original) + if (!visiting.contains(stmt.original)) + visitStatement(stmt.original); + } + + override void visit(ExpStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(ConditionalStatement stmt) + { + if (!stop && stmt.condition) + { + stmt.condition.accept(this); + + if (unconditional) + { + visitStatement(stmt.ifbody); + visitStatement(stmt.elsebody); + } + else if (stmt.condition.include(null)) + visitStatement(stmt.ifbody); + else + visitStatement(stmt.elsebody); + } + visit(cast(Statement)stmt); + } + + override void visit(CompileStatement stmt) + { + if (stmt.exps) + foreach(e; *stmt.exps) + if (!stop) + e.accept(this); + visit(cast(Statement)stmt); + } + + override void visit(WhileStatement stmt) + { + visitExpression(stmt.condition); + visit(cast(Statement)stmt); + } + + override void visit(DoStatement stmt) + { + visitExpression(stmt.condition); + visit(cast(Statement)stmt); + } + + override void visit(ForStatement stmt) + { + visitExpression(stmt.condition); + visitExpression(stmt.increment); + visit(cast(Statement)stmt); + } + + override void visit(ForeachStatement stmt) + { + if (stmt.parameters) + foreach(p; *stmt.parameters) + if (!stop) + p.accept(this); + visitExpression(stmt.aggr); + visit(cast(Statement)stmt); + } + + override void visit(ForeachRangeStatement stmt) + { + if (!stop && stmt.prm) + stmt.prm.accept(this); + visitExpression(stmt.lwr); + visitExpression(stmt.upr); + visit(cast(Statement)stmt); + } + + override void visit(IfStatement stmt) + { + if (!stop && stmt.prm) + stmt.prm.accept(this); + visitExpression(stmt.condition); + visit(cast(Statement)stmt); + } + + override void visit(PragmaStatement stmt) + { + if (!stop && stmt.args) + foreach(a; *stmt.args) + if (!stop) + a.accept(this); + visit(cast(Statement)stmt); + } + + override void visit(StaticAssertStatement stmt) + { + visitExpression(stmt.sa.exp); + visitExpression(stmt.sa.msg); + visit(cast(Statement)stmt); + } + + override void visit(SwitchStatement stmt) + { + visitExpression(stmt.condition); + visit(cast(Statement)stmt); + } + + override void visit(CaseStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(CaseRangeStatement stmt) + { + visitExpression(stmt.first); + visitExpression(stmt.last); + visit(cast(Statement)stmt); + } + + override void visit(GotoCaseStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(ReturnStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(SynchronizedStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(WithStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(TryCatchStatement stmt) + { + // variables not looked at by PostorderStatementVisitor + if (!stop && stmt.catches) + foreach(c; *stmt.catches) + visitDeclaration(c.var); + visit(cast(Statement)stmt); + } + + override void visit(ThrowStatement stmt) + { + visitExpression(stmt.exp); + visit(cast(Statement)stmt); + } + + override void visit(ImportStatement stmt) + { + if (!stop && stmt.imports) + foreach(i; *stmt.imports) + visitDeclaration(i); + visit(cast(Statement)stmt); + } +} + +extern(C++) class FindASTVisitor : ASTVisitor +{ + const(char*) filename; + int startLine; + int startIndex; + int endLine; + int endIndex; + + alias visit = ASTVisitor.visit; + RootObject found; + ScopeDsymbol foundScope; + + this(const(char*) filename, int startLine, int startIndex, int endLine, int endIndex) + { + this.filename = filename; + this.startLine = startLine; + this.startIndex = startIndex; + this.endLine = endLine; + this.endIndex = endIndex; + } + + bool foundNode(RootObject obj) + { + if (obj) + { + found = obj; + stop = true; + } + return stop; + } + + bool matchIdentifier(ref const Loc loc, Identifier ident) + { + if (ident) + if (loc.filename is filename) + if (loc.linnum == startLine && loc.linnum == endLine) + if (loc.charnum <= startIndex && loc.charnum + ident.toString().length >= endIndex) + return true; + return false; + } + + bool visitPackages(IdentifiersAtLoc* packages) + { + if (packages) + for (size_t p; p < packages.dim; p++) + if (!found && matchIdentifier((*packages)[p].loc, (*packages)[p].ident)) + { + Package pkg; + auto pkgs = new IdentifiersAtLoc(); + for (size_t q = 0; q <= p; q++) + pkgs.push((*packages)[p]); + Package.resolve(pkgs, null, &pkg); + if (pkg) + foundNode(pkg); + return true; + } + return false; + } + + bool matchLoc(ref const(Loc) loc, int len) + { + if (loc.filename is filename) + if (loc.linnum == startLine && loc.linnum == endLine) + if (loc.charnum <= startIndex && loc.charnum + len >= endIndex) + return true; + return false; + } + + override void visit(Dsymbol sym) + { + if (!found && matchIdentifier(sym.loc, sym.ident)) + foundNode(sym); + } + + override void visit(Parameter sym) + { + if (!found && matchIdentifier(sym.ident.loc, sym.ident)) + foundNode(sym); + } + + override void visit(Module mod) + { + if (mod.md) + { + visitPackages(mod.md.packages); + + if (!found && matchIdentifier(mod.md.loc, mod.md.id)) + foundNode(mod); + } + visit(cast(Package)mod); + } + + override void visit(Import imp) + { + visitPackages(imp.packages); + + if (!found && matchIdentifier(imp.loc, imp.id)) + foundNode(imp.mod); + + for (int n = 0; !found && n < imp.names.dim; n++) + if (matchIdentifier(imp.names[n].loc, imp.names[n].ident) || + matchIdentifier(imp.aliases[n].loc, imp.aliases[n].ident)) + if (n < imp.aliasdecls.dim) + foundNode(imp.aliasdecls[n]); + + // symbol has ident of first package, so don't forward + } + + override void visit(DVCondition cond) + { + if (!found && matchIdentifier(cond.loc, cond.ident)) + foundNode(cond); + } + + override void visit(TypeIdentifier t) + { + visitTypeIdentifier(t, t); + visit(cast(TypeQualified)t); + } + + override void visit(Expression expr) + { + super.visit(expr); + } + + override void visit(CastExp expr) + { + visitTypeIdentifier(expr.parsedTo, expr.to, true); + if (expr.parsedTo != expr.to) + visitTypeIdentifier(expr.to, expr.to); + super.visit(expr); + } + + override void visit(CompoundStatement cs) + { + // optimize to only visit members in approriate source range + size_t scnt = cs.statements ? cs.statements.dim : 0; + for (size_t i = 0; i < scnt && !stop; i++) + { + Statement s = (*cs.statements)[i]; + if (!s) + continue; + if (visiting.contains(s)) + continue; + + if (s.loc.filename) + { + if (s.loc.filename !is filename || s.loc.linnum > endLine) + continue; + Loc endloc; + if (auto ss = s.isScopeStatement()) + endloc = ss.endloc; + else if (auto ws = s.isWhileStatement()) + endloc = ws.endloc; + else if (auto ds = s.isDoStatement()) + endloc = ds.endloc; + else if (auto fs = s.isForStatement()) + endloc = fs.endloc; + else if (auto fs = s.isForeachStatement()) + endloc = fs.endloc; + else if (auto fs = s.isForeachRangeStatement()) + endloc = fs.endloc; + else if (auto ifs = s.isIfStatement()) + endloc = ifs.endloc; + else if (auto ws = s.isWithStatement()) + endloc = ws.endloc; + if (endloc.filename && endloc.linnum < startLine) + continue; + } + s.accept(this); + } + visit(cast(Statement)cs); + } + + override void visit(ScopeDsymbol scopesym) + { + // optimize to only visit members in approriate source range + // unfortunately, some members don't have valid locations + size_t mcnt = scopesym.members ? scopesym.members.dim : 0; + for (size_t m = 0; m < mcnt && !stop; m++) + { + Dsymbol s = (*scopesym.members)[m]; + if (s.isTemplateInstance) + continue; + if (s.loc.filename) + { + if (s.loc.filename !is filename || s.loc.linnum > endLine) + continue; + Loc endloc; + if (auto fd = s.isFuncDeclaration()) + endloc = fd.endloc; + if (endloc.filename && endloc.linnum < startLine) + continue; + } + s.accept(this); + } + if (found && !foundScope) + foundScope = scopesym; + } + + override void visit(ScopeStatement ss) + { + visit(cast(Statement)ss); + if (found && !foundScope) + foundScope = ss.scopesym; + } + + override void visit(TemplateInstance ti) + { + // skip members added by semantic + visit(cast(ScopeDsymbol)ti); + } + + override void visit(TemplateDeclaration td) + { + foreach(ti; td.instances) + if (!stop) + visit(ti); + + visit(cast(ScopeDsymbol)td); + } + + override void visit(CallExp expr) + { + super.visit(expr); + } + + override void visit(ScopeExp expr) + { + if (auto ti = expr.sds.isTemplateInstance()) + { + if (ti.tiargs && ti.parsedArgs) + { + size_t args = min(ti.tiargs.dim, ti.parsedArgs.dim); + for (size_t a = 0; a < args; a++) + if (Type tip = (*ti.parsedArgs)[a].isType()) + if (Type tir = (*ti.tiargs)[a].isType()) + visitTypeIdentifier(tip, tir); + } + } + super.visit(expr); + } + + override void visit(SymbolExp expr) + { + if (!found && expr.var) + if (matchIdentifier(expr.loc, expr.var.ident)) + foundNode(expr); + super.visit(expr); + } + override void visit(NewExp ne) + { + if (!found && matchLoc(ne.loc, 99)) + if (ne.member) + foundNode(ne.member); + else + foundNode(ne.newtype); + } + + override void visit(IdentifierExp expr) + { + if (!found && expr.ident) + { + if (matchIdentifier(expr.loc, expr.ident)) + { + if (expr.type) + foundNode(expr.type); + else if (expr.original) + { + if (auto se = expr.original.isScopeExp()) + foundNode(se.sds); + else + foundNode(expr.original.type); + } + } + } + visit(cast(Expression)expr); + } + + override void visit(DotIdExp de) + { + if (!found) + if (de.ident) + if (matchIdentifier(de.identloc, de.ident)) + { + if (de.type) + foundNode(de); + else if (de.original) + { + if (auto se = de.original.isScopeExp()) + foundNode(se.sds); + else + foundNode(de.original.type); + } + else + foundNode(de); + } + } + + override void visit(DotExp de) + { + if (!found) + { + // '.' of erroneous DotIdExp + if (matchLoc(de.loc, 2)) + foundNode(de); + } + } + + override void visit(DotTemplateExp dte) + { + if (!found && dte.td && dte.td.ident) + if (matchIdentifier(dte.identloc, dte.td.ident)) + foundNode(dte); + } + + override void visit(TemplateExp te) + { + if (!found && te.td && te.td.ident) + if (matchIdentifier(te.identloc, te.td.ident)) + foundNode(te); + } + + override void visit(DotVarExp dve) + { + if (!found && dve.var && dve.var.ident) + if (matchIdentifier(dve.varloc.filename ? dve.varloc : dve.loc, dve.var.ident)) + foundNode(dve); + } + + override void visit(VarDeclaration decl) + { + visitTypeIdentifier(decl.parsedType, decl.type, true); + if (!found && decl.originalType != decl.parsedType) + visitTypeIdentifier(decl.originalType, decl.type); + if (!found && decl.type != decl.originalType && decl.type != decl.parsedType) + visitTypeIdentifier(decl.type, decl.type); // not yet semantically analyzed (or a template declaration) + super.visit(decl); + } + + override void visit(EnumDeclaration ed) + { + if (!found && ed.ident) + if (matchIdentifier(ed.loc, ed.ident)) + foundNode(ed); + + visit(cast(ScopeDsymbol)ed); + } + + override void visit(AggregateDeclaration ad) + { + if (!found && ad.ident) + if (matchIdentifier(ad.loc, ad.ident)) + foundNode(ad); + + visit(cast(ScopeDsymbol)ad); + } + + override void visit(ClassDeclaration cd) + { + if (cd.baseclasses) + { + foreach (bc; *(cd.baseclasses)) + { + visitTypeIdentifier(bc.parsedType, bc.type); + } + } + visit(cast(AggregateDeclaration)cd); + } + + override void visit(FuncDeclaration decl) + { + super.visit(decl); + + if (found && !foundScope) + foundScope = decl.scopesym; + + visitTypeIdentifier(decl.originalType, decl.type); + } + + void visitTypeIdentifier(Type originalType, Type resolvedType, bool syntaxCopiedOriginal = false) + { + if (found || !originalType || !resolvedType) + return; + while (originalType.ty != Tident) + { + // val[max] is parsed as an AA, but can be resolved to a static array + if (originalType.ty != resolvedType.ty && + !(originalType.ty == Taarray && resolvedType.ty == Tsarray)) + return; + switch (resolvedType.ty) + { + case Tsarray: + { + auto resolvedSA = cast(TypeSArray) resolvedType; + visitExpression(resolvedSA.dim); + goto case Tarray; + } + case Taarray: + { + auto originalAA = cast(TypeAArray) originalType; + auto resolvedAA = cast(TypeAArray) resolvedType; + visitTypeIdentifier(originalAA.index, resolvedAA.index); + if (found) + return; + goto case; + } + case Tarray: + case Tpointer: + case Treference: + case Tvector: + case Tfunction: + originalType = (cast(TypeNext) originalType).next; + resolvedType = (cast(TypeNext) resolvedType).next; + if (!originalType || !resolvedType) + return; + break; + default: + return; + } + } + auto otype = cast(TypeIdentifier) originalType; + if (otype.copiedFrom && syntaxCopiedOriginal) + otype = otype.copiedFrom; + Loc loc = otype.loc; + if (matchIdentifier(loc, otype.ident)) + { + if (otype.parentScopes.dim > 0) + foundNode(otype.parentScopes[0]); + else + foundNode(resolvedType); + } + else + { + // guess qualified name to be without spaces + foreach (i, id; otype.idents) + { + RootObject obj = id; + if (obj.dyncast() == DYNCAST.identifier) + { + auto ident = cast(Identifier)obj; + if (matchIdentifier(id.loc, ident)) + if (otype.parentScopes.dim > i + 1) + foundNode(otype.parentScopes[i + 1]); + else + foundNode(resolvedType); + } + } + } + } +} + +RootObject _findAST(Dsymbol sym, const(char*) filename, int startLine, int startIndex, int endLine, int endIndex) +{ + scope FindASTVisitor fav = new FindASTVisitor(filename, startLine, startIndex, endLine, endIndex); + sym.accept(fav); + + return fav.found; +} + +RootObject findAST(Module mod, int startLine, int startIndex, int endLine, int endIndex) +{ + auto filename = mod.srcfile.toChars(); + return _findAST(mod, filename, startLine, startIndex, endLine, endIndex); +} + +//////////////////////////////////////////////////////////////////////////////// + +extern(C++) class FindTipVisitor : FindASTVisitor +{ + string tip; + + alias visit = FindASTVisitor.visit; + + this(const(char*) filename, int startLine, int startIndex, int endLine, int endIndex) + { + super(filename, startLine, startIndex, endLine, endIndex); + } + + void visitCallExpression(CallExp expr) + { + if (!found) + { + // replace function type with actual + visitExpression(expr); + if (found is expr.e1) + { + foundNode(expr); + } + } + } + + override bool foundNode(RootObject obj) + { + found = obj; + if (obj) + { + tip = tipForObject(obj, true); + stop = true; + } + return stop; + } +} + +string quoteCode(bool quote, string s) +{ + if (!quote || s.empty) + return s; + return "`" ~ s ~ "`"; +} + +string tipForObject(RootObject obj, bool quote) +{ + string tipForDeclaration(Declaration decl) + { + if (auto func = decl.isFuncDeclaration()) + { + OutBuffer buf; + if (decl.type) + functionToBufferWithIdent(decl.type.toTypeFunction(), &buf, decl.toPrettyChars()); + else + buf.writestring(decl.toPrettyChars()); + auto res = buf.peekSlice(); + buf.extractSlice(); // take ownership + return quoteCode(quote, cast(string)res); + } + + bool fqn = true; + string txt; + string kind; + if (decl.isParameter()) + { + if (decl.parent) + if (auto fd = decl.parent.isFuncDeclaration()) + if (fd.ident.toString().startsWith("__foreachbody")) + kind = "(foreach variable) "; + if (kind.empty) + kind = "(parameter) "; + fqn = false; + } + else if (auto em = decl.isEnumMember()) + { + kind = "(enum value) "; + txt = decl.toPrettyChars(fqn).to!string; + if (em.origValue) + txt ~= " = " ~ cast(string)em.origValue.toString(); + return kind ~ quoteCode(quote, txt); + } + else if (decl.storage_class & STC.manifest) + kind = "(constant) "; + else if (decl.isAliasDeclaration()) + kind = "(alias) "; + else if (decl.isField()) + kind = "(field) "; + else if (decl.semanticRun >= PASS.semanticdone) // avoid lazy semantic analysis + { + if (!decl.isDataseg() && !decl.isCodeseg()) + { + kind = "(local variable) "; + fqn = false; + } + else if (decl.isThreadlocal()) + kind = "(thread local variable) "; + else if (decl.type && decl.type.isShared()) + kind = "(shared variable) "; + else if (decl.type && decl.type.ty != Terror) + kind = "(__gshared variable) "; + } + + if (decl.type) + txt ~= to!string(decl.type.toPrettyChars(true)) ~ " "; + txt ~= to!string(fqn ? decl.toPrettyChars(fqn) : decl.toChars()); + if (decl.storage_class & STC.manifest) + if (auto var = decl.isVarDeclaration()) + if (var._init) + txt ~= " = " ~ var._init.toString(); + if (auto ad = decl.isAliasDeclaration()) + if (ad.aliassym) + txt ~= " = " ~ tipForObject(ad.aliassym, false); + return kind ~ quoteCode(quote, txt); + } + + string tip; + string toc; + const(char)* doc; + + string tipForType(Type t) + { + string kind; + if (t.isTypeIdentifier()) + kind = "unresolved type"; + else if (auto tc = t.isTypeClass()) + kind = tc.sym.isInterfaceDeclaration() ? "interface" : "class"; + else if (auto ts = t.isTypeStruct()) + kind = ts.sym.isUnionDeclaration() ? "union" : "struct"; + else + kind = t.kind().to!string; + string txt = "(" ~ kind ~ ") " ~ quoteCode(quote, t.toPrettyChars(true).to!string); + if (auto sym = typeSymbol(t)) + if (sym.comment) + doc = sym.comment; + return txt; + } + string tipForDotIdExp(DotIdExp die) + { + bool isConstant = die.original.isConstantExpr(); + Expression e1; + if (!isConstant && !die.original.isArrayLengthExp() && die.type) + { + e1 = isAALenCall(die.original); + if (!e1 && die.ident == Id.ptr && die.original.isCastExp()) + e1 = die.original; + if (!e1) + return tipForType(die.type); + } + if (!e1) + e1 = die.e1; + string tip = isConstant ? "(constant) `" : "(field) `"; + tip ~= die.original.type.toPrettyChars(true).to!string ~ " "; + tip ~= e1.type ? die.e1.type.toPrettyChars(true).to!string : e1.toString(); + tip ~= "." ~ die.ident.toString(); + if (isConstant) + tip ~= " = " ~ die.original.toString(); + tip ~= "`"; + return tip; + } + + if (auto t = obj.isType()) + { + toc = tipForType(t.mutableOf().unSharedOf()); + } + else if (auto e = obj.isExpression()) + { + switch(e.op) + { + case TOK.variable: + case TOK.symbolOffset: + tip = tipForDeclaration((cast(SymbolExp)e).var); + doc = (cast(SymbolExp)e).var.comment; + break; + case TOK.dotVariable: + tip = tipForDeclaration((cast(DotVarExp)e).var); + doc = (cast(DotVarExp)e).var.comment; + break; + case TOK.dotIdentifier: + if (e.original && e.original.type) + { + tip = tipForDotIdExp(e.isDotIdExp()); + break; + } + goto default; + default: + if (e.type) + toc = tipForType(e.type); + break; + } + } + else if (auto s = obj.isDsymbol()) + { + if (auto imp = s.isImport()) + if (imp.mod) + s = imp.mod; + if (auto decl = s.isDeclaration()) + tip = tipForDeclaration(decl); + else + toc = "(" ~ s.kind().to!string ~ ") " ~ quoteCode(quote, s.toPrettyChars(true).to!string); + + if (s.comment) + doc = s.comment; + } + if (!tip.length) + { + if (!toc) + toc = quoteCode(quote, obj.toString().dup); + tip = toc; + } + // append doc + if (doc) + tip = tip ~ "\n\n" ~ strip(cast(string)doc[0..strlen(doc)]); + return tip; +} + +string findTip(Module mod, int startLine, int startIndex, int endLine, int endIndex) +{ + auto filename = mod.srcfile.toChars(); + scope FindTipVisitor ftv = new FindTipVisitor(filename, startLine, startIndex, endLine, endIndex); + mod.accept(ftv); + + return ftv.tip; +} +//////////////////////////////////////////////////////////////// + +extern(C++) class FindDefinitionVisitor : FindASTVisitor +{ + Loc loc; + + alias visit = FindASTVisitor.visit; + + this(const(char*) filename, int startLine, int startIndex, int endLine, int endIndex) + { + super(filename, startLine, startIndex, endLine, endIndex); + } + + override bool foundNode(RootObject obj) + { + found = obj; + if (obj) + { + if (auto t = obj.isType()) + { + if (auto sym = typeSymbol(t)) + loc = sym.loc; + } + else if (auto e = obj.isExpression()) + { + switch(e.op) + { + case TOK.variable: + case TOK.symbolOffset: + loc = (cast(SymbolExp)e).var.loc; + break; + case TOK.dotVariable: + loc = (cast(DotVarExp)e).var.loc; + break; + default: + loc = e.loc; + break; + } + } + else if (auto s = obj.isDsymbol()) + { + loc = s.loc; + } + stop = true; + } + return stop; + } +} + +string findDefinition(Module mod, ref int line, ref int index) +{ + auto filename = mod.srcfile.toChars(); + scope FindDefinitionVisitor fdv = new FindDefinitionVisitor(filename, line, index, line, index + 1); + mod.accept(fdv); + + if (!fdv.loc.filename) + return null; + line = fdv.loc.linnum; + index = fdv.loc.charnum; + return to!string(fdv.loc.filename); +} + +//////////////////////////////////////////////////////////////////////////////// + +Loc[] findBinaryIsInLocations(Module mod) +{ + extern(C++) class BinaryIsInVisitor : ASTVisitor + { + Loc[] locdata; + const(char)* filename; + + alias visit = ASTVisitor.visit; + + final void addLocation(const ref Loc loc) + { + if (loc.filename is filename) + locdata ~= loc; + } + + override void visit(InExp e) + { + addLocation(e.oploc); + super.visit(e); + } + override void visit(IdentityExp e) + { + addLocation(e.oploc); + super.visit(e); + } + } + + scope BinaryIsInVisitor biiv = new BinaryIsInVisitor; + biiv.filename = mod.srcfile.toChars(); + biiv.unconditional = true; + mod.accept(biiv); + + return biiv.locdata; +} + +//////////////////////////////////////////////////////////////////////////////// +struct IdTypePos +{ + int type; + int line; + int col; +} + +alias FindIdentifierTypesResult = IdTypePos[][const(char)[]]; + +FindIdentifierTypesResult findIdentifierTypes(Module mod) +{ + extern(C++) class IdentifierTypesVisitor : ASTVisitor + { + FindIdentifierTypesResult idTypes; + const(char)* filename; + + alias visit = ASTVisitor.visit; + + extern(D) + final void addTypePos(const(char)[] ident, int type, int line, int col) + { + if (auto pid = ident in idTypes) + { + // merge sorted + import std.range; + auto a = assumeSorted!"a.line < b.line || (a.line == b.line && a.col < b.col)"(*pid); + auto itp = IdTypePos(type, line, col); + auto sections = a.trisect(itp); + if (!sections[1].empty && sections[1][0].type == type) // upperbound + sections[1][0] = itp; + else if (sections[0].empty || sections[0][$-1].type != type) // lowerbound + *pid = (*pid)[0..sections[0].length] ~ itp ~ (*pid)[sections[0].length..$]; + } + else + idTypes[ident] = [IdTypePos(type, line, col)]; + } + + void addIdent(ref const Loc loc, Identifier ident, int type) + { + if (ident && loc.filename is filename) + addTypePos(ident.toString(), type, loc.linnum, loc.charnum); + } + + void addIdentByType(ref const Loc loc, Identifier ident, Type t) + { + if (ident && t && loc.filename is filename) + { + int type = TypeReferenceKind.Unknown; + switch (t.ty) + { + case Tstruct: type = TypeReferenceKind.Struct; break; + //case Tunion: type = TypeReferenceKind.Union; break; + case Tclass: type = TypeReferenceKind.Class; break; + case Tenum: type = TypeReferenceKind.Enum; break; + default: break; + } + if (type != TypeReferenceKind.Unknown) + addTypePos(ident.toString(), type, loc.linnum, loc.charnum); + } + } + + void addPackages(IdentifiersAtLoc* packages) + { + if (packages) + for (size_t p; p < packages.dim; p++) + addIdent((*packages)[p].loc, (*packages)[p].ident, TypeReferenceKind.Package); + } + + void addDeclaration(ref const Loc loc, Declaration decl) + { + auto ident = decl.ident; + if (auto func = decl.isFuncDeclaration()) + { + auto p = decl.toParent2; + if (p && p.isAggregateDeclaration) + addIdent(loc, ident, TypeReferenceKind.Method); + else + addIdent(loc, ident, TypeReferenceKind.Function); + } + else if (decl.isParameter()) + addIdent(loc, ident, TypeReferenceKind.ParameterVariable); + else if (decl.isEnumMember()) + addIdent(loc, ident, TypeReferenceKind.EnumValue); + else if (decl.storage_class & STC.manifest) + addIdent(loc, ident, TypeReferenceKind.Constant); + else if (decl.isAliasDeclaration()) + addIdent(loc, ident, TypeReferenceKind.Alias); + else if (decl.isField()) + addIdent(loc, ident, TypeReferenceKind.MemberVariable); + else if (!decl.isDataseg() && !decl.isCodeseg()) + addIdent(loc, ident, TypeReferenceKind.LocalVariable); + else if (decl.isThreadlocal()) + addIdent(loc, ident, TypeReferenceKind.TLSVariable); + else if (decl.type && decl.type.isShared()) + addIdent(loc, ident, TypeReferenceKind.SharedVariable); + else + addIdent(loc, ident, TypeReferenceKind.GSharedVariable); + } + + void addType(Type type, Type originalType, bool syntaxCopiedOriginal = false) + { + while (type && originalType && (type.ty == originalType.ty || + (originalType.ty == Taarray && type.ty == Tsarray))) + { + switch (type.ty) + { + case Tsarray: + { + auto resolvedSA = cast(TypeSArray) type; + visitExpression(resolvedSA.dim); + goto case Tarray; + } + case Taarray: + { + auto originalAA = cast(TypeAArray) originalType; + auto resolvedAA = cast(TypeAArray) type; + addType(resolvedAA.index, originalAA.index, syntaxCopiedOriginal); + goto case Tarray; + } + case Tarray: + case Tpointer: + case Treference: + case Tvector: + originalType = (cast(TypeNext) originalType).next; + type = (cast(TypeNext) type ).next; + continue; + default: + break; + } + break; + } + static TypeReferenceKind refkind(Type t) + { + switch (t.ty) + { + case Tident: return TypeReferenceKind.TemplateTypeParameter; + case Tclass: return (cast(TypeClass)t).sym.isInterfaceDeclaration() ? TypeReferenceKind.Interface + : TypeReferenceKind.Class; + case Tstruct: return (cast(TypeStruct)t).sym.isUnionDeclaration() ? TypeReferenceKind.Union + : TypeReferenceKind.Struct; + case Tenum: return TypeReferenceKind.Enum; + default: return TypeReferenceKind.BasicType; + } + } + void addTypeIdentifier(TypeIdentifier tid, Type resolvedType) + { + if (tid.copiedFrom && syntaxCopiedOriginal) + tid = tid.copiedFrom; + if (tid.parentScopes.dim > 0) + addObject(tid.loc, tid.parentScopes[0]); + else + addIdent(tid.loc, tid.ident, refkind(resolvedType)); + + foreach (i, id; tid.idents) + { + RootObject obj = id; + if (obj.dyncast() == DYNCAST.identifier) + { + auto ident = cast(Identifier)obj; + if (tid.parentScopes.dim > i + 1) + addObject(id.loc, tid.parentScopes[i + 1]); + else + addIdent(id.loc, id, refkind(resolvedType)); + } + } + } + + if (originalType && originalType.ty == Tident && type) + addTypeIdentifier(cast(TypeIdentifier) originalType, type); + else if (type && type.ty == Tident) // not yet semantically analyzed (or a template declaration) + addTypeIdentifier(cast(TypeIdentifier) type, type); + } + + void addObject(ref const Loc loc, RootObject obj) + { + if (auto t = obj.isType()) + addType(t, t); + else if (auto s = obj.isDsymbol()) + { + if (auto imp = s.isImport()) + if (imp.mod) + s = imp.mod; + addSymbol(loc, s); + } + else if (auto e = obj.isExpression()) + e.accept(this); + } + + void addSymbol(ref const Loc loc, Dsymbol sym) + { + if (auto decl = sym.isDeclaration()) + addDeclaration(loc, decl); + else if (sym.isModule()) + addIdent(loc, sym.ident, TypeReferenceKind.Module); + else if (sym.isPackage()) + addIdent(loc, sym.ident, TypeReferenceKind.Package); + else + addIdent(loc, sym.ident, TypeReferenceKind.Variable); + } + + override void visit(Dsymbol sym) + { + addSymbol(sym.loc, sym); + } + + override void visit(Parameter sym) + { + addIdent(sym.ident.loc, sym.ident, TypeReferenceKind.ParameterVariable); + } + + override void visit(Module mod) + { + if (mod.md) + { + addPackages(mod.md.packages); + addIdent(mod.md.loc, mod.md.id, TypeReferenceKind.Module); + } + visit(cast(Package)mod); + } + + override void visit(Import imp) + { + addPackages(imp.packages); + + addIdent(imp.loc, imp.id, TypeReferenceKind.Module); + + for (int n = 0; n < imp.names.dim; n++) + { + addIdent(imp.names[n].loc, imp.names[n].ident, TypeReferenceKind.Alias); + if (imp.aliases[n].ident && n < imp.aliasdecls.dim) + addDeclaration(imp.aliases[n].loc, imp.aliasdecls[n]); + } + // symbol has ident of first package, so don't forward + } + + override void visit(DebugCondition cond) + { + addIdent(cond.loc, cond.ident, TypeReferenceKind.VersionIdentifier); + } + + override void visit(VersionCondition cond) + { + addIdent(cond.loc, cond.ident, TypeReferenceKind.VersionIdentifier); + } + + override void visit(VarDeclaration decl) + { + addType(decl.type, decl.originalType); + if (decl.parsedType != decl.originalType) + addType(decl.type, decl.parsedType, true); + super.visit(decl); + } + + override void visit(SymbolExp expr) + { + if (expr.var && expr.var.ident) + addDeclaration(expr.loc, expr.var); + super.visit(expr); + } + + override void visit(NewExp ne) + { + if (ne.member) + ne.member.accept(this); + + addType(ne.newtype, ne.parsedType, true); + if (ne.newtype != ne.parsedType) + addType(ne.newtype, ne.newtype); + + super.visit(ne); + } + + override void visit(TypeExp expr) + { + if (expr.original && expr.type) + { + if (auto ie = expr.original.isIdentifierExp()) + { + addIdentByType(ie.loc, ie.ident, expr.type); + } + else if (auto die = expr.original.isDotIdExp()) + { + addIdentByType(die.ident.loc, die.ident, expr.type); + } + } + super.visit(expr); + } + + override void visit(IdentifierExp expr) + { + if (expr.original) + if (auto se = expr.original.isScopeExp()) + addSymbol(expr.loc, se.sds); + +// if (expr.type) +// addIdentByType(expr.loc, expr.ident, expr.type); +// else if (expr.original && expr.original.type) +// addIdentByType(expr.loc, expr.ident, expr.original.type); +// else + super.visit(expr); + } + + override void visit(DotIdExp expr) + { + auto orig = expr.original; + if (orig && orig.type && orig.isConstantExpr()) + addIdent(expr.identloc, expr.ident, TypeReferenceKind.Constant); + else if (orig && orig.type && + (orig.isArrayLengthExp() || orig.isAALenCall() || (expr.ident == Id.ptr && orig.isCastExp()))) + addIdent(expr.identloc, expr.ident, TypeReferenceKind.MemberVariable); + else + super.visit(expr); + } + + override void visit(DotVarExp dve) + { + if (dve.var && dve.var.ident) + addDeclaration(dve.varloc.filename ? dve.varloc : dve.loc, dve.var); + super.visit(dve); + } + + override void visit(ScopeExp expr) + { + if (auto ti = expr.sds.isTemplateInstance()) + { + if (ti.tiargs && ti.parsedArgs) + { + size_t args = min(ti.tiargs.dim, ti.parsedArgs.dim); + for (size_t a = 0; a < args; a++) + if (Type tip = (*ti.parsedArgs)[a].isType()) + if (Type tir = (*ti.tiargs)[a].isType()) + addType(tir, tip); + } + } + super.visit(expr); + } + + override void visit(CastExp expr) + { + addType(expr.to, expr.parsedTo, true); + super.visit(expr); + } + + override void visit(EnumDeclaration ed) + { + addIdent(ed.loc, ed.ident, TypeReferenceKind.Enum); + super.visit(ed); + } + + override void visit(FuncDeclaration decl) + { + super.visit(decl); + + if (decl.type) + { + auto ft = decl.type.isTypeFunction(); + auto ot = decl.originalType ? decl.originalType.isTypeFunction() : null; + addType(ft ? ft.nextOf() : null, ot ? ot.nextOf() : null); // the return type + } + } + + override void visit(AggregateDeclaration ad) + { + if (ad.isInterfaceDeclaration) + addIdent(ad.loc, ad.ident, TypeReferenceKind.Interface); + else if (ad.isClassDeclaration) + addIdent(ad.loc, ad.ident, TypeReferenceKind.Class); + else if (ad.isUnionDeclaration) + addIdent(ad.loc, ad.ident, TypeReferenceKind.Union); + else + addIdent(ad.loc, ad.ident, TypeReferenceKind.Struct); + super.visit(ad); + } + + override void visit(ClassDeclaration cd) + { + if (cd.baseclasses) + foreach (bc; *(cd.baseclasses)) + addType(bc.type, bc.parsedType); + + return super.visit(cd); + } + } + + scope IdentifierTypesVisitor itv = new IdentifierTypesVisitor; + itv.filename = mod.srcfile.toChars(); + mod.accept(itv); + + return itv.idTypes; +} + +//////////////////////////////////////////////////////////////////////////////// +struct Reference +{ + Loc loc; + Identifier ident; +} + +Reference[] findReferencesInModule(Module mod, int line, int index) +{ + auto filename = mod.srcfile.toChars(); + scope FindDefinitionVisitor fdv = new FindDefinitionVisitor(filename, line, index, line, index + 1); + mod.accept(fdv); + + if (!fdv.found) + return null; + + extern(C++) class FindReferencesVisitor : ASTVisitor + { + RootObject search; + Reference[] references; + + alias visit = ASTVisitor.visit; + + extern(D) + void addReference(ref const Loc loc, Identifier ident) + { + if (loc.filename && ident) + if (!references.contains(Reference(loc, ident))) + references ~= Reference(loc, ident); + } + + override void visit(Dsymbol sym) + { + if (sym is search) + addReference(sym.loc, sym.ident); + } + override void visit(SymbolExp expr) + { + if (expr.var is search) + addReference(expr.loc, expr.var.ident); + } + override void visit(DotVarExp dve) + { + if (dve.var is search) + addReference(dve.varloc.filename ? dve.varloc : dve.loc, dve.var.ident); + } + } + + scope FindReferencesVisitor frv = new FindReferencesVisitor(); + + if (auto t = fdv.found.isType()) + { + if (t.ty == Tstruct) + fdv.found = (cast(TypeStruct)t).sym; + } + else if (auto e = fdv.found.isExpression()) + { + switch(e.op) + { + case TOK.variable: + case TOK.symbolOffset: + fdv.found = (cast(SymbolExp)e).var; + break; + case TOK.dotVariable: + fdv.found = (cast(DotVarExp)e).var; + break; + default: + break; + } + } + frv.search = fdv.found; + mod.accept(frv); + + return frv.references; +} + +//////////////////////////////////////////////////////////////////////////////// +string[] findExpansions(Module mod, int line, int index, string tok) +{ + auto filename = mod.srcfile.toChars(); + scope FindDefinitionVisitor fdv = new FindDefinitionVisitor(filename, line, index, line, index + 1); + mod.accept(fdv); + + if (!fdv.found) + return null; + + int flags = 0; + Type type = fdv.found.isType(); + if (auto e = fdv.found.isExpression()) + { + switch(e.op) + { + case TOK.variable: + case TOK.symbolOffset: + //type = (cast(SymbolExp)e).var.type; + break; + case TOK.dotVariable: + case TOK.dotIdentifier: + type = (cast(UnaExp)e).e1.type; + flags |= SearchLocalsOnly; + break; + case TOK.dot: + type = (cast(DotExp)e).e1.type; + flags |= SearchLocalsOnly; + break; + default: + break; + } + } + + auto sds = fdv.foundScope; + if (type) + if (auto sym = typeSymbol(type)) + sds = sym; + + string[void*] idmap; // doesn't work with extern(C++) classes + void searchScope(ScopeDsymbol sds, int flags) + { + static Dsymbol uplevel(Dsymbol s) + { + if (auto ad = s.isAggregateDeclaration()) + return ad.enclosing; + return s.toParent; + } + // TODO: properties + // TODO: base classes + // TODO: struct/class not going to parent if accessed from elsewhere (but does if nested) + for (Dsymbol ds = sds; ds; ds = uplevel(ds)) + { + ScopeDsymbol sd = ds.isScopeDsymbol(); + if (!sd) + continue; + + //foreach (pair; sd.symtab.tab.asRange) + if (sd.symtab) + { + foreach (key, s; sd.symtab.tab.aa) + { + //Dsymbol s = pair.value; + if (!symbolIsVisible(mod, s)) + continue; + auto ident = /*pair.*/(cast(Dsymbol)key).toString(); + if (ident.startsWith(tok)) + idmap[cast(void*)s] = ident.idup; + } + } + + // TODO: alias this + + // imported modules + size_t cnt = sd.importedScopes ? sd.importedScopes.dim : 0; + for (size_t i = 0; i < cnt; i++) + { + if ((flags & IgnorePrivateImports) && sd.prots[i] == Prot.Kind.private_) + continue; + auto ss = (*sd.importedScopes)[i].isScopeDsymbol(); + if (!ss) + continue; + + int sflags = 0; + if (ss.isModule()) + { + if (flags & SearchLocalsOnly) + continue; + sflags |= IgnorePrivateImports; + } + else // mixin template + { + if (flags & SearchImportsOnly) + continue; + sflags |= SearchLocalsOnly; + } + searchScope(ss, sflags | IgnorePrivateImports); + } + } + } + searchScope(sds, flags); + + string[] idlist; + foreach(sym, id; idmap) + idlist ~= id ~ ":" ~ cast(string) (cast(Dsymbol)sym).toString(); + return idlist; +} + +//////////////////////////////////////////////////////////////////////////////// + +bool isConstantExpr(Expression expr) +{ + switch(expr.op) + { + case TOK.int64, TOK.float64, TOK.char_, TOK.complex80: + case TOK.null_, TOK.void_: + case TOK.string_: + case TOK.arrayLiteral, TOK.assocArrayLiteral, TOK.structLiteral: + case TOK.classReference: + //case TOK.type: + case TOK.vector: + case TOK.function_, TOK.delegate_: + case TOK.symbolOffset, TOK.address: + case TOK.typeid_: + case TOK.slice: + return true; + default: + return false; + } +} + +// return first argument to aaLen() +Expression isAALenCall(Expression expr) +{ + // unpack first argument of _aaLen(aa) + if (auto ce = expr.isCallExp()) + if (auto ve = ce.e1.isVarExp()) + if (ve.var.ident is Id.aaLen) + if (ce.arguments && ce.arguments.dim > 0) + return (*ce.arguments)[0]; + return null; +} + +//////////////////////////////////////////////////////////////////////////////// + +ScopeDsymbol typeSymbol(Type type) +{ + if (auto ts = type.isTypeStruct()) + return ts.sym; + if (auto tc = type.isTypeClass()) + return tc.sym; + if (auto te = type.isTypeEnum()) + return te.sym; + return null; +} + +Module cloneModule(Module mo) +{ + if (!mo) + return null; + Module m = new Module(mo.srcfile.toString(), mo.ident, mo.isDocFile, mo.isHdrFile); + *cast(FileName*)&(m.srcfile) = mo.srcfile; // keep identical source file name pointer + m.isPackageFile = mo.isPackageFile; + m.md = mo.md; + mo.syntaxCopy(m); + + extern(C++) class AdjustModuleVisitor : ASTVisitor + { + // avoid allocating capture + Module m; + this (Module m) + { + this.m = m; + } + + alias visit = ASTVisitor.visit; + + override void visit(ConditionalStatement cond) + { + if (auto dbg = cond.condition.isDebugCondition()) + cond.condition = new DebugCondition(dbg.loc, m, dbg.level, dbg.ident); + else if (auto ver = cond.condition.isVersionCondition()) + cond.condition = new VersionCondition(ver.loc, m, ver.level, ver.ident); + } + + override void visit(ConditionalDeclaration cond) + { + if (auto dbg = cond.condition.isDebugCondition()) + cond.condition = new DebugCondition(dbg.loc, m, dbg.level, dbg.ident); + else if (auto ver = cond.condition.isVersionCondition()) + cond.condition = new VersionCondition(ver.loc, m, ver.level, ver.ident); + } + } + + import dmd.permissivevisitor; + scope v = new AdjustModuleVisitor(m); + m.accept(v); + return m; +} + +Module createModuleFromText(string filename, string text) +{ + import std.path; + + text ~= "\0\0"; // parser needs 2 trailing zeroes + string name = stripExtension(baseName(filename)); + auto id = Identifier.idPool(name); + auto mod = new Module(filename, id, true, false); + mod.srcBuffer = new FileBuffer(cast(ubyte[])text); + mod.read(Loc.initial); + mod.parse(); + return mod; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/vdc/interpret.d b/vdc/interpret.d index f5b72f45..f9de8850 100644 --- a/vdc/interpret.d +++ b/vdc/interpret.d @@ -207,7 +207,7 @@ class Value return semanticErrorValue("cannot calculate property ", prop, " of value ", toStr()); } - @disable Value _interpretProperty(Context ctx, string prop) + /*@disable*/ Value _interpretProperty(Context ctx, string prop) { return getType()._interpretProperty(ctx, prop); } @@ -1237,7 +1237,7 @@ class DynArrayValue : ArrayValue!TypeDynamicArray return super.toMixin(); } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { switch(prop) { @@ -1510,7 +1510,7 @@ class PointerValue : Value } } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { switch(prop) { @@ -1688,7 +1688,7 @@ public: } } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { switch(prop) { @@ -1864,7 +1864,7 @@ class AggrValue : TupleValue return "" ~ _toStr("{", "}"); } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { auto type = getType(); if(Value v = type.getProperty(this, prop, true)) @@ -2007,7 +2007,7 @@ class ReferenceValueT(T) : ReferenceValue return type; } - @disable override Value _interpretProperty(Context ctx, string prop) + /*@disable*/ override Value _interpretProperty(Context ctx, string prop) { if(instance) if(Value v = instance._interpretProperty(ctx, prop)) diff --git a/vdc/ivdserver.d b/vdc/ivdserver.d index cac03a08..471c5433 100644 --- a/vdc/ivdserver.d +++ b/vdc/ivdserver.d @@ -88,6 +88,8 @@ public: // startLine, startIndex, endLine, endIndex: selected range in the editor // if start==end, mouse hovers without selection // flags: 1 - try to evaluate constants/expressions + // flags: 2 - quote code for highlighting + // flags: 4 - return all overloads (rather than the current best match) // // it is assumed that the semantic analysis is forwarded to some other thread // and that the status can be polled by GetTipResult @@ -220,7 +222,7 @@ public: /////////////////////////////////////////////////////////////////////// uint ConfigureFlags()(bool unittestOn, bool debugOn, bool x64, bool cov, bool doc, bool nobounds, bool gdc, - int versionLevel, int debugLevel, bool noDeprecated, bool ldc, bool msvcrt, + int versionLevel, int debugLevel, bool noDeprecated, bool ldc, bool msvcrt, bool warnings, bool mixinAnalysis, bool ufcsExpansions) { return (unittestOn ? 1 : 0) @@ -233,9 +235,43 @@ uint ConfigureFlags()(bool unittestOn, bool debugOn, bool x64, bool cov, bool do | (noDeprecated ? 128 : 0) | ((versionLevel & 0xff) << 8) | ((debugLevel & 0xff) << 16) - | (mixinAnalysis ? 0x1_00_00_00 : 0) - | (ufcsExpansions ? 0x2_00_00_00 : 0) - | (ldc ? 0x4_00_00_00 : 0) - | (msvcrt ? 0x8_00_00_00 : 0); + | (mixinAnalysis ? 0x01_00_00_00 : 0) + | (ufcsExpansions ? 0x02_00_00_00 : 0) + | (ldc ? 0x04_00_00_00 : 0) + | (msvcrt ? 0x08_00_00_00 : 0) + | (warnings ? 0x10_00_00_00 : 0); } +// from D_Parser: types returned by GetIdentifierTypes +enum TypeReferenceKind : uint +{ + Unknown, + + Interface, + Enum, + EnumValue, + Template, + Class, + Struct, + Union, + TemplateTypeParameter, + + Constant, + LocalVariable, + ParameterVariable, + TLSVariable, + SharedVariable, + GSharedVariable, + MemberVariable, + Variable, + + Alias, + Module, + Package = Module, // todo + Function, + Method, + BasicType, + + DebugIdentifier, + VersionIdentifier, +} diff --git a/vdc/ivdserver.idl b/vdc/ivdserver.idl new file mode 100644 index 00000000..52e1af1c --- /dev/null +++ b/vdc/ivdserver.idl @@ -0,0 +1,42 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2012 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +// bring in core IDL files +import "oaidl.idl"; + +[ + object, + uuid(002a2de9-8bb6-484d-9901-7e4ad4084715), + dual, + nonextensible, + helpstring("IVDServer Interface"), + pointer_default(unique) +] +interface IVDServer : IUnknown +{ + HRESULT ConfigureSemanticProject([in] BSTR filename, [in] BSTR imp, [in] BSTR stringImp, [in] BSTR versionids, [in] BSTR debugids, [in] DWORD flags); + HRESULT ClearSemanticProject(); + HRESULT UpdateModule([in] BSTR filename, [in] BSTR srcText, [in] DWORD flags); + HRESULT GetTip([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex, [in] DWORD flags); + HRESULT GetTipResult([out] DWORD *startLine, [out] DWORD *startIndex, [out] DWORD *endLine, [out] DWORD *endIndex, [out,retval] BSTR* answer); + HRESULT GetSemanticExpansions([in] BSTR filename, [in] BSTR tok, [in] DWORD line, [in] DWORD idx, [in] BSTR expr); + HRESULT GetSemanticExpansionsResult([out,retval] BSTR* stringList); + HRESULT IsBinaryOperator([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex, [out,retval] BOOL* pIsOp); + HRESULT GetParseErrors([in] BSTR filename, [out, retval] BSTR* errors); + HRESULT GetBinaryIsInLocations([in] BSTR filename, [out,retval] VARIANT* locs); // array of pairs of DWORD + HRESULT GetLastMessage([out,retval] BSTR* message); + HRESULT GetIdentifierTypes([in] BSTR filename, [in] DWORD startLine, [in] DWORD endLine, [in] DWORD flags); + HRESULT GetIdentifierTypesResult([out, retval] BSTR* types); + HRESULT GetDefinition([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex); + HRESULT GetDefinitionResult([out] DWORD *startLine, [out] DWORD *startIndex, [out] DWORD *endLine, [out] DWORD *endIndex, [out,retval] BSTR* filename); + HRESULT GetReferences([in] BSTR filename, [in] BSTR tok, [in] DWORD line, [in] DWORD idx, [in] BSTR expr, [in] BOOL moduleOnly); + HRESULT GetReferencesResult([out,retval] BSTR* stringList); + HRESULT ConfigureCommentTasks([in] BSTR tasks); + HRESULT GetCommentTasks([in] BSTR filename, [out,retval] BSTR* tasks); +}; + diff --git a/vdc/parser.visualdproj b/vdc/parser.visualdproj index fce31c07..f8b4b546 100644 --- a/vdc/parser.visualdproj +++ b/vdc/parser.visualdproj @@ -32,7 +32,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -45,7 +45,6 @@ 0 0 0 - 2 0 0 0 @@ -54,14 +53,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -100,10 +98,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -154,7 +153,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -167,7 +166,6 @@ 0 0 0 - 2 0 0 0 @@ -176,14 +174,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -222,10 +219,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -276,7 +274,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -289,7 +287,6 @@ 0 0 0 - 2 0 0 0 @@ -298,14 +295,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -344,10 +340,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -398,7 +395,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -411,7 +408,6 @@ 0 0 0 - 2 0 0 0 @@ -420,14 +416,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -466,10 +461,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -520,7 +516,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -533,7 +529,6 @@ 0 0 0 - 2 0 0 0 @@ -542,14 +537,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -588,10 +582,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -642,7 +637,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -655,7 +650,6 @@ 0 0 0 - 2 0 0 0 @@ -664,14 +658,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -681,7 +674,7 @@ m:\s\d\rainers\windows\bin\dmd.exe .. . - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -710,10 +703,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -764,7 +758,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -777,7 +771,6 @@ 0 0 0 - 2 0 0 0 @@ -786,14 +779,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 1 0 @@ -832,10 +824,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -886,7 +879,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -899,7 +892,6 @@ 0 0 0 - 2 0 0 0 @@ -908,14 +900,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 1 0 @@ -954,10 +945,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1008,7 +1000,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1021,7 +1013,6 @@ 0 0 0 - 2 0 0 0 @@ -1030,14 +1021,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 2 0 @@ -1076,10 +1066,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1130,7 +1121,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1143,7 +1134,6 @@ 0 0 0 - 2 0 0 0 @@ -1152,14 +1142,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 2 0 @@ -1198,10 +1187,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1252,7 +1242,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1265,7 +1255,6 @@ 0 0 0 - 2 0 0 0 @@ -1274,14 +1263,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -1320,10 +1308,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1374,7 +1363,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1387,7 +1376,6 @@ 0 0 0 - 2.043 0 0 0 @@ -1396,24 +1384,23 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 - 1 + 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. . - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1442,10 +1429,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1496,7 +1484,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -1509,7 +1497,6 @@ 0 0 0 - 2 0 0 0 @@ -1518,14 +1505,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 2 0 @@ -1564,10 +1550,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1618,7 +1605,7 @@ 0 0 0 - 0 + 0 0 1 0 @@ -1631,7 +1618,6 @@ 0 0 0 - 2 0 0 0 @@ -1640,14 +1626,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 2 0 @@ -1686,10 +1671,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1709,7 +1695,6 @@ *.obj - 0 0 0 1 @@ -1741,7 +1726,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1754,7 +1739,6 @@ 0 0 0 - 2 0 0 0 @@ -1763,14 +1747,13 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 0 @@ -1809,10 +1792,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1863,7 +1847,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1876,7 +1860,6 @@ 0 0 0 - 2 0 0 0 @@ -1885,24 +1868,23 @@ 0 0 0 - 0 - 0 + 0 + 0 0 0 - 0 - 0 - 0 - 0 + 0 + 0 + 0 0 0 - 1 + 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. . - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1931,10 +1913,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -1985,8 +1968,8 @@ + - diff --git a/vdc/semantic.d b/vdc/semantic.d index cc5dbd5c..06f00065 100644 --- a/vdc/semantic.d +++ b/vdc/semantic.d @@ -21,6 +21,7 @@ import vdc.parser.engine; import vdc.logger; import vdc.interpret; import vdc.versions; +import vdc.semanticopt; import stdext.util; import stdext.array; @@ -833,207 +834,3 @@ class Project : Node } } } - -struct VersionInfo -{ - TextPos defined; // line -1 if not defined yet - TextPos firstUsage; // line int.max if not used yet -} - -struct VersionDebug -{ - int level; - VersionInfo[string] identifiers; - - bool reset(int lev, string[] ids) - { - if(lev == level && ids.length == identifiers.length) - { - bool different = false; - foreach(id; ids) - if(id !in identifiers) - different = true; - if(!different) - return false; - } - - level = lev; - identifiers = identifiers.init; - foreach(id; ids) - identifiers[id] = VersionInfo(); - - return true; - } - - bool preDefined(string ident) const - { - if(auto vi = ident in identifiers) - return vi.defined.line >= 0; - return false; - } - - bool defined(string ident, TextPos pos) - { - if(auto vi = ident in identifiers) - { - if(pos < vi.defined) - semanticErrorPos(pos, "identifier " ~ ident ~ " used before defined"); - - if(pos < vi.firstUsage) - vi.firstUsage = pos; - - return vi.defined.line >= 0; - } - VersionInfo vi; - vi.defined.line = -1; - vi.firstUsage = pos; - identifiers[ident] = vi; - return false; - } - - void define(string ident, TextPos pos) - { - if(auto vi = ident in identifiers) - { - if(pos > vi.firstUsage) - semanticErrorPos(pos, "identifier " ~ ident ~ " defined after usage"); - if(pos < vi.defined) - vi.defined = pos; - } - - VersionInfo vi; - vi.firstUsage.line = int.max; - vi.defined = pos; - identifiers[ident] = vi; - } -} - -class Options -{ - string[] importDirs; - string[] stringImportDirs; - - public /* debug & version handling */ { - bool unittestOn; - bool x64; - bool msvcrt; - bool debugOn; - bool coverage; - bool doDoc; - bool noBoundsCheck; - bool gdcCompiler; - bool ldcCompiler; - bool noDeprecated; - bool mixinAnalysis; - bool UFCSExpansions; - VersionDebug debugIds; - VersionDebug versionIds; - - int changeCount; - - bool setImportDirs(string[] dirs) - { - if(dirs == importDirs) - return false; - - importDirs = dirs.dup; - changeCount++; - return true; - } - bool setStringImportDirs(string[] dirs) - { - if(dirs == stringImportDirs) - return false; - - stringImportDirs = dirs.dup; - changeCount++; - return true; - } - bool setVersionIds(int level, string[] versionids) - { - if(!versionIds.reset(level, versionids)) - return false; - changeCount++; - return true; - } - bool setDebugIds(int level, string[] debugids) - { - if(!debugIds.reset(level, debugids)) - return false; - changeCount++; - return true; - } - - bool versionEnabled(string ident) - { - int pre = versionPredefined(ident); - if(pre == 0) - return versionIds.defined(ident, TextPos()); - - return pre > 0; - } - - bool versionEnabled(int level) - { - return level <= versionIds.level; - } - - bool debugEnabled(string ident) - { - return debugIds.defined(ident, TextPos()); - } - - bool debugEnabled(int level) - { - return level <= debugIds.level; - } - - int versionPredefined(string ident) - { - int* p = ident in sPredefinedVersions; - if(!p) - return 0; - if(*p) - return *p; - - switch(ident) - { - case "unittest": - return unittestOn ? 1 : -1; - case "assert": - return unittestOn || debugOn ? 1 : -1; - case "D_Coverage": - return coverage ? 1 : -1; - case "D_Ddoc": - return doDoc ? 1 : -1; - case "D_NoBoundsChecks": - return noBoundsCheck ? 1 : -1; - case "Win32": - case "X86": - case "D_InlineAsm_X86": - return x64 ? -1 : 1; - case "CRuntime_DigitalMars": - return msvcrt ? -1 : 1; - case "CRuntime_Microsoft": - return msvcrt ? 1 : -1; - case "MinGW": - return gdcCompiler || (ldcCompiler && !msvcrt) ? 1 : -1; - case "Win64": - case "X86_64": - case "D_InlineAsm_X86_64": - case "D_LP64": - return x64 ? 1 : -1; - case "GNU": - return gdcCompiler ? 1 : -1; - case "LDC": - return ldcCompiler ? 1 : -1; - case "DigitalMars": - return gdcCompiler || ldcCompiler ? -1 : 1; - default: - assert(false, "inconsistent predefined versions"); - } - } - - } -} - diff --git a/vdc/semanticopt.d b/vdc/semanticopt.d new file mode 100644 index 00000000..c3656d42 --- /dev/null +++ b/vdc/semanticopt.d @@ -0,0 +1,239 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +module vdc.semanticopt; + +version(MARS) +{ + struct TextPos + { + enum line = 0; // always defined + } +} +else +{ + import vdc.semantic; + import vdc.util; + import vdc.versions; +} + +struct VersionInfo +{ + TextPos defined; // line -1 if not defined yet + TextPos firstUsage; // line int.max if not used yet +} + +struct VersionDebug +{ + int level; + VersionInfo[string] identifiers; + + bool reset(int lev, string[] ids) + { + if(lev == level && ids.length == identifiers.length) + { + bool different = false; + foreach(id; ids) + if(id !in identifiers) + different = true; + if(!different) + return false; + } + + level = lev; + identifiers = identifiers.init; + foreach(id; ids) + identifiers[id] = VersionInfo(); + + return true; + } + + bool preDefined(string ident) const + { + if(auto vi = ident in identifiers) + return vi.defined.line >= 0; + return false; + } + + bool defined(string ident, TextPos pos) + { + version(MARS) + { + return (ident in identifiers) != null; + } + else + { + if(auto vi = ident in identifiers) + { + if(pos < vi.defined) + semanticErrorPos(pos, "identifier " ~ ident ~ " used before defined"); + + if(pos < vi.firstUsage) + vi.firstUsage = pos; + + return vi.defined.line >= 0; + } + VersionInfo vi; + vi.defined.line = -1; + vi.firstUsage = pos; + identifiers[ident] = vi; + return false; + } + } + + version(MARS) {} else + void define(string ident, TextPos pos) + { + if(auto vi = ident in identifiers) + { + if(pos > vi.firstUsage) + semanticErrorPos(pos, "identifier " ~ ident ~ " defined after usage"); + if(pos < vi.defined) + vi.defined = pos; + } + + VersionInfo vi; + vi.firstUsage.line = int.max; + vi.defined = pos; + identifiers[ident] = vi; + } +} + +class Options +{ + string[] importDirs; + string[] stringImportDirs; + + public /* debug & version handling */ { + bool unittestOn; + bool x64; + bool msvcrt; + bool debugOn; + bool coverage; + bool doDoc; + bool noBoundsCheck; + bool warnings; + bool gdcCompiler; + bool ldcCompiler; + bool noDeprecated; + bool mixinAnalysis; + bool UFCSExpansions; + VersionDebug debugIds; + VersionDebug versionIds; + + int changeCount; + + bool setImportDirs(string[] dirs) + { + if(dirs == importDirs) + return false; + + importDirs = dirs.dup; + changeCount++; + return true; + } + bool setStringImportDirs(string[] dirs) + { + if(dirs == stringImportDirs) + return false; + + stringImportDirs = dirs.dup; + changeCount++; + return true; + } + bool setVersionIds(int level, string[] versionids) + { + if(!versionIds.reset(level, versionids)) + return false; + changeCount++; + return true; + } + bool setDebugIds(int level, string[] debugids) + { + if(!debugIds.reset(level, debugids)) + return false; + changeCount++; + return true; + } + + bool versionEnabled(string ident) + { + int pre = versionPredefined(ident); + if(pre == 0) + return versionIds.defined(ident, TextPos()); + + return pre > 0; + } + + bool versionEnabled(int level) + { + return level <= versionIds.level; + } + + bool debugEnabled(string ident) + { + return debugIds.defined(ident, TextPos()); + } + + bool debugEnabled(int level) + { + return level <= debugIds.level; + } + + int versionPredefined(string ident) + { + version(MARS) {} else + { + int* p = ident in sPredefinedVersions; + if(!p) + return 0; + if(*p) + return *p; + } + + switch(ident) + { + case "unittest": + return unittestOn ? 1 : -1; + case "assert": + return unittestOn || debugOn ? 1 : -1; + case "D_Coverage": + return coverage ? 1 : -1; + case "D_Ddoc": + return doDoc ? 1 : -1; + case "D_NoBoundsChecks": + return noBoundsCheck ? 1 : -1; + case "Win32": + case "X86": + case "D_InlineAsm_X86": + return x64 ? -1 : 1; + case "CRuntime_DigitalMars": + return msvcrt ? -1 : 1; + case "CRuntime_Microsoft": + return msvcrt ? 1 : -1; + case "MinGW": + return gdcCompiler || (ldcCompiler && !msvcrt) ? 1 : -1; + case "Win64": + case "X86_64": + case "D_InlineAsm_X86_64": + case "D_LP64": + return x64 ? 1 : -1; + case "GNU": + return gdcCompiler ? 1 : -1; + case "LDC": + return ldcCompiler ? 1 : -1; + case "DigitalMars": + return gdcCompiler || ldcCompiler ? -1 : 1; + default: + assert(false, "inconsistent predefined versions"); + } + } + + } +} + diff --git a/vdc/vdserver.d b/vdc/vdserver.d index b5c9ab54..3a9f2272 100644 --- a/vdc/vdserver.d +++ b/vdc/vdserver.d @@ -184,7 +184,7 @@ class VDServer : ComObject, IVDServer uint oldflags = ConfigureFlags!()(opts.unittestOn, opts.debugOn, opts.x64, opts.coverage, opts.doDoc, opts.noBoundsCheck, opts.gdcCompiler, 0, 0, // no need to compare version levels, done in setVersionIds - opts.noDeprecated, opts.ldcCompiler, opts.msvcrt, + opts.noDeprecated, opts.ldcCompiler, opts.msvcrt, opts.warnings, opts.mixinAnalysis, opts.UFCSExpansions); opts.unittestOn = (flags & 1) != 0; @@ -199,6 +199,7 @@ class VDServer : ComObject, IVDServer opts.UFCSExpansions = (flags & 0x2_00_00_00) != 0; opts.ldcCompiler = (flags & 0x4_00_00_00) != 0; opts.msvcrt = (flags & 0x8_00_00_00) != 0; + opts.warnings = (flags & 0x10_00_00_00) != 0; int versionlevel = (flags >> 8) & 0xff; int debuglevel = (flags >> 16) & 0xff; @@ -208,7 +209,7 @@ class VDServer : ComObject, IVDServer int changed = (oldflags != (flags & 0xff0000ff)); changed += opts.setImportDirs(splitLines(imports)); - changed += opts.setImportDirs(splitLines(imports)); + changed += opts.setStringImportDirs(splitLines(strImports)); changed += opts.setVersionIds(versionlevel, splitLines(verids)); changed += opts.setDebugIds(debuglevel, splitLines(dbgids)); } diff --git a/vdc/vdserver.idl b/vdc/vdserver.idl index ce29f3a9..3c10aa06 100644 --- a/vdc/vdserver.idl +++ b/vdc/vdserver.idl @@ -8,37 +8,7 @@ // bring in core IDL files import "oaidl.idl"; - -[ - object, - uuid(002a2de9-8bb6-484d-9901-7e4ad4084715), - dual, - nonextensible, - helpstring("IVDServer Interface"), - pointer_default(unique) -] -interface IVDServer : IUnknown -{ - HRESULT ConfigureSemanticProject([in] BSTR filename, [in] BSTR imp, [in] BSTR stringImp, [in] BSTR versionids, [in] BSTR debugids, [in] DWORD flags); - HRESULT ClearSemanticProject(); - HRESULT UpdateModule([in] BSTR filename, [in] BSTR srcText, [in] DWORD flags); - HRESULT GetTip([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex, [in] DWORD flags); - HRESULT GetTipResult([out] DWORD *startLine, [out] DWORD *startIndex, [out] DWORD *endLine, [out] DWORD *endIndex, [out,retval] BSTR* answer); - HRESULT GetSemanticExpansions([in] BSTR filename, [in] BSTR tok, [in] DWORD line, [in] DWORD idx, [in] BSTR expr); - HRESULT GetSemanticExpansionsResult([out,retval] BSTR* stringList); - HRESULT IsBinaryOperator([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex, [out,retval] BOOL* pIsOp); - HRESULT GetParseErrors([in] BSTR filename, [out, retval] BSTR* errors); - HRESULT GetBinaryIsInLocations([in] BSTR filename, [out,retval] VARIANT* locs); // array of pairs of DWORD - HRESULT GetLastMessage([out,retval] BSTR* message); - HRESULT GetIdentifierTypes([in] BSTR filename, [in] DWORD startLine, [in] DWORD endLine, [in] DWORD flags); - HRESULT GetIdentifierTypesResult([out, retval] BSTR* types); - HRESULT GetDefinition([in] BSTR filename, [in] DWORD startLine, [in] DWORD startIndex, [in] DWORD endLine, [in] DWORD endIndex); - HRESULT GetDefinitionResult([out] DWORD *startLine, [out] DWORD *startIndex, [out] DWORD *endLine, [out] DWORD *endIndex, [out,retval] BSTR* filename); - HRESULT GetReferences([in] BSTR filename, [in] BSTR tok, [in] DWORD line, [in] DWORD idx, [in] BSTR expr, [in] BOOL moduleOnly); - HRESULT GetReferencesResult([out,retval] BSTR* stringList); - HRESULT ConfigureCommentTasks([in] BSTR tasks); - HRESULT GetCommentTasks([in] BSTR filename, [out,retval] BSTR* tasks); -}; +import "ivdserver.idl"; // library statement [uuid(002a2de9-8bb6-484d-9903-7e4ad4084715), version(1.0), diff --git a/vdc/vdserver.visualdproj b/vdc/vdserver.visualdproj index 1a06dbeb..1b7dd425 100644 --- a/vdc/vdserver.visualdproj +++ b/vdc/vdserver.visualdproj @@ -1,6 +1,6 @@ {2F75431E-B8DB-4231-AAC1-EA68D06A22E6} - + 0 0 0 @@ -15,6 +15,7 @@ 0 0 1 + 1 0 0 0 @@ -31,7 +32,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -44,10 +45,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -85,10 +98,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -107,7 +121,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -122,6 +136,7 @@ 0 0 0 + 1 0 0 0 @@ -138,7 +153,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -151,10 +166,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -192,10 +219,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -214,7 +242,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -229,6 +257,7 @@ 0 0 1 + 1 0 0 1 @@ -245,7 +274,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -258,10 +287,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -270,7 +311,7 @@ m:\s\d\rainers\windows\bin\dmd_msc.exe .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -299,10 +340,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -321,7 +363,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -336,6 +378,7 @@ 0 0 0 + 1 0 0 1 @@ -352,7 +395,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -365,10 +408,22 @@ 0 0 0 - 2.043 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -406,10 +461,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin @@ -428,7 +484,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -443,6 +499,7 @@ 0 0 0 + 1 0 0 0 @@ -459,7 +516,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -472,10 +529,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 1 0 $(CC) -c @@ -513,10 +582,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -535,7 +605,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -550,6 +620,7 @@ 0 0 1 + 1 0 0 1 @@ -566,7 +637,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -579,10 +650,22 @@ 0 0 0 - 2.043 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 1 0 $(CC) -c @@ -620,10 +703,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -642,7 +726,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -657,6 +741,7 @@ 0 0 0 + 1 0 0 0 @@ -673,7 +758,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -686,10 +771,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -727,10 +824,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -749,7 +847,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -764,6 +862,7 @@ 0 0 1 + 1 0 0 1 @@ -780,7 +879,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -793,10 +892,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -834,10 +945,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -856,7 +968,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -871,6 +983,7 @@ 0 0 1 + 1 0 0 0 @@ -887,7 +1000,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -900,10 +1013,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -941,10 +1066,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -963,7 +1089,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -978,6 +1104,7 @@ 0 0 1 + 1 0 0 1 @@ -994,7 +1121,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1007,19 +1134,31 @@ 0 0 0 - 2.043 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 - 1 + 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1048,10 +1187,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1070,7 +1210,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -1085,6 +1225,7 @@ 0 0 0 + 1 1 0 0 @@ -1101,7 +1242,7 @@ 0 0 0 - 1 + 3 0 0 1 @@ -1114,10 +1255,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1155,10 +1308,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1177,7 +1331,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -1192,6 +1346,7 @@ 0 0 1 + 1 0 0 1 @@ -1208,7 +1363,7 @@ 0 0 0 - 0 + 0 0 0 0 @@ -1221,10 +1376,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 2 0 $(CC) -c @@ -1262,10 +1429,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1284,7 +1452,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -1299,6 +1467,7 @@ 0 0 1 + 1 1 0 0 @@ -1315,7 +1484,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1328,10 +1497,22 @@ 0 0 0 - 2 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 0 $(CC) -c @@ -1369,10 +1550,11 @@ 0 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1391,7 +1573,7 @@ *.obj;*.cmd;*.build;*.json;*.dep - + 0 0 0 @@ -1406,6 +1588,7 @@ 0 0 1 + 1 1 0 1 @@ -1422,7 +1605,7 @@ 0 0 0 - 0 + 0 0 0 1 @@ -1435,19 +1618,31 @@ 0 0 0 - 2.043 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 0 - 1 + 0 $(CC) -c 1 0 - m:\s\d\rainers\windows\bin\dmd_msc.exe + .. - ..\bin\$(ConfigurationName) + ..\bin\$(ConfigurationName)\$(PlatformName) $(OutDir)\$(ProjectName) @@ -1476,10 +1671,11 @@ 1 $(VisualDInstallDir)cv2pdb\cv2pdb.exe - 0 0 0 + 0 + $(IntDir)\$(SafeProjectName).mixin ole32.lib oleaut32.lib @@ -1499,16 +1695,17 @@ *.obj;*.cmd;*.build;*.json;*.dep - + - + +rc /fo"$(OutDir)\vdserver.res" "/I$(OutDir)" $(InputPath)" dependencies=""$(OutDir)\vdserver.tlb" ..\version" outfile="$(OutDir)\vdserver.res" path="vdserver.rc" linkoutput="true" tool="Custom" /> - + diff --git a/vdc/vdserverfactory.d b/vdc/vdserverfactory.d index 83f107e9..7d089643 100644 --- a/vdc/vdserverfactory.d +++ b/vdc/vdserverfactory.d @@ -9,7 +9,15 @@ module vdc.vdserverfactory; import vdc.ivdserver; -import vdc.vdserver; +version(MARS) +{ + import vdc.dmdserver.dmdserver; + alias VDServer = DMDServer; +} +else +{ + import vdc.vdserver; +} import sdk.port.base; import sdk.win32.oaidl; @@ -45,8 +53,10 @@ static ~this() class VDServerClassFactory : ComObject, IClassFactory { - debug static GUID iid = uuid("002a2de9-8bb6-484d-9A02-7e4ad4084715"); - else static GUID iid = uuid("002a2de9-8bb6-484d-9902-7e4ad4084715"); + version(MARS) static immutable GUID iid = uuid("002a2de9-8bb6-484d-9906-7e4ad4084715"); + else debug static immutable GUID iid = uuid("002a2de9-8bb6-484d-9A02-7e4ad4084715"); + else debug static immutable GUID iid = uuid("002a2de9-8bb6-484d-9902-7e4ad4084715"); + else static immutable GUID iid = uuid("002a2de9-8bb6-484d-9A02-7e4ad4084715"); override HRESULT QueryInterface(in IID* riid, void** pvObject) { @@ -97,7 +107,7 @@ extern(C) int vdserver_main() // Register the Factory. DWORD regID = 0; - hr = CoRegisterClassObject(VDServerClassFactory.iid, cf, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®ID); + hr = CoRegisterClassObject(*cast(GUID*)&VDServerClassFactory.iid, cf, CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, ®ID); if(FAILED(hr)) { ShowErrorMessage("CoRegisterClassObject()", hr); @@ -116,7 +126,7 @@ extern(C) int vdserver_main() } // All done, so remove class object. - CoRevokeClassObject(regID); + CoRevokeClassObject(regID); return 0; } @@ -137,19 +147,16 @@ void ShowErrorMessage(LPCTSTR header, HRESULT hr) import std.compiler; import std.conv; -static if(version_minor < 64) +version(TEST) { - // dmd 2.064 implicitely adds C main with D main int main(char[][] argv) { - return vdserver_main(); + return 0; //vdserver_main(); } } else { - extern (C) int rt_init(); - extern (C) int rt_term(); - extern (C) bool runModuleUnitTests(); + import core.runtime; enum EXIT_SUCCESS = 0; enum EXIT_FAILURE = -1; @@ -159,9 +166,13 @@ else int result = EXIT_FAILURE; try { - if (rt_init() && runModuleUnitTests()) - result = vdserver_main(); - + if (rt_init()) + { + version(unittest) + result = runModuleUnitTests().passed ? EXIT_SUCCESS : EXIT_FAILURE; + else + result = vdserver_main(); + } if (!rt_term()) result = (result == EXIT_SUCCESS) ? EXIT_FAILURE : result; } diff --git a/vdextensions/Properties/AssemblyInfo15.cs b/vdextensions/Properties/AssemblyInfo15.cs new file mode 100644 index 00000000..668f0b3c --- /dev/null +++ b/vdextensions/Properties/AssemblyInfo15.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("vdext15")] +[assembly: AssemblyDescription("Extension to the Visual D package for Visual Studio 2017 and later")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Rainer Schuetze")] +[assembly: AssemblyProduct("vdext15")] +[assembly: AssemblyCopyright("Copyright 2019 Rainer Schuetze")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/vdextensions/gotodef.cs b/vdextensions/gotodef.cs new file mode 100644 index 00000000..22c51ff1 --- /dev/null +++ b/vdextensions/gotodef.cs @@ -0,0 +1,576 @@ +// adapted from +// https://github.com/Microsoft/VS-PPT/blob/master/src/GoToDef/GoToDefMouseHandler.cs +// +// Productivity Power Tools for Visual Studio +// +// Copyright(c) Microsoft Corporation +// +// All rights reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software +// and associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial +// portions of the Software. +// +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Text.Tagging; +using Microsoft.VisualStudio.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Windows; +using System.Windows.Input; + +namespace vdext15 +{ + public static class PredefinedTextViewRoles14 + { + // not in older versions of PredefinedTextViewRoles + public const string PreviewTextView = "ENHANCED_SCROLLBAR_PREVIEW"; + public const string EmbeddedPeekTextView = "EMBEDDED_PEEK_TEXT_VIEW"; + public const string CodeDefinitionView = "CODEDEFINITION"; + public const string Printable = "PRINTABLE"; + } + + [Export(typeof(IKeyProcessorProvider))] + [TextViewRole(PredefinedTextViewRoles.Document)] + [TextViewRole(PredefinedTextViewRoles14.EmbeddedPeekTextView)] + [ContentType("code")] + [Name("GotoDefVisualD")] + [Order(Before = "VisualStudioKeyboardProcessor")] + internal sealed class GoToDefKeyProcessorProvider : IKeyProcessorProvider + { + //[Import] + //private SVsServiceProvider _serviceProvider; + + public KeyProcessor GetAssociatedProcessor(IWpfTextView view) + { + //IVsExtensionManager manager = _serviceProvider.GetService(typeof(SVsExtensionManager)) as IVsExtensionManager; + //if (manager == null) + // return null; + // + //IInstalledExtension extension; + //manager.TryGetInstalledExtension("GoToDef", out extension); + //if (extension != null) + // return null; + + return view.Properties.GetOrCreateSingletonProperty(typeof(GoToDefKeyProcessor), + () => new GoToDefKeyProcessor(CtrlKeyState.GetStateForView(view))); + } + } + + [Export(typeof(EditorOptionDefinition))] + [Name(ControlClickOpensPeekOption.OptionName)] + public sealed class ControlClickOpensPeekOption : WpfViewOptionDefinition + { + public const string OptionName = "ControlClickOpensPeek"; + public readonly static EditorOptionKey OptionKey = new EditorOptionKey(ControlClickOpensPeekOption.OptionName); + + public override bool Default { get { return true; } } + + public override EditorOptionKey Key { get { return ControlClickOpensPeekOption.OptionKey; } } + } + + /// + /// The state of the control key for a given view, which is kept up-to-date by a combination of the + /// key processor and the mouse processor. + /// + internal sealed class CtrlKeyState + { + internal static CtrlKeyState GetStateForView(ITextView view) + { + return view.Properties.GetOrCreateSingletonProperty(typeof(CtrlKeyState), () => new CtrlKeyState()); + } + + private bool _enabled; + + internal bool Enabled + { + get + { + // Check and see if ctrl is down but we missed it somehow. + bool ctrlDown = (Keyboard.Modifiers & ModifierKeys.Control) != 0; + if (ctrlDown != _enabled) + Enabled = ctrlDown; + + return _enabled; + } + set + { + bool oldVal = _enabled; + _enabled = value; + if (oldVal != _enabled) + { + var temp = CtrlKeyStateChanged; + if (temp != null) + temp(this, new EventArgs()); + } + } + } + + internal event EventHandler CtrlKeyStateChanged; + } + + /// + /// Listen for the control key being pressed or released to update the CtrlKeyStateChanged for a view. + /// + internal sealed class GoToDefKeyProcessor : KeyProcessor + { + private CtrlKeyState _state; + + public GoToDefKeyProcessor(CtrlKeyState state) + { + _state = state; + } + + private void UpdateState(KeyEventArgs args) + { + _state.Enabled = (args.KeyboardDevice.Modifiers & ModifierKeys.Control) != 0; + } + + public override void PreviewKeyDown(KeyEventArgs args) + { + UpdateState(args); + } + + public override void PreviewKeyUp(KeyEventArgs args) + { + UpdateState(args); + } + } + + [Export(typeof(IMouseProcessorProvider))] + [TextViewRole(PredefinedTextViewRoles.Document)] + [TextViewRole(PredefinedTextViewRoles14.EmbeddedPeekTextView)] + [ContentType("code")] + [Name("GotoDefVisualD")] + [Order(Before = "WordSelection")] + internal sealed class GoToDefMouseHandlerProvider : IMouseProcessorProvider + { +#pragma warning disable 649 // Field is never assigned to, and will always have its default value null + + [Import] + private IClassifierAggregatorService _aggregatorFactory; + + [Import] + private ITextStructureNavigatorSelectorService _navigatorService; + + [Import] + private SVsServiceProvider _globalServiceProvider; + + public IMouseProcessor GetAssociatedProcessor(IWpfTextView view) + { + var buffer = view.TextBuffer; + + IOleCommandTarget shellCommandDispatcher = GetShellCommandDispatcher(view); + + if (shellCommandDispatcher == null) + return null; + + //IInstalledExtension extension; + //manager.TryGetInstalledExtension("GoToDef", out extension); + //if (extension != null) + // return null; + + if (!view.TextBuffer.ContentType.IsOfType("d")) + return null; + + return new GoToDefMouseHandler(view, + shellCommandDispatcher, + _aggregatorFactory.GetClassifier(buffer), + _navigatorService.GetTextStructureNavigator(buffer), + CtrlKeyState.GetStateForView(view)); + } + + #region Private helpers + + /// + /// Get the SUIHostCommandDispatcher from the global service provider. + /// + private IOleCommandTarget GetShellCommandDispatcher(ITextView view) + { + return _globalServiceProvider.GetService(typeof(SUIHostCommandDispatcher)) as IOleCommandTarget; + } + + #endregion + } + + /// + /// Handle ctrl+click on valid elements to send GoToDefinition to the shell. Also handle mouse moves + /// (when control is pressed) to highlight references for which GoToDefinition will (likely) be valid. + /// + internal sealed class GoToDefMouseHandler : MouseProcessorBase + { + private IWpfTextView _view; + private CtrlKeyState _state; + private IClassifier _aggregator; + private ITextStructureNavigator _navigator; + private IOleCommandTarget _commandTarget; + + public GoToDefMouseHandler(IWpfTextView view, IOleCommandTarget commandTarget, + IClassifier aggregator, ITextStructureNavigator navigator, CtrlKeyState state) + { + _view = view; + _commandTarget = commandTarget; + _state = state; + _aggregator = aggregator; + _navigator = navigator; + + _state.CtrlKeyStateChanged += (sender, args) => + { + if (_state.Enabled) + this.TryHighlightItemUnderMouse(RelativeToView(Mouse.PrimaryDevice.GetPosition(_view.VisualElement))); + else + this.SetHighlightSpan(null); + }; + + // Some other points to clear the highlight span. + _view.LostAggregateFocus += (sender, args) => this.SetHighlightSpan(null); + _view.VisualElement.MouseLeave += (sender, args) => this.SetHighlightSpan(null); + } + + #region Mouse processor overrides + + // Remember the location of the mouse on left button down, so we only handle left button up + // if the mouse has stayed in a single location. + private Point? _mouseDownAnchorPoint; + + public override void PostprocessMouseLeftButtonDown(MouseButtonEventArgs e) + { + //register the mouse down only if control is being pressed + if (_state.Enabled) + { + _mouseDownAnchorPoint = RelativeToView(e.GetPosition(_view.VisualElement)); + } + } + + public override void PreprocessMouseMove(MouseEventArgs e) + { + if (!_mouseDownAnchorPoint.HasValue && _state.Enabled && e.LeftButton == MouseButtonState.Released) + { + TryHighlightItemUnderMouse(RelativeToView(e.GetPosition(_view.VisualElement))); + } + else if (_mouseDownAnchorPoint.HasValue) + { + // Check and see if this is a drag; if so, clear out the highlight. + var currentMousePosition = RelativeToView(e.GetPosition(_view.VisualElement)); + if (InDragOperation(_mouseDownAnchorPoint.Value, currentMousePosition)) + { + _mouseDownAnchorPoint = null; + this.SetHighlightSpan(null); + } + } + } + + private bool InDragOperation(Point anchorPoint, Point currentPoint) + { + // If the mouse up is more than a drag away from the mouse down, this is a drag + //the drag can happen also on the same row so just one of these condition should make the movement a drag + return Math.Abs(anchorPoint.X - currentPoint.X) >= SystemParameters.MinimumHorizontalDragDistance || + Math.Abs(anchorPoint.Y - currentPoint.Y) >= SystemParameters.MinimumVerticalDragDistance; + } + + public override void PreprocessMouseLeave(MouseEventArgs e) + { + _mouseDownAnchorPoint = null; + } + + public override void PreprocessMouseUp(MouseButtonEventArgs e) + { + if (_mouseDownAnchorPoint.HasValue && _state.Enabled) + { + var currentMousePosition = RelativeToView(e.GetPosition(_view.VisualElement)); + + if (!InDragOperation(_mouseDownAnchorPoint.Value, currentMousePosition)) + { + _state.Enabled = false; + + this.SetHighlightSpan(null); + _view.Selection.Clear(); + this.DispatchGoToDef(); + + e.Handled = true; + } + } + + _mouseDownAnchorPoint = null; + } + + + #endregion + + #region Private helpers + + private Point RelativeToView(Point position) + { + return new Point(position.X + _view.ViewportLeft, position.Y + _view.ViewportTop); + } + + private bool TryHighlightItemUnderMouse(Point position) + { + bool updated = false; + + try + { + var line = _view.TextViewLines.GetTextViewLineContainingYCoordinate(position.Y); + if (line == null) + return false; + + var bufferPosition = line.GetBufferPositionFromXCoordinate(position.X); + + if (!bufferPosition.HasValue) + return false; + + // Quick check - if the mouse is still inside the current underline span, we're already set. + var currentSpan = CurrentUnderlineSpan; + if (currentSpan.HasValue && currentSpan.Value.Contains(bufferPosition.Value)) + { + updated = true; + return true; + } + + + var extent = _navigator.GetExtentOfWord(bufferPosition.Value); + if (!extent.IsSignificant) + return false; + + // For C#, we ignore namespaces after using statements - GoToDef will fail for those. + if (_view.TextBuffer.ContentType.IsOfType("csharp")) + { + string lineText = bufferPosition.Value.GetContainingLine().GetText().Trim(); + if (lineText.StartsWith("using", StringComparison.OrdinalIgnoreCase)) + return false; + } + + // Now, check for valid classification type. C# and C++ (at least) classify the things we are interested + // in as either "identifier" or "user types" (though "identifier" will yield some false positives). VB, unfortunately, + // doesn't classify identifiers. + foreach (var classification in _aggregator.GetClassificationSpans(extent.Span)) + { + var name = classification.ClassificationType.Classification.ToLower(); + if ((name.Contains("identifier") || name.Contains("user types")) && + SetHighlightSpan(classification.Span)) + { + updated = true; + return true; + } + } + + // No update occurred, so return false. + return false; + } + finally + { + if (!updated) + SetHighlightSpan(null); + } + } + + private SnapshotSpan? CurrentUnderlineSpan + { + get + { + var classifier = UnderlineClassifierProvider.GetClassifierForView(_view); + if (classifier != null && classifier.CurrentUnderlineSpan.HasValue) + return classifier.CurrentUnderlineSpan.Value.TranslateTo(_view.TextSnapshot, SpanTrackingMode.EdgeExclusive); + else + return null; + } + } + + private bool SetHighlightSpan(SnapshotSpan? span) + { + var classifier = UnderlineClassifierProvider.GetClassifierForView(_view); + if (classifier != null) + { + if (span.HasValue) + Mouse.OverrideCursor = Cursors.Hand; + else + Mouse.OverrideCursor = null; + + classifier.SetUnderlineSpan(span); + return true; + } + + return false; + } + + private bool DispatchGoToDef() + { + bool showDefinitionsPeek = false; // _view.Options.GetOptionValue(ControlClickOpensPeekOption.OptionKey); + Guid cmdGroup = showDefinitionsPeek ? VSConstants.VsStd12 : VSConstants.GUID_VSStandardCommandSet97; + uint cmdID = showDefinitionsPeek ? (uint)VSConstants.VSStd12CmdID.PeekDefinition : (uint)VSConstants.VSStd97CmdID.GotoDefn; + + // Don't block until we've finished executing the command + int hr = _commandTarget.Exec(ref cmdGroup, + cmdID, + (uint)OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT, + System.IntPtr.Zero, + System.IntPtr.Zero); + + return ErrorHandler.Succeeded(hr); + } + + #endregion + } + + #region Classification type/format exports + + [Export(typeof(EditorFormatDefinition))] + [ClassificationType(ClassificationTypeNames = "UnderlineClassificationVisualD")] + [Name("UnderlineClassificationFormatVisualD")] + [UserVisible(true)] + [Order(After = Priority.High)] + internal sealed class UnderlineFormatDefinition : ClassificationFormatDefinition + { + public UnderlineFormatDefinition() + { + this.DisplayName = "Visual D Goto Definition"; + this.TextDecorations = System.Windows.TextDecorations.Underline; + this.ForegroundColor = System.Windows.Media.Colors.LightSkyBlue; + } + } + + #endregion + + #region Provider definition + + [Export(typeof(IViewTaggerProvider))] + [ContentType("text")] + [TagType(typeof(ClassificationTag))] + internal class UnderlineClassifierProvider : IViewTaggerProvider + { + [Import] + internal IClassificationTypeRegistryService ClassificationRegistry; + + //[Import] + //private SVsServiceProvider _serviceProvider; + + [Export(typeof(ClassificationTypeDefinition))] + [Name("UnderlineClassificationVisualD")] + internal static ClassificationTypeDefinition underlineClassificationType; + + private static IClassificationType s_underlineClassification; + public static UnderlineClassifier GetClassifierForView(ITextView view) + { + if (s_underlineClassification == null) + return null; + + return view.Properties.GetOrCreateSingletonProperty(() => new UnderlineClassifier(view, s_underlineClassification)); + } + + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag + { + if (s_underlineClassification == null) + s_underlineClassification = ClassificationRegistry.GetClassificationType("UnderlineClassificationVisualD"); + + if (textView.TextBuffer != buffer) + return null; + + //IVsExtensionManager manager = _serviceProvider.GetService(typeof(SVsExtensionManager)) as IVsExtensionManager; + //if (manager == null) + // return null; + // + //IInstalledExtension extension; + //manager.TryGetInstalledExtension("GoToDef", out extension); + //if (extension != null) + // return null; + + return GetClassifierForView(textView) as ITagger; + } + } + + #endregion + + internal class UnderlineClassifier : ITagger + { + private IClassificationType _classificationType; + private ITextView _textView; + private SnapshotSpan? _underlineSpan; + + internal UnderlineClassifier(ITextView textView, IClassificationType classificationType) + { + _textView = textView; + _classificationType = classificationType; + _underlineSpan = null; + } + + #region Private helpers + + private void SendEvent(SnapshotSpan span) + { + var temp = this.TagsChanged; + if (temp != null) + temp(this, new SnapshotSpanEventArgs(span)); + } + + #endregion + + #region UnderlineClassification public members + + public SnapshotSpan? CurrentUnderlineSpan { get { return _underlineSpan; } } + + public void SetUnderlineSpan(SnapshotSpan? span) + { + var oldSpan = _underlineSpan; + _underlineSpan = span; + + if (!oldSpan.HasValue && !_underlineSpan.HasValue) + return; + + else if (oldSpan.HasValue && _underlineSpan.HasValue && oldSpan == _underlineSpan) + return; + + if (!_underlineSpan.HasValue) + { + this.SendEvent(oldSpan.Value); + } + else + { + SnapshotSpan updateSpan = _underlineSpan.Value; + if (oldSpan.HasValue) + updateSpan = new SnapshotSpan(updateSpan.Snapshot, + Span.FromBounds(Math.Min(updateSpan.Start, oldSpan.Value.Start), + Math.Max(updateSpan.End, oldSpan.Value.End))); + + this.SendEvent(updateSpan); + } + } + + #endregion + + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if (!_underlineSpan.HasValue || spans.Count == 0) + yield break; + + SnapshotSpan request = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End); + SnapshotSpan underline = _underlineSpan.Value.TranslateTo(request.Snapshot, SpanTrackingMode.EdgeInclusive); + if (underline.IntersectsWith(request)) + { + yield return new TagSpan(underline, new ClassificationTag(_classificationType)); + } + } + + public event EventHandler TagsChanged; + } +} diff --git a/vdextensions/quickinfo.cs b/vdextensions/quickinfo.cs new file mode 100644 index 00000000..96c46eec --- /dev/null +++ b/vdextensions/quickinfo.cs @@ -0,0 +1,308 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2016 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; +using Microsoft.VisualStudio.Utilities; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Language.StandardClassification; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Adornments; + +using System; +using System.ComponentModel.Composition; +using System.Collections.Generic; +using System.Windows.Controls; +using System.Windows; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Documents; +using System.Runtime.InteropServices; // DllImport + +namespace vdext15 +{ + class ClassifiedTextBlock : TextBlock + { + public ClassifiedTextBlock(string text) + : base(new Run(text)) + { + } + + public void setForeground(System.Windows.Media.Brush brush, bool bold) + { + Foreground = brush; + foreach (var inl in Inlines) + { + inl.Foreground = brush; + inl.FontWeight = FontWeight.FromOpenTypeWeight(bold ? 700 : 400); + } + } + + public void enableLink() + { + MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler( + delegate (object sender, System.Windows.Input.MouseButtonEventArgs args) + { + // Text = "clicked!"; + }); + MouseEnter += new System.Windows.Input.MouseEventHandler( + delegate (object sender, System.Windows.Input.MouseEventArgs args) + { + TextDecorations.Add(System.Windows.TextDecorations.Underline); + }); + MouseLeave += new System.Windows.Input.MouseEventHandler( + delegate (object sender, System.Windows.Input.MouseEventArgs args) + { + foreach (var td in System.Windows.TextDecorations.Underline) + TextDecorations.Remove(td); + }); + } + } + + internal sealed class VisualDQuickInfoSource : IAsyncQuickInfoSource + { + private ITextBuffer _textBuffer; + private string _filename; + + VisualDQuickInfoSourceProvider _provider; + + public VisualDQuickInfoSource(VisualDQuickInfoSourceProvider provider, ITextBuffer textBuffer) + { + _provider = provider; + _textBuffer = textBuffer; + _filename = GetFileName(_textBuffer); + } + + [DllImport("visuald.dll")] + public static extern int GetTooltip([MarshalAs(UnmanagedType.BStr)] string fname, int line, int col); + [DllImport("visuald.dll")] + public static extern bool GetTooltipResult(int request, + [MarshalAs(UnmanagedType.BStr)] out string tip, + [MarshalAs(UnmanagedType.BStr)] out string fmt); + + static bool GetQuickInfo(string fname, int line, int col, out string info, out string fmt, + CancellationToken cancellationToken) + { + try + { + int req = GetTooltip(fname, line, col); + if (req != 0) + { + while (!GetTooltipResult(req, out info, out fmt)) + { + if (cancellationToken.IsCancellationRequested) + return false; + Thread.Sleep(100); + } + return !string.IsNullOrEmpty(info); + } + } + catch + { + } + info = ""; + fmt = ""; + return false; + } + + public static string GetFileName(ITextBuffer buffer) + { + Microsoft.VisualStudio.TextManager.Interop.IVsTextBuffer bufferAdapter; + buffer.Properties.TryGetProperty(typeof(Microsoft.VisualStudio.TextManager.Interop.IVsTextBuffer), out bufferAdapter); + if (bufferAdapter != null) + { + var persistFileFormat = bufferAdapter as IPersistFileFormat; + if (persistFileFormat != null) + { + string ppzsFilename = null; + persistFileFormat.GetCurFile(out ppzsFilename, out _); + return ppzsFilename; + } + } + return null; + } + + public System.Windows.Media.Brush GetBrush(ITextView view, string type) + { + if (_provider.typeRegistry != null && _provider.formatMap != null) + { + var ctype = _provider.typeRegistry.GetClassificationType(type); + var cmap = _provider.formatMap.GetClassificationFormatMap(view); + if (ctype != null && cmap != null) + { + var tprop = cmap.GetTextProperties(ctype); + if (tprop != null) + return tprop.ForegroundBrush; + } + } + return null; + } + + public ClassifiedTextBlock createClassifiedTextBlock(ITextView view, string text, string type, bool bold) + { + var tb = new ClassifiedTextBlock(text); + if (String.IsNullOrEmpty(text) || String.IsNullOrEmpty(text.Trim())) + return tb; + + //if (type == "Identifier") + // tb.enableLink(); + + // Foreground cannot be set from the constructor?! + tb.setForeground(GetBrush(view, type), bold); + return tb; + } + + // This is called on a background thread. + public Task GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) + { + var triggerPoint = session.GetTriggerPoint(_textBuffer.CurrentSnapshot); + + if (triggerPoint != null) + { + var line = triggerPoint.Value.GetContainingLine(); + var lineNumber = triggerPoint.Value.GetContainingLine().LineNumber; + var lineSpan = _textBuffer.CurrentSnapshot.CreateTrackingSpan(line.Extent, SpanTrackingMode.EdgeInclusive); + + var column = triggerPoint.Value.Position - line.Start.Position; + string info, fmt; + if (!GetQuickInfo(_filename, lineNumber, column, out info, out fmt, cancellationToken)) + return System.Threading.Tasks.Task.FromResult(null); + + ContainerElement infoElm = null; + Application.Current.Dispatcher.Invoke(delegate + { + // back in the UI thread to allow creation of UIElements + var rows = new List(); + var secs = new List(); + bool bold = false; + Func addClassifiedTextBlock = (string txt, string type) => + { + while (!String.IsNullOrEmpty(txt)) + { + string tag = bold ? "" : ""; + string sec; + bool secbold = bold; + var pos = txt.IndexOf(tag); + if (pos >= 0) + { + bold = !bold; + sec = txt.Substring(0, pos); + txt = txt.Substring(pos + tag.Length); + } + else + { + sec = txt; + txt = null; + } + if (!String.IsNullOrEmpty(sec)) + secs.Add(createClassifiedTextBlock(session.TextView, sec, type, secbold)); + } + return txt; + }; + + Func addTextSection = (string sec, string type) => + { + var nls = sec.Split(new char[1] { '\n' }, StringSplitOptions.None); + for (int n = 0; n < nls.Length - 1; n++) + { + addClassifiedTextBlock(nls[n], type); + rows.Add(new ContainerElement(ContainerElementStyle.Wrapped, secs)); + secs = new List(); + } + addClassifiedTextBlock(nls[nls.Length - 1], type); + return sec; + }; + + string[] ops = fmt.Split(';'); + int prevpos = 0; + string prevtype = null; + foreach (var op in ops) + { + if (prevtype == null) + prevtype = op; + else + { + string[] colname = op.Split(':'); + if (colname.Length == 2) + { + int pos; + if (Int32.TryParse(colname[0], out pos) && pos > prevpos) + { + string sec = info.Substring(prevpos, pos - prevpos); + addTextSection(sec, prevtype); + prevtype = colname[1]; + prevpos = pos; + } + } + } + } + if (prevtype != null && prevpos < info.Length) + { + string sec = info.Substring(prevpos, info.Length - prevpos); + addTextSection(sec, prevtype); + } + else + { + addClassifiedTextBlock(info, PredefinedClassificationTypeNames.SymbolDefinition); + } + if (secs.Count > 0) + rows.Add(new ContainerElement(ContainerElementStyle.Wrapped, secs)); + + // var tb = createClassifiedTextBlock(session.TextView, " Hello again", PredefinedClassificationTypeNames.Keyword); + +/* + var lineNumberElm = new ContainerElement( + ContainerElementStyle.Wrapped, + new ClassifiedTextElement( + new ClassifiedTextRun(PredefinedClassificationTypeNames.Identifier, _filename), + new ClassifiedTextRun(PredefinedClassificationTypeNames.Keyword, " Line number: "), + new ClassifiedTextRun(PredefinedClassificationTypeNames.Identifier, $"{lineNumber + 1}"), + new ClassifiedTextRun(PredefinedClassificationTypeNames.Keyword, " Column: "), + new ClassifiedTextRun(PredefinedClassificationTypeNames.Identifier, $"{column}"))); + + rows.Add(lineNumberElm); +*/ + + infoElm = new ContainerElement(ContainerElementStyle.Stacked, rows); + }); + return System.Threading.Tasks.Task.FromResult(new QuickInfoItem(lineSpan, infoElm)); + } + + return System.Threading.Tasks.Task.FromResult(null); + } + + public void Dispose() + { + // This provider does not perform any cleanup. + } + } + + [Export(typeof(IAsyncQuickInfoSourceProvider))] + [Name("Visual D Quick Info Provider")] + [ContentType("d")] + [Order] + internal sealed class VisualDQuickInfoSourceProvider : IAsyncQuickInfoSourceProvider + { + // these imports don't work in VisualDQuickInfoSource, maybe because created in another thread? + [Import] + public IClassificationFormatMapService formatMap = null; + [Import] + public IClassificationTypeRegistryService typeRegistry = null; + + public IAsyncQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + //if (!textBuffer.ContentType.IsOfType("d")) + // return null; + + // This ensures only one instance per textbuffer is created + return textBuffer.Properties.GetOrCreateSingletonProperty(() + => new VisualDQuickInfoSource(this, textBuffer)); + } + } +} diff --git a/vdextensions/vdext15.cs b/vdextensions/vdext15.cs new file mode 100644 index 00000000..db96b2d8 --- /dev/null +++ b/vdextensions/vdext15.cs @@ -0,0 +1,38 @@ +// This file is part of Visual D +// +// Visual D integrates the D programming language into Visual Studio +// Copyright (c) 2016 by Rainer Schuetze, All Rights Reserved +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +using System; +using System.Runtime.InteropServices; // DllImport + +namespace vdext15 +{ + public class IID + { + public const string IVisualDHelper15 = "002a2de9-8bb6-484d-9915-7e4ad4084715"; + public const string VisualDHelper15 = "002a2de9-8bb6-484d-AA15-7e4ad4084715"; + } + + [ComVisible(true), Guid(IID.IVisualDHelper15)] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IVisualDHelper15 + { + } + + [ComVisible(true), Guid(IID.VisualDHelper15)] + [ClassInterface(ClassInterfaceType.None)] + public partial class VisualDHelper15 : IVisualDHelper15 + { + public VisualDHelper15() + { + } + + public void Dispose() + { + } + } +} diff --git a/vdextensions/vdext15.csproj b/vdextensions/vdext15.csproj new file mode 100644 index 00000000..6996da58 --- /dev/null +++ b/vdextensions/vdext15.csproj @@ -0,0 +1,149 @@ + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3} + Library + vdext15 + vdext15 + assembly + c:\Windows\Microsoft.NET\assembly\GAC_MSIL + ..\bin\$(Configuration)\$(MSBuildProjectName)\obj\ + v4.6 + + + + True + full + False + ..\bin\Debug\vdext15\any\ + DEBUG; + prompt + 4 + False + false + + + full + True + ..\bin\Release\vdext15\any\ + prompt + 4 + False + true + false + + + true + ..\bin\Debug\vdext15\ + DEBUG; + full + x86 + prompt + MinimumRecommendedRules.ruleset + false + + + true + ..\bin\Release\vdext15\ + true + full + x86 + prompt + MinimumRecommendedRules.ruleset + false + + + + False + + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.CoreUtility\vs15\Microsoft.VisualStudio.CoreUtility.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Editor\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Editor.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Shell.15.0\vs15\Microsoft.VisualStudio.Shell.15.0.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Shell.Framework\vs15\Microsoft.VisualStudio.Shell.Framework.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Text.Data\vs15\Microsoft.VisualStudio.Text.Data.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Text.Logic\vs15\Microsoft.VisualStudio.Text.Logic.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Text.UI\vs15\Microsoft.VisualStudio.Text.UI.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Text.UI.Wpf\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Text.UI.Wpf.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Utilities\vs15\Microsoft.VisualStudio.Utilities.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Language\vs15\Microsoft.VisualStudio.Language.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Language.Intellisense\vs15\Microsoft.VisualStudio.Language.Intellisense.dll + + + False + $(GAC_HintPath)\Microsoft.VisualStudio.Language.StandardClassification\vs15\Microsoft.VisualStudio.Language.StandardClassification.dll + + + + + + + + + + + + + + + + C:\Windows\assembly\GAC\Microsoft.VisualStudio.TextManager.Interop\7.1.40304.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.TextManager.Interop.dll + + + C:\Windows\assembly\GAC\Microsoft.VisualStudio.OLE.Interop\7.1.40304.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.OLE.Interop.dll + + + $(GAC_HintPath)\Microsoft.VisualStudio.Shell.Interop\vs15\Microsoft.VisualStudio.Shell.Interop.dll + + + $(GAC_HintPath)\Microsoft.VisualStudio.Shell.Interop\vs15\Microsoft.VisualStudio.Shell.Interop.dll + + + $(GAC_HintPath)\Microsoft.VisualStudio.Shell.Interop.8.0\vs15\Microsoft.VisualStudio.Shell.Interop.8.0.dll + + + + + + + + + + + \ No newline at end of file diff --git a/vdextensions/vdextensions.sln b/vdextensions/vdextensions.sln index 1fae8c70..3dcc769a 100644 --- a/vdextensions/vdextensions.sln +++ b/vdextensions/vdextensions.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DParser2", "..\vdc\abothe\P EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualDWizard", "..\vdwizard\VisualDWizard.csproj", "{32171DBC-DB3B-401A-B3F7-06356D6167EE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "vdext15", "vdext15.csproj", "{64534E86-A08A-4F9A-8DB1-A5C280773BA3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -75,8 +77,8 @@ Global {45508B90-440B-46DD-82CC-178196D9794E}.Debug|Any CPU.Build.0 = Debug|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug|x86.ActiveCfg = Debug|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug|x86.Build.0 = Debug|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Debug|x86.ActiveCfg = Debug|x86 + {45508B90-440B-46DD-82CC-178196D9794E}.Debug|x86.Build.0 = Debug|x86 {45508B90-440B-46DD-82CC-178196D9794E}.Debug-Linux|Any CPU.ActiveCfg = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-Linux|Any CPU.Build.0 = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-Linux|Mixed Platforms.ActiveCfg = Debug-v14|Any CPU @@ -86,26 +88,26 @@ Global {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|Any CPU.Build.0 = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|Mixed Platforms.ActiveCfg = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|Mixed Platforms.Build.0 = Debug-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|x86.ActiveCfg = Debug-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|x86.Build.0 = Debug-v14|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|x86.ActiveCfg = Debug-v14|x86 + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v14|x86.Build.0 = Debug-v14|x86 {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.ActiveCfg = Debug-v16|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Any CPU.Build.0 = Debug-v16|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Mixed Platforms.ActiveCfg = Debug-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|Mixed Platforms.Build.0 = Debug-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|x86.ActiveCfg = Debug-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|x86.Build.0 = Debug-v14|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|x86.ActiveCfg = Debug-v16|x86 + {45508B90-440B-46DD-82CC-178196D9794E}.Debug-v16|x86.Build.0 = Debug-v16|x86 {45508B90-440B-46DD-82CC-178196D9794E}.Release|Any CPU.ActiveCfg = Release|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release|Any CPU.Build.0 = Release|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release|x86.ActiveCfg = Release|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release|x86.Build.0 = Release|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Release|x86.ActiveCfg = Release|x86 + {45508B90-440B-46DD-82CC-178196D9794E}.Release|x86.Build.0 = Release|x86 {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Any CPU.ActiveCfg = Release-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Any CPU.Build.0 = Release-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Mixed Platforms.ActiveCfg = Release-v14|Any CPU {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|Mixed Platforms.Build.0 = Release-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|x86.ActiveCfg = Release-v14|Any CPU - {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|x86.Build.0 = Release-v14|Any CPU + {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|x86.ActiveCfg = Release-v14|x86 + {45508B90-440B-46DD-82CC-178196D9794E}.Release-v14|x86.Build.0 = Release-v14|x86 {7B4FB722-905A-4851-8399-1E0F3361CCD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B4FB722-905A-4851-8399-1E0F3361CCD8}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B4FB722-905A-4851-8399-1E0F3361CCD8}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 @@ -214,6 +216,42 @@ Global {32171DBC-DB3B-401A-B3F7-06356D6167EE}.Release-v14|Mixed Platforms.Build.0 = Release|Any CPU {32171DBC-DB3B-401A-B3F7-06356D6167EE}.Release-v14|x86.ActiveCfg = Release|Any CPU {32171DBC-DB3B-401A-B3F7-06356D6167EE}.Release-v14|x86.Build.0 = Release|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|x86.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug|x86.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|Any CPU.ActiveCfg = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|Any CPU.Build.0 = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|Mixed Platforms.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|Mixed Platforms.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|x86.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-Linux|x86.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|Any CPU.ActiveCfg = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|Any CPU.Build.0 = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|Mixed Platforms.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|Mixed Platforms.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|x86.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v14|x86.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|Any CPU.ActiveCfg = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|Any CPU.Build.0 = Debug|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|Mixed Platforms.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|Mixed Platforms.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|x86.ActiveCfg = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Debug-v16|x86.Build.0 = Debug|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|Any CPU.Build.0 = Release|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|Mixed Platforms.Build.0 = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|x86.ActiveCfg = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release|x86.Build.0 = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|Any CPU.ActiveCfg = Release|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|Any CPU.Build.0 = Release|Any CPU + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|Mixed Platforms.ActiveCfg = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|Mixed Platforms.Build.0 = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|x86.ActiveCfg = Release|x86 + {64534E86-A08A-4F9A-8DB1-A5C280773BA3}.Release-v14|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visuald/Resources/pkgcmd.vsct b/visuald/Resources/pkgcmd.vsct index f1b47c22..34ba99aa 100644 --- a/visuald/Resources/pkgcmd.vsct +++ b/visuald/Resources/pkgcmd.vsct @@ -291,6 +291,14 @@ DUB Upgrade +