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