Skip to content

Instantly share code, notes, and snippets.

@OmerRaviv
Created September 6, 2015 08:47
Show Gist options
  • Save OmerRaviv/fc3ce6fbd5b6af501f01 to your computer and use it in GitHub Desktop.
Save OmerRaviv/fc3ce6fbd5b6af501f01 to your computer and use it in GitHub Desktop.
[Obsolete("Not supported on VS2015, Use INavigationEngine implementation instead")]
internal static class LegacyGoToDefinitionEngine
{
/// <summary>
/// If Visual Studio's recognizes the given member and knows where its source code is, goes to the source code.
/// Otherwise, opens the "Find Symbols" ToolWindow.
/// </summary>
public static void GoToMemberDefinition(string memberName, uint sreachOptions = (uint)_VSOBSEARCHOPTIONS.VSOBSO_LOOKINREFS)
{
GoToDefinition(memberName, _LIB_LISTTYPE.LLT_MEMBERS, sreachOptions);
}
public static void GoToClassDefinition(string typeName, uint sreachOptions = (uint)_VSOBSEARCHOPTIONS.VSOBSO_LOOKINREFS)
{
GoToDefinition(typeName, _LIB_LISTTYPE.LLT_CLASSES, sreachOptions);
}
private static void GoToDefinition(string memberName, _LIB_LISTTYPE libListtype, uint sreachOptions)
{
if (GoToDefinitionInternal(memberName, libListtype, sreachOptions) == false)
{
// There was an ambiguity (more than one item found) or no items found at all.
if (LegacyLocationFinder.CanFindSymbols(memberName, sreachOptions) == false)
{
Logger.Error("Failed to FindSymbol for symbol " + memberName);
}
}
}
private static bool GoToDefinitionInternal(string typeOrMemberName, _LIB_LISTTYPE symbolType, uint sreachOptions)
{
IVsSimpleObjectList2 list;
if (LegacyLocationFinder.TryFindSymbol(typeOrMemberName, out list, symbolType, sreachOptions))
{
int ok;
const VSOBJGOTOSRCTYPE whereToGo = VSOBJGOTOSRCTYPE.GS_DEFINITION;
DataTipService.CloseDataTipIfOpen();
return HResult.Succeeded(list.CanGoToSource(0, whereToGo, out ok)) &&
HResult.Succeeded(ok) &&
HResult.Succeeded(list.GoToSource(0, whereToGo));
}
return false;
}
}
public static class LibraryGetter
{
public static readonly Guid CSharpLibrary = new Guid("58f1bad0-2288-45b9-ac3a-d56398f7781d");
public static readonly Guid VBLibrary = new Guid("414AC972-9829-4B6A-A8D7-A08152FEB8AA");
/// <summary>
/// Get Visual Studio's library of metadata for C#.
/// </summary>
public static IVsSimpleLibrary2 GetCSharpLibrary()
{
var objManager = VisualStudioServices.GetService<SVsObjectManager, IVsObjectManager2>();
IVsLibrary2 csharpLib;
var cSharpLibrary = CSharpLibrary;
objManager.FindLibrary(ref cSharpLibrary, out csharpLib);
return (IVsSimpleLibrary2)csharpLib;
}
}
[Obsolete("Not supported on vs 2015, Use FileLocationFinder implementation instead")]
internal static class LegacyLocationFinder
{
public static bool TryGetSourceLocation(string memberName, out string fileName, out uint line, uint sreachOptions)
{
IVsSimpleObjectList2 list;
if (LegacyLocationFinder.TryFindSymbol(memberName, out list, _LIB_LISTTYPE.LLT_MEMBERS, sreachOptions))
{
return HResult.Succeeded(list.GetSourceContextWithOwnership(0, out fileName, out line));
}
fileName = null;
line = 0;
return false;
}
/// <summary>
/// Tries to find a member (field/property/event/methods/etc).
/// </summary>
/// <param name="typeOrMemberName">The type or member we are searching for</param>
/// <param name="resultList">An IVsSimpleObjectList2 which contains a single result.</param>
/// <param name="symbolType">The type of symbol we are looking for (member/class/etc)</param>
/// <returns>
/// True if a unique match was found. False if the member does not exist or there was an ambiguity
/// (more than one member matched the search term).
/// </returns>
public static bool TryFindSymbol(string typeOrMemberName,
out IVsSimpleObjectList2 resultList,
_LIB_LISTTYPE symbolType,
uint sreachOptions)
{
try
{
// The Visual Studio API we're using here breaks with superfulous spaces
typeOrMemberName = typeOrMemberName.Replace(" ", "");
var library = LibraryGetter.GetCSharpLibrary();
IVsSimpleObjectList2 list;
var searchSucceed = HResult.Succeeded(library.GetList2((uint)symbolType,
(uint)_LIB_LISTFLAGS.LLF_USESEARCHFILTER,
CreateSearchCriteria(typeOrMemberName, sreachOptions),
out list));
if (searchSucceed && list != null)
{
// Check if there is an ambiguity (where there is more than one symbol that matches)
if (GetSymbolNames(list).Distinct().Count() == 1)
{
uint count;
list.GetItemCount(out count);
if (count > 1)
{
int ok;
list.CanDelete((uint)1, out ok);
}
resultList = list;
return true;
}
}
}
catch (AccessViolationException e)
{
/* eat this type of exception (ripped from original implementation) */
}
resultList = null;
return false;
}
public static bool CanFindSymbols(string memberName, uint sreachOptions)
{
var searcher = VisualStudioServices.GetService<SVsObjectSearch, IVsFindSymbol>();
var guidSymbolScope = LibraryGetter.CSharpLibrary;
return HResult.Succeeded(searcher.DoSearch(ref guidSymbolScope, CreateSearchCriteria(memberName, sreachOptions)));
}
private static VSOBSEARCHCRITERIA2[] CreateSearchCriteria(string typeOrMemberName, uint sreachOptions)
{
return new[]
{
new VSOBSEARCHCRITERIA2
{
eSrchType = VSOBSEARCHTYPE.SO_PRESTRING,
//grfOptions = (uint)_VSOBSEARCHOPTIONS.VSOBSO_LOOKINREFS,
grfOptions = sreachOptions,
szName = typeOrMemberName
}
};
}
private static IEnumerable<string> GetSymbolNames(IVsSimpleObjectList2 list)
{
uint count;
if (HResult.Succeeded(list.GetItemCount(out count)))
{
for (uint i = 0; i < count; i++)
{
object symbol;
if (HResult.Succeeded(list.GetProperty(i,
(int)_VSOBJLISTELEMPROPID.VSOBJLISTELEMPROPID_FULLNAME,
out symbol)))
{
yield return (string)symbol;
}
}
}
}
}
@PeterMacej
Copy link

Thank you for the code! Just one question. What is the following code in TryFindSymbol for?

if (count > 1)
{
    int ok;
    list.CanDelete((uint)1, out ok);
}

It seems it does nothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment