private static CodeFunction GetCodeFunction(FileCodeModel2 fcm, TextPoint point) { try { var element = fcm.CodeElementFromPoint(point, vsCMElement.vsCMElementFunction); return((CodeFunction)element); } catch { return(null); } }
/// <summary> /// Used by C# ad-hoc methods (move and inline) to get information about the block of code, where right-click was performed. /// This methods makes use of document's FileCodeModel, which is not available for ASP .NET files - these files are thus /// handled by their own parser. /// </summary> /// <param name="text">Text of the block (e.g. code of a method, declaration of a variable...)</param> /// <param name="startPoint">Beginning of the text</param> /// <param name="codeFunctionName">Name of the function, where right-click was performed, null if right-click was performed on a variable.</param> /// <param name="codeVariableName">Name of the variable, where right-click was performed, null otherwise.</param> /// <param name="codeClass">Name of the class, where the code block is located.</param> /// <param name="selectionSpan">Current selection span.</param> /// <returns>True, if all necessary information was succesfully obtained, false otherwise.</returns> protected bool GetCodeBlockFromSelection(out string text, out TextPoint startPoint, out string codeFunctionName, out string codeVariableName, out CodeElement2 codeClass, out TextSpan selectionSpan, out bool isConst, out object codeModelSource) { // get current selection span TextSpan[] spans = new TextSpan[1]; int hr = textView.GetSelectionSpan(spans); Marshal.ThrowExceptionForHR(hr); selectionSpan = spans[0]; object o; hr = textLines.CreateTextPoint(selectionSpan.iStartLine, selectionSpan.iStartIndex, out o); Marshal.ThrowExceptionForHR(hr); TextPoint selectionPoint = (TextPoint)o; startPoint = null; text = null; bool ok = false; codeFunctionName = null; codeVariableName = null; codeClass = null; isConst = false; codeModelSource = null; // It is impossible to find out the code block, where right-click was performed. Following code // assumes that valid string literals or references can only be found in a method, in a class variable (as initializers) // or in a property code. C# syntax permits more locations (attributes, default argument values in .NET 4+) but we can ignore // these, because they are all evaluated at compile-time, making resource references impossible. // assume we are in a function (method) try { CodeFunction2 codeFunction = (CodeFunction2)currentCodeModel.CodeElementFromPoint(selectionPoint, vsCMElement.vsCMElementFunction); codeFunctionName = codeFunction.Name; codeClass = codeFunction.GetClass(); // extension codeModelSource = codeFunction; text = codeFunction.GetText(); if (!string.IsNullOrEmpty(text)) { startPoint = codeFunction.GetStartPoint(vsCMPart.vsCMPartBody); ok = true; } } catch (Exception) { // it's not a method - maybe a property? try { CodeProperty codeProperty = (CodeProperty)currentCodeModel.CodeElementFromPoint(selectionPoint, vsCMElement.vsCMElementProperty); codeFunctionName = codeProperty.Name; codeClass = codeProperty.GetClass(); codeModelSource = codeProperty; text = codeProperty.GetText(); if (!string.IsNullOrEmpty(text)) { startPoint = codeProperty.GetStartPoint(vsCMPart.vsCMPartBody); ok = true; } } catch (Exception) { // not a property, either. It must be a variable - or there's no valid code block try { CodeVariable2 codeVariable = (CodeVariable2)currentCodeModel.CodeElementFromPoint(selectionPoint, vsCMElement.vsCMElementVariable); if (codeVariable.InitExpression != null) { codeVariableName = codeVariable.Name; codeClass = codeVariable.GetClass(); isConst = codeVariable.ConstKind == vsCMConstKind.vsCMConstKindConst; codeModelSource = codeVariable; startPoint = codeVariable.StartPoint; text = codeVariable.GetText(); if ((codeClass.Kind == vsCMElement.vsCMElementStruct && codeVariable.IsShared) || (codeClass.Kind == vsCMElement.vsCMElementClass || codeClass.Kind == vsCMElement.vsCMElementModule) && !string.IsNullOrEmpty(text)) { ok = true; } } } catch (Exception) { return(false); } } } return(ok); }
public static CodeElement GetCodeElement(DTE dte, vsCMElement[] searchScopes) { if (dte.ActiveDocument == null) { return(null); } if (dte.ActiveDocument.ProjectItem == null) { return(null); } if (dte.ActiveDocument.ProjectItem.FileCodeModel == null) { return(null); } TextSelection selection = (TextSelection)dte.ActiveWindow.Selection; if (selection == null || selection.ActivePoint == null) { return(null); } EditPoint selPoint = selection.ActivePoint.CreateEditPoint(); CodeLanguage currentLang = CodeLanguage.CSharp; selPoint.StartOfLine(); while (true) { string BlockText = selPoint.GetText(selPoint.LineLength).Trim(); // *** Skip over any XML Doc comments and Attributes if (currentLang == CodeLanguage.CSharp && BlockText.StartsWith("/// ") || currentLang == CodeLanguage.CSharp && BlockText.StartsWith("[") || currentLang == CodeLanguage.VB && BlockText.StartsWith("''' ") || currentLang == CodeLanguage.VB && BlockText.StartsWith("<")) { selPoint.LineDown(1); selPoint.StartOfLine(); } else { break; } } // *** Make sure the cursor is placed inside of the definition always // *** Especially required for single line methods/fields/events etc. selPoint.EndOfLine(); selPoint.CharLeft(1); // Force into the text string xBlockText = selPoint.GetText(selPoint.LineLength).Trim(); // get the element under the cursor CodeElement element = null; FileCodeModel2 CodeModel = dte.ActiveDocument.ProjectItem.FileCodeModel as FileCodeModel2; // *** Supported scopes - set up here in the right parsing order // *** from lowest level to highest level // *** NOTE: Must be adjusted to match any CodeElements supported foreach (vsCMElement scope in searchScopes) { try { element = CodeModel.CodeElementFromPoint(selPoint, scope); if (element != null) { break; // if no exception - break } } catch {; } } if (element == null) { return(null); } return(element); }