Created
September 6, 2015 08:47
-
-
Save OmerRaviv/fc3ce6fbd5b6af501f01 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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; | |
} | |
} | |
} | |
} | |
} |
That's this method: https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivsfindsymbol.dosearch.aspx
My specific implementation just opens the Find All References window if there is an ambiguity (more than one item was found and we don't know which one to Go To)
Ah yes of course, sorry, I adapted the code slightly and the "var searcher = " just disappeared.
Its working like a charm!
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
Hi Omar,
Thanks a lot for this gist! Just a question:
What does the "searcher.DoSearch()" method do? Looks like a key method for the GoToDefinitionEngine.