Files
Sourcetrail/ide_plugins/vs/vs2015/SourcetrailPlugin/SourcetrailPlugin/Utility/ProjectUtility.cs
T
malte_langkabel 7010b9a6fb logic: update Visual Studio plugin to support Visual Studio 2017
* changed description text of Visual Studio plugin
* changed plugin install targets to include VS 2017
* add license file with MIT license
* updated vsix for deployment

* implement wrapper for all used classes of VCProjectEngine.dll since you cannot just use the oldest version of this
  assembly (see https://stackoverflow.com/questions/44288050/typecast-fails-when-visual-studio-extension-uses-reference-to-older-assembly).
* improved serialization and deserialization of compile commands and compilation databases.
* updated used JSON package
* rename CommandObject to CompileCommand
* changed implementation to keep non-existent file paths in cdb
* made methods of SolutionParser non-static
* replace spaces with tabs

* added IntegrationTests project
* configured tests to simulate a new instance of VisualStudio
* added cinder as test project for integration tests
* remove all absolute paths from expected output of integration tests

fortune cookie message = A stranger will bring great meaning to your life.
2017-06-02 14:48:29 +02:00

357 lines
10 KiB
C#

using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using VCProjectEngineWrapper;
namespace CoatiSoftware.SourcetrailPlugin.Utility
{
public class ProjectUtility
{
public static List<string> GetPropertyNamesAndValues(Properties properties)
{
List<string> ret = new List<string>();
foreach (Property propertiy in properties)
{
string name = propertiy.Name;
string value = "";
try
{
value = propertiy.Value.ToString();
}
catch (Exception e)
{
value = "Error occurred while converting value to string.";
}
ret.Add(name + ": " + value);
}
return ret;
}
public static bool HasProperty(Properties properties, string propertyName)
{
if (properties != null)
{
foreach (Property item in properties)
{
if (item != null && item.Name == propertyName)
{
return true;
}
}
}
return false;
}
public static bool ContainsCFiles(Project project)
{
List<ProjectItem> projectItems = GetProjectItems(project);
try
{
foreach (EnvDTE.ProjectItem item in projectItems)
{
if (item.FileCodeModel != null && item.FileCodeModel.Language == CodeModelLanguageConstants.vsCMLanguageVC)
{
string extension = item.Properties.Item("Extension").Value.ToString();
if (extension == ".c")
{
return true;
}
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
return false;
}
static public List<ProjectItem> GetProjectItems(Project project)
{
List<ProjectItem> items = new List<ProjectItem>();
IEnumerator itemEnumerator = project.ProjectItems.GetEnumerator();
while (itemEnumerator.MoveNext())
{
ProjectItem currentItem = (ProjectItem)itemEnumerator.Current;
items.Add(GetProjectSubItemsRecursive(currentItem, ref items));
}
return items;
}
static private ProjectItem GetProjectSubItemsRecursive(ProjectItem item, ref List<ProjectItem> projectItems)
{
if (item.ProjectItems == null)
{
return item;
}
IEnumerator items = item.ProjectItems.GetEnumerator();
while (items.MoveNext())
{
ProjectItem currentItem = (ProjectItem)items.Current;
projectItems.Add(GetProjectSubItemsRecursive(currentItem, ref projectItems));
}
return item;
}
static public List<string> GetProjectIncludeDirectories(IVCProjectWrapper project, string configurationName, string platformName, IPathResolver pathResolver)
{
// get additional include directories
// source: http://www.mztools.com/articles/2014/MZ2014005.aspx
Logging.Logging.LogInfo("Attempting to retreive Include Directories for project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.GetName()) + "'");
List<string> includeDirectories = new List<string>();
IVCConfigurationWrapper vcProjectConfig = project.getConfiguration(configurationName, platformName);
if (vcProjectConfig != null && vcProjectConfig.isValid())
{
IVCCLCompilerToolWrapper compilerTool = vcProjectConfig.GetCompilerTool();
if (compilerTool != null && compilerTool.isValid())
{
foreach (string directory in compilerTool.GetAdditionalIncludeDirectories())
{
if (directory.Length <= 0)
{
continue;
}
string resolvedDirectories = pathResolver.ResolveVsMacroInPath(directory, vcProjectConfig);
foreach (string resolvedDirectory in resolvedDirectories.Split(';'))
{
string dir = pathResolver.GetAsAbsoluteCanonicalPath(resolvedDirectory, project);
includeDirectories.Add(dir);
}
}
}
try
{
IVCPlatformWrapper platform = vcProjectConfig.GetPlatform();
if (platform != null && platform.isValid())
{
foreach (string directory in platform.GetIncludeDirectories())
{
string resolvedDirectories = pathResolver.ResolveVsMacroInPath(directory, vcProjectConfig);
foreach (string resolvedDirectory in resolvedDirectories.Split(';'))
{
includeDirectories.Add(resolvedDirectory);
}
}
}
}
catch (Exception e)
{
Logging.Logging.LogError("Failed to retreive platform include directories: " + e.Message);
return new List<string>();
}
}
else
{
Logging.Logging.LogWarning("Could not retreive Project Configuration. No include directories could be retreived.");
return new List<string>();
}
includeDirectories = includeDirectories.Distinct().ToList();
Logging.Logging.LogInfo("Attempting to clean up.");
for (int i = 0; i < includeDirectories.Count; i++)
{
string path = includeDirectories.ElementAt(i).Replace("\\", "/"); // backslashes would cause some string-escaping hassles...
if (path.Length == 0)
{
includeDirectories.RemoveAt(i);
i--;
}
else
{
includeDirectories[i] = path;
}
}
Logging.Logging.LogInfo("Found " + includeDirectories.Count.ToString() + " distinct include directories.");
return includeDirectories;
}
static public List<string> GetProjectPreprocessorDefinitions(IVCProjectWrapper project, string configurationName, string platformName)
{
Logging.Logging.LogInfo("Attempting to retreive Preprocessor Definitions for project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.GetName()) + "'");
List<string> preprocessorDefinitions = new List<string>();
IVCCLCompilerToolWrapper compilerTool = null;
IVCConfigurationWrapper vcProjectConfig = project.getConfiguration(configurationName, platformName);
if (vcProjectConfig != null && vcProjectConfig.isValid())
{
compilerTool = vcProjectConfig.GetCompilerTool();
}
if (compilerTool != null && compilerTool.isValid())
{
foreach (string preprocessorDefinition in compilerTool.GetPreprocessorDefinitions())
{
preprocessorDefinitions.Add(preprocessorDefinition.Replace("\\\"", "\""));
}
}
else
{
Logging.Logging.LogWarning("Could not retreive compiler tool. No preprocessor definitions could be retreived.");
return new List<string>();
}
preprocessorDefinitions = preprocessorDefinitions.Distinct().ToList();
Logging.Logging.LogInfo("Found " + preprocessorDefinitions.Count.ToString() + " distinct preprocessor definitions.");
return preprocessorDefinitions;
}
// AFAIK there is no way to programmatically get the c++ standard version supported by any given VS version
// instead I'm refearing to the VS docu for that information
// https://msdn.microsoft.com/en-us/library/hh567368.aspx
static public string GetCppStandardForProject(IVCProjectWrapper project, string configurationName, string platformName)
{
string result = "";
string toolset = project.GetWrappedVersion();
string justNumbers = new String(toolset.Where(Char.IsDigit).ToArray());
int versionNumber = int.Parse(justNumbers);
if (versionNumber < 120) // version 11 (2012)
{
result = "-std=c++11";
}
else if (versionNumber < 130) // version 12 (2013)
{
result = "-std=c++14";
}
else if (versionNumber < 150) // version 14 (2015)
{
result = "-std=c++14";
}
else if (versionNumber < 160) // version 15 (2017)
{
result = "-std=c++14";
}
return result;
}
// returns a valid Guid if the project was reloaded or an empty Guid if the project did not need to be reloaded
static public Guid ReloadProject(Project project)
{
Logging.Logging.LogInfo("Attempting to reload project");
try
{
if (project != null && project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled)
{
DTE dte = project.DTE;
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(IVsSolution)) as IVsSolution;
IVsHierarchy hierarchy;
string solutionDirectory = "";
string solutionFile = "";
string userOptions = "";
vsSolution.GetSolutionInfo(out solutionDirectory, out solutionFile, out userOptions);
vsSolution.GetProjectOfUniqueName(solutionDirectory + project.UniqueName, out hierarchy);
if (hierarchy != null)
{
Guid projectGuid;
hierarchy.GetGuidProperty(
VSConstants.VSITEMID_ROOT,
(int)__VSHPROPID.VSHPROPID_ProjectIDGuid,
out projectGuid);
if (projectGuid != null)
{
Logging.Logging.LogInfo("Project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "' with GUID {" + projectGuid.ToString() + "} loaded.");
(vsSolution as IVsSolution4).ReloadProject(projectGuid);
return projectGuid;
}
else
{
Logging.Logging.LogError("Failed to load project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "'");
}
}
else
{
Logging.Logging.LogError("Failed to retreive IVsHierarchy. Can't load project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "'");
}
}
else
{
if (project == null)
{
Logging.Logging.LogWarning("Project is null");
}
else
{
Logging.Logging.LogInfo("Project '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(project.Name) + "' is already loaded");
}
}
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
return Guid.Empty;
}
return Guid.Empty;
}
static public void UnloadProject(Guid guid, DTE dte)
{
Logging.Logging.LogInfo("Attempting to unload project with GUID {" + guid.ToString() + "}");
if (dte == null)
{
return;
}
try
{
ServiceProvider sp = new ServiceProvider(dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
IVsSolution vsSolution = sp.GetService(typeof(SVsSolution)) as IVsSolution;
(vsSolution as IVsSolution4).UnloadProject(guid, (uint)_VSProjectUnloadStatus.UNLOADSTATUS_UnloadedByUser);
Logging.Logging.LogInfo("Done unloading project with GUID {" + guid.ToString() + "}");
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
}
}
}