From 27d7b19e7f43a7152f33fe4e4fec53b3551efed0 Mon Sep 17 00:00:00 2001 From: triton Date: Thu, 21 Mar 2013 16:06:03 +0000 Subject: [PATCH] Replace the existing VS lookup code with the one from Clang driver (it works better). --- src/Parser/Parser.cpp | 84 +++++++--- src/Parser/VSLookup.cpp | 343 ++++++++++++++++++++++++++++++---------- 2 files changed, 322 insertions(+), 105 deletions(-) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 8209a3c6..1d06aa0f 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -63,9 +63,7 @@ static std::string GetClangBuiltinIncludeDir() //-----------------------------------// #ifdef _MSC_VER -bool GetVisualStudioEnv(const char* env, - std::vector& pathes, - int probeFrom = 0, int probeTo = 0); +std::vector GetWindowsSystemIncludeDirs(); #endif void Parser::Setup(ParserOptions^ Opts) @@ -122,27 +120,13 @@ void Parser::Setup(ParserOptions^ Opts) C->getHeaderSearchOpts().AddPath(GetClangBuiltinIncludeDir(), clang::frontend::System, false, false); - -#if defined(WithClangWindowsSystemIncludeDirsPatch) +#ifdef _MSC_VER std::vector SystemDirs = clang::driver::GetWindowsSystemIncludeDirs(); clang::HeaderSearchOptions& HSOpts = C->getHeaderSearchOpts(); for(size_t i = 0; i < SystemDirs.size(); ++i) { - HSOpts.AddPath(SystemDirs[i], frontend::System, false, false, true); - } -#endif - -#ifdef _MSC_VER - std::vector SystemDirs; - if(GetVisualStudioEnv("INCLUDE", SystemDirs, Opts->ToolSetToUse, Opts->ToolSetToUse)) - { - clang::HeaderSearchOptions& HSOpts = C->getHeaderSearchOpts(); - - for(size_t i = 0; i < SystemDirs.size(); ++i) - { - HSOpts.AddPath(SystemDirs[i], frontend::System, false, false); - } + HSOpts.AddPath(SystemDirs[i], frontend::System, false, false); } #endif @@ -323,6 +307,12 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record, bool IsDependen using namespace clang; using namespace clix; + //if (Record->isAnonymousStructOrUnion()) + //{ + // //assert(0); + // return nullptr; + //} + if (Record->hasFlexibleArrayMember()) { assert(0); @@ -600,6 +590,12 @@ Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND) // We might be able to translate these to C# nested types. continue; } + case Decl::ClassTemplateSpecialization: + { + // FIXME: Ignore ClassTemplateSpecialization namespaces... + // We might be able to translate these to C# nested types. + continue; + } default: { StringRef Kind = Ctx->getDeclKindName(); @@ -656,6 +652,37 @@ static Cxxi::PrimitiveType WalkBuiltinType(const clang::BuiltinType* Builtin) //-----------------------------------// +clang::TypeLoc ResolveTypeLoc(clang::TypeLoc TL, clang::TypeLoc::TypeLocClass Class) +{ + using namespace clang; + + auto TypeLocClass = TL.getTypeLocClass(); + + if (TypeLocClass == Class) + { + return TL; + } + if (TypeLocClass == TypeLoc::Qualified) + { + auto UTL = TL.getUnqualifiedLoc(); + TL = UTL; + } + else if (TypeLocClass == TypeLoc::Elaborated) + { + auto ETL = TL.getAs(); + auto ITL = ETL.getNextTypeLoc(); + TL = ITL; + } + else if (TypeLocClass == TypeLoc::Paren) + { + auto PTL = TL.getAs(); + TL = PTL.getNextTypeLoc(); + } + + assert(TL.getTypeLocClass() == Class); + return TL; +} + Cxxi::Type^ Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL, bool DesugarType) { @@ -884,11 +911,19 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL, case Type::TemplateTypeParm: { auto TP = Type->getAs(); + auto TPT = gcnew Cxxi::TemplateParameterType(); - //TPT->Parameter = WalkDeclaration(TP->getDecl()); + + if (auto Ident = TP->getIdentifier()) + TPT->Parameter.Name = marshalString(Ident->getName()); return TPT; } + case Type::SubstTemplateTypeParm: + { + auto TPT = gcnew Cxxi::TemplateParameterType(); + return TPT; + } case Type::InjectedClassName: { auto MYIN = Type->getAs(); @@ -1053,6 +1088,7 @@ void Parser::WalkFunction(clang::FunctionDecl* FD, Cxxi::Function^ F, if (auto TSI = FD->getTypeSourceInfo()) { TypeLoc TL = TSI->getTypeLoc(); + //RTL = ResolveTypeLoc(TL).getAs.getResultLoc(); RTL = TL.getAs().getResultLoc(); } F->ReturnType = WalkType(FD->getResultType(), &RTL); @@ -1498,6 +1534,14 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, clang::TypeLoc* TL, default: { Debug("Unhandled declaration kind: %s\n", D->getDeclKindName()); + + auto &SM = C->getSourceManager(); + auto Loc = D->getLocation(); + auto FileName = SM.getFilename(Loc); + auto Offset = SM.getFileOffset(Loc); + auto LineNo = SM.getLineNumber(SM.getFileID(Loc), Offset); + Debug(" %s (line %u)\n", FileName, LineNo); + break; } }; diff --git a/src/Parser/VSLookup.cpp b/src/Parser/VSLookup.cpp index 6d344ff6..2020b175 100644 --- a/src/Parser/VSLookup.cpp +++ b/src/Parser/VSLookup.cpp @@ -9,102 +9,275 @@ #include #include -#include - -static std::string exec(const char* cmd) -{ - FILE* pipe = _popen(cmd, "r"); - if (!pipe) return "ERROR"; - char buffer[128]; - std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - _pclose(pipe); - return result; -} -#pragma comment(lib, "shlwapi.lib") //_popen, _pclose -#include - -// -// Returns true if got settings, false if not. -// -bool GetVisualStudioEnv( - const char* envVar, // [in] "INCLUDE" / "LIBPATH" - std::vector& vecPathes, - int iProbeFrom = 0, int iProbeTo = 0 // 2005 - 8, 2008 - 9, 2010 - 10 -) -{ - std::string s; - - if( iProbeFrom == 0 && iProbeTo == 0 ) - { - // Environment variable specifies which VS to use. - if( getenv("VSENV") != NULL ) - { - int iVer = atoi( getenv("VSENV") ); - - if( iVer == 0 ) - return false; - - return GetVisualStudioEnv(envVar, vecPathes, iVer, iVer ); - } - - iProbeFrom = 20; - iProbeTo = 9; +// Include the necessary headers to interface with the Windows registry and +// environment. +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#define NOMINMAX +#include + +// Has all the registry lookup related code +struct MSVCRegLookup { + HKEY hRootKey; + HKEY hKey; + const char* subKey; + DWORD valueType; + + MSVCRegLookup() + : hRootKey(NULL), hKey(NULL), subKey(NULL), valueType(0) { } + + bool InitializeRootKey(const char *keyPath) { + if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { + hRootKey = HKEY_CLASSES_ROOT; + subKey = keyPath + 18; + } else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { + hRootKey = HKEY_USERS; + subKey = keyPath + 11; + } else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { + hRootKey = HKEY_LOCAL_MACHINE; + subKey = keyPath + 19; + } else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { + hRootKey = HKEY_CURRENT_USER; + subKey = keyPath + 18; + } else { + return false; } + return true; + } - for( int iProbeVer = iProbeFrom; iProbeVer >= iProbeTo; iProbeVer-- ) - { - char envvar[64]; - sprintf(envvar, "VS%d0COMNTOOLS", iProbeVer); - - // Not defined - if( getenv(envvar) == NULL ) - continue; - - std::string cmd = getenv(envvar); - cmd += "\\..\\..\\vc\\vcvarsall.bat"; - - if( !PathFileExistsA( cmd.c_str() ) ) - continue; - - //printf("Located: %s", envvar); - - cmd = "cmd /C \"" + cmd + "\" ^>nul ^& set"; - s = exec(cmd.c_str()); - break; + bool FindSimpleKeyValue(const char *valueName, char *value, DWORD valueSize) { + bool Ret = false; + long Res = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey); + if (Res == ERROR_SUCCESS) { + Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (Res == ERROR_SUCCESS) + Ret = true; + RegCloseKey(hKey); } + return Ret; + } + + bool FindBestVersionKeyValue(const char* versionIndex, + const char *valueName, char *value, DWORD valueSize) { + bool Ret = false; + const char *keyEnd = versionIndex - 1; + const char *nextKey = versionIndex; - if( s.length() == 0 ) - return false; + // Find end of previous key. + while ((keyEnd > subKey) && (*keyEnd != '\\')) + keyEnd--; - char* envline; + // Find end of key containing $VERSION. + while (*nextKey && (*nextKey != '\\')) + nextKey++; + + size_t partialKeyLength = keyEnd - subKey; + char partialKey[256]; + if (partialKeyLength > sizeof(partialKey)) + partialKeyLength = sizeof(partialKey); + strncpy(partialKey, subKey, partialKeyLength); + partialKey[partialKeyLength] = '\0'; + + HKEY hTopKey = NULL; + long Res = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey); - vecPathes.clear(); - - for (envline = strtok( &s[0], "\n" ); envline; envline = strtok( NULL, "\n" )) - { - char* varend = strchr( envline, '='); - if( !varend ) - continue; - - *varend = 0; - - if( strcmp(envline,envVar) == 0 ) - { - char* val; - for (val = strtok( varend + 1, ";" ); val; val = strtok( NULL, ";" )) - { - vecPathes.push_back(val); - } + if (Res != ERROR_SUCCESS) + return false; + + char keyName[256]; + int bestIndex = -1; + char bestName[256]; + bestName[0] = '\0'; + double bestValue = 0.0; + + // Find the highest versioned key. + DWORD index, size = sizeof(keyName) - 1; + for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + + double versionValue = strtod(numBuf, NULL); + if (versionValue > bestValue) { + // Better values are only better if the desired key exists for them. + std::string candidate = std::string(keyName) + nextKey; + Res = RegOpenKeyExA(hTopKey, candidate.c_str(), 0, KEY_READ, &hKey); + if (Res == ERROR_SUCCESS) { + Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (Res == ERROR_SUCCESS) { + bestIndex = (int)index; + bestValue = versionValue; + strcpy(bestName, keyName); + } + RegCloseKey(hKey); } - *varend = '='; + } } + // If we found the highest versioned key, open the key and get the value. + if (bestIndex != -1) { + // Append rest of key. + strncat(bestName, nextKey, sizeof(bestName) - 1); + bestName[sizeof(bestName) - 1] = '\0'; + // Open the chosen key path remainder. + Res = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey); + if (Res == ERROR_SUCCESS) { + Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (Res == ERROR_SUCCESS) + Ret = true; + RegCloseKey(hKey); + } + } + RegCloseKey(hTopKey); + return Ret; + } +}; + +/// \brief Read registry string. +/// This also supports a means to look for high-versioned keys by use +/// of a $VERSION placeholder in the key path. +/// $VERSION in the key path is a placeholder for the version number, +/// causing the highest value path to be searched for and used. +/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". +/// There can be additional characters in the component. Only the numeric +/// characters are compared. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + char *value, size_t maxLength) { + MSVCRegLookup Reg; + if (!Reg.InitializeRootKey(keyPath)) + return false; + + const char* versionIndex = strstr(Reg.subKey, "$VERSION"); + // If we have a $VERSION placeholder, do the highest-version search. + if (versionIndex) + return Reg.FindBestVersionKeyValue(versionIndex, valueName, + value, maxLength-1); + else + return Reg.FindSimpleKeyValue(valueName, value, maxLength-1); +} + +/// \brief Get Windows SDK installation directory. +static bool getWindowsSDKDir(std::string &path) { + char windowsSDKInstallDir[256]; + // Try the Windows registry. + bool hasSDKDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", + windowsSDKInstallDir, + sizeof(windowsSDKInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasSDKDir && windowsSDKInstallDir[0]) { + path = windowsSDKInstallDir; return true; + } + return false; +} + + // Get Visual Studio installation directory. +static bool getVisualStudioDir(std::string &path) { + // First check the environment variables that vsvars32.bat sets. + const char* vcinstalldir = getenv("VCINSTALLDIR"); + if (vcinstalldir) { + char *p = const_cast(strstr(vcinstalldir, "\\VC")); + if (p) + *p = '\0'; + path = vcinstalldir; + return true; + } + + char vsIDEInstallDir[256]; + char vsExpressIDEInstallDir[256]; + // Then try the windows registry. + bool hasVCDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", + "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); + bool hasVCExpressDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", + "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasVCDir && vsIDEInstallDir[0]) { + char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsIDEInstallDir; + return true; + } + + if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { + char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsExpressIDEInstallDir; + return true; + } + + // Try the environment. + const char *vs100comntools = getenv("VS100COMNTOOLS"); + const char *vs90comntools = getenv("VS90COMNTOOLS"); + const char *vs80comntools = getenv("VS80COMNTOOLS"); + const char *vscomntools = NULL; + + // Try to find the version that we were compiled with + if(false) {} + #if (_MSC_VER >= 1600) // VC100 + else if(vs100comntools) { + vscomntools = vs100comntools; + } + #elif (_MSC_VER == 1500) // VC80 + else if(vs90comntools) { + vscomntools = vs90comntools; + } + #elif (_MSC_VER == 1400) // VC80 + else if(vs80comntools) { + vscomntools = vs80comntools; + } + #endif + // Otherwise find any version we can + else if (vs100comntools) + vscomntools = vs100comntools; + else if (vs90comntools) + vscomntools = vs90comntools; + else if (vs80comntools) + vscomntools = vs80comntools; + + if (vscomntools && *vscomntools) { + const char *p = strstr(vscomntools, "\\Common7\\Tools"); + path = p ? std::string(vscomntools, p) : vscomntools; + return true; + } + return false; +} + +std::vector GetWindowsSystemIncludeDirs() { + std::vector Paths; + + std::string VSDir; + std::string WindowsSDKDir; + + // When built with access to the proper Windows APIs, try to actually find + // the correct include paths first. + if (getVisualStudioDir(VSDir)) { + Paths.push_back(VSDir + "\\VC\\include"); + if (getWindowsSDKDir(WindowsSDKDir)) + Paths.push_back(WindowsSDKDir + "\\include"); + else + Paths.push_back(VSDir + "\\VC\\PlatformSDK\\Include"); + } + + return Paths; } #endif \ No newline at end of file