diff options
author | Eugene Tarassov | 2015-03-10 19:22:52 +0000 |
---|---|---|
committer | Eugene Tarassov | 2015-03-10 19:22:52 +0000 |
commit | 09d7b0b7c4ba6ae8a83e173f4b13d9af85d1cf34 (patch) | |
tree | 925f55f008bef91135907989d2614ac7006f41f0 /plugins/org.eclipse.tcf.cdt.ui/src | |
parent | 4904421444e5f3cb06871c5216c2666d82450cff (diff) | |
download | org.eclipse.tcf-09d7b0b7c4ba6ae8a83e173f4b13d9af85d1cf34.tar.gz org.eclipse.tcf-09d7b0b7c4ba6ae8a83e173f4b13d9af85d1cf34.tar.xz org.eclipse.tcf-09d7b0b7c4ba6ae8a83e173f4b13d9af85d1cf34.zip |
TCF Debugger: fixed: Step Into Selection is disabled in the TCF debugger
Diffstat (limited to 'plugins/org.eclipse.tcf.cdt.ui/src')
3 files changed, 775 insertions, 62 deletions
diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/TCFNodeAdapterFactory.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/TCFNodeAdapterFactory.java index d112ddb86..1c9d6ece9 100644 --- a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/TCFNodeAdapterFactory.java +++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/TCFNodeAdapterFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2012 Wind River Systems, Inc. and others. + * Copyright (c) 2010, 2015 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.tcf.internal.cdt.ui; +import java.util.ArrayList; + import org.eclipse.cdt.debug.core.model.IReverseResumeHandler; import org.eclipse.cdt.debug.core.model.IReverseStepIntoHandler; import org.eclipse.cdt.debug.core.model.IReverseStepOverHandler; @@ -29,6 +31,7 @@ import org.eclipse.tcf.internal.cdt.ui.commands.TCFReverseStepIntoCommand; import org.eclipse.tcf.internal.cdt.ui.commands.TCFReverseStepOverCommand; import org.eclipse.tcf.internal.cdt.ui.commands.TCFReverseStepReturnCommand; import org.eclipse.tcf.internal.cdt.ui.commands.TCFReverseToggleCommand; +import org.eclipse.tcf.internal.cdt.ui.commands.TCFStepIntoSelectionHandler; import org.eclipse.tcf.internal.cdt.ui.disassembly.TCFDisassemblyBackend; import org.eclipse.tcf.internal.cdt.ui.hover.TCFDebugTextHover; import org.eclipse.tcf.internal.cdt.ui.sourcelookup.TCFSourceNotFoundPresentation; @@ -42,7 +45,11 @@ import org.eclipse.tcf.internal.debug.ui.model.TCFNodeStackFrame; @SuppressWarnings({ "rawtypes", "restriction" }) public class TCFNodeAdapterFactory implements IAdapterFactory { - private static final Class<?>[] CLASSES = { + // Not available before CDT 8.2 + private static final String STEP_INTO_SELECTION = + "org.eclipse.cdt.debug.core.model.IStepIntoSelectionHandler"; + + private static final Object[] class_names = { IDisassemblyBackend.class, ISteppingModeTarget.class, ISuspendResume.class, @@ -51,85 +58,95 @@ public class TCFNodeAdapterFactory implements IAdapterFactory { IReverseStepIntoHandler.class, IReverseStepOverHandler.class, IReverseResumeHandler.class, + STEP_INTO_SELECTION, IUncallHandler.class, IPinProvider.class, ICWatchpointTarget.class, ISourceNotFoundPresentation.class }; - private static final TCFSourceNotFoundPresentation fgSourceNotFoundPresentation = new TCFSourceNotFoundPresentation(); + private static final Class[] class_list; + + static { + ArrayList<Class> l = new ArrayList<Class>(); + for (Object o : class_names) { + if (o instanceof Class) { + l.add((Class)o); + } + else { + try { + l.add(Class.forName((String)o)); + } + catch (ClassNotFoundException e) { + } + } + } + class_list = l.toArray(new Class[l.size()]); + } public Object getAdapter(Object obj, Class type) { if (obj instanceof TCFNode) { final TCFNode node = (TCFNode)obj; TCFModel model = node.getModel(); - if (IDisassemblyBackend.class == type) { - TCFDisassemblyBackend backend = new TCFDisassemblyBackend(); - if (backend.supportsDebugContext((TCFNode)obj)) return backend; - } - else if (ISteppingModeTarget.class == type) { - ISteppingModeTarget target = (ISteppingModeTarget)model.getAdapter(type, node); - if (target == null) model.setAdapter(type, target = new TCFSteppingModeTarget(model)); - return target; - } - else if (ISuspendResume.class == type) { - TCFNodeExecContext exec = null; - if (node instanceof TCFNodeExecContext) { - exec = (TCFNodeExecContext)node; + Object handler = model.getAdapter(type, node); + if (handler == null) { + if (IDisassemblyBackend.class == type) { + TCFDisassemblyBackend backend = new TCFDisassemblyBackend(); + if (backend.supportsDebugContext(node)) return backend; + backend.dispose(); } - else if (node instanceof TCFNodeStackFrame) { - exec = (TCFNodeExecContext)node.getParent(); + else if (ISteppingModeTarget.class == type) { + model.setAdapter(type, handler = new TCFSteppingModeTarget(model)); } - if (exec != null) { - return new TCFSuspendResumeAdapter(exec); + else if (ISuspendResume.class == type) { + TCFNodeExecContext exec = null; + if (node instanceof TCFNodeExecContext) { + exec = (TCFNodeExecContext)node; + } + else if (node instanceof TCFNodeStackFrame) { + exec = (TCFNodeExecContext)node.getParent(); + } + if (exec != null) { + return new TCFSuspendResumeAdapter(exec); + } + } + else if (ICEditorTextHover.class == type) { + model.setAdapter(type, handler = new TCFDebugTextHover()); + } + else if (IReverseToggleHandler.class == type) { + model.setAdapter(type, handler = new TCFReverseToggleCommand()); + } + else if (IReverseStepIntoHandler.class == type) { + model.setAdapter(type, handler = new TCFReverseStepIntoCommand(model)); + } + else if (IReverseStepOverHandler.class == type) { + model.setAdapter(type, handler = new TCFReverseStepOverCommand(model)); + } + else if (IUncallHandler.class == type) { + model.setAdapter(type, handler = new TCFReverseStepReturnCommand(model)); + } + else if (IReverseResumeHandler.class == type) { + model.setAdapter(type, handler = new TCFReverseResumeCommand(model)); + } + else if (IPinProvider.class == type) { + model.setAdapter(type, handler = new TCFPinViewCommand(model)); + } + else if (ICWatchpointTarget.class == type) { + if (node instanceof TCFNodeExpression) return new TCFWatchpointTarget((TCFNodeExpression)node); + } + else if (ISourceNotFoundPresentation.class == type) { + model.setAdapter(type, handler = new TCFSourceNotFoundPresentation()); + } + else if (type.getName().equals(STEP_INTO_SELECTION)) { + model.setAdapter(type, handler = new TCFStepIntoSelectionHandler()); } } - else if (ICEditorTextHover.class == type) { - ICEditorTextHover hover = (ICEditorTextHover)model.getAdapter(type, node); - if (hover == null) model.setAdapter(type, hover = new TCFDebugTextHover()); - return hover; - } - else if (IReverseToggleHandler.class == type) { - IReverseToggleHandler handler = (IReverseToggleHandler)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFReverseToggleCommand()); - return handler; - } - else if (IReverseStepIntoHandler.class == type) { - IReverseStepIntoHandler handler = (IReverseStepIntoHandler)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFReverseStepIntoCommand(model)); - return handler; - } - else if (IReverseStepOverHandler.class == type) { - IReverseStepOverHandler handler = (IReverseStepOverHandler)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFReverseStepOverCommand(model)); - return handler; - } - else if (IUncallHandler.class == type) { - IUncallHandler handler = (IUncallHandler)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFReverseStepReturnCommand(model)); - return handler; - } - else if (IReverseResumeHandler.class == type) { - IReverseResumeHandler handler = (IReverseResumeHandler)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFReverseResumeCommand(model)); - return handler; - } - else if (IPinProvider.class == type) { - IPinProvider handler = (IPinProvider)model.getAdapter(type, node); - if (handler == null) model.setAdapter(type, handler = new TCFPinViewCommand(model)); - return handler; - } - else if (ICWatchpointTarget.class == type) { - if (node instanceof TCFNodeExpression) return new TCFWatchpointTarget((TCFNodeExpression)node); - } - else if (ISourceNotFoundPresentation.class == type) { - return fgSourceNotFoundPresentation; - } + return handler; } return null; } public Class[] getAdapterList() { - return CLASSES; + return class_list; } } diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/StepIntoSelectionLocation.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/StepIntoSelectionLocation.java new file mode 100644 index 000000000..bdda7f2ca --- /dev/null +++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/StepIntoSelectionLocation.java @@ -0,0 +1,457 @@ +/******************************************************************************* + * Copyright (c) 2015 Xilinx, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Xilinx - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.internal.cdt.ui.commands; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IName; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTImplicitName; +import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IParameter; +import org.eclipse.cdt.core.dom.ast.IProblemBinding; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.index.IIndexManager; +import org.eclipse.cdt.core.index.IIndexName; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.IFunctionDeclaration; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.debug.internal.ui.CDebugUIUtils; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; +import org.eclipse.cdt.internal.core.index.IIndexFragmentName; +import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; +import org.eclipse.cdt.internal.core.model.ext.CElementHandleFactory; +import org.eclipse.cdt.internal.core.model.ext.ICElementHandle; +import org.eclipse.cdt.internal.ui.editor.ASTProvider; +import org.eclipse.cdt.internal.ui.editor.CEditor; +import org.eclipse.cdt.internal.ui.viewsupport.IndexUI; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.tcf.internal.cdt.ui.Activator; +import org.eclipse.tcf.internal.debug.ui.model.TCFModel; +import org.eclipse.tcf.internal.debug.ui.model.TCFNodeExecContext; +import org.eclipse.tcf.internal.debug.ui.model.TCFNodeStackFrame; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.editors.text.TextEditor; + +@SuppressWarnings("restriction") +class StepIntoSelectionLocation { + + IDebugCommandRequest request; + TCFNodeExecContext node; + TextEditor editor; + ITextSelection text_selection; + String text_file; + int text_line; + ITranslationUnit compilation_unit; + IIndex project_index; + IFunctionDeclaration[] resolved_functions; + IFunctionDeclaration target_function; + + private enum NameKind { REFERENCE, DECLARATION, USING_DECL, DEFINITION } + + void getTextLocation(IDebugCommandRequest request) { + this.request = request; + Object[] elements = request.getElements(); + if (elements.length != 1) return; + + if (elements[0] instanceof TCFNodeExecContext) { + node = (TCFNodeExecContext)elements[0]; + } + else if (elements[0] instanceof TCFNodeStackFrame) { + node = (TCFNodeExecContext)((TCFNodeStackFrame)elements[0]).getParent(); + } + else { + return; + } + + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + if (win != null && win.getActivePage() != null) { + IEditorPart part = win.getActivePage().getActiveEditor(); + if (part instanceof TextEditor) editor = (TextEditor)part; + } + if (editor != null) { + ISelection selection = editor.getEditorSite().getSelectionProvider().getSelection(); + if (selection instanceof ITextSelection) text_selection = (ITextSelection)selection; + try { + text_file = CDebugUIUtils.getEditorFilePath(editor.getEditorInput()); + } + catch (CoreException x) { + request.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + IStatus.ERROR, TCFModel.getErrorMessage(x, true), x)); + return; + } + } + if (text_selection != null) { + text_line = text_selection.getStartLine() + 1; + } + } + + private IName[] findDefinitions(IIndex index, IASTTranslationUnit ast, StepIntoSelectionLocation.NameKind kind, IBinding binding) throws CoreException { + List<IASTName> declNames = new ArrayList<IASTName>(); + declNames.addAll(Arrays.asList(ast.getDefinitionsInAST(binding))); + for (Iterator<IASTName> i = declNames.iterator(); i.hasNext();) { + IASTName name = i.next(); + final IBinding b2 = name.resolveBinding(); + if (b2 instanceof ICPPUsingDeclaration) { + i.remove(); + } + if (binding != b2 && binding instanceof ICPPSpecialization) { + // Make sure binding specializes b2 so that for instance we do + // not navigate from + // one partial specialization to another. + IBinding spec = binding; + while (spec instanceof ICPPSpecialization) { + spec = ((ICPPSpecialization) spec).getSpecializedBinding(); + if (spec == b2) + break; + } + if (!(spec instanceof ICPPSpecialization)) { + i.remove(); + } + } + } + if (!declNames.isEmpty()) { + return declNames.toArray(new IASTName[declNames.size()]); + } + + // 2. Try definition in index. + return index.findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); + } + + private IName[] findDeclarations(IIndex index, IASTTranslationUnit ast, IBinding binding) throws CoreException { + IASTName[] astNames = ast.getDeclarationsInAST(binding); + ArrayList<IASTName> usingDeclarations = null; + for (int i = 0; i < astNames.length; i++) { + IASTName name = astNames[i]; + if (name.isDefinition()) { + astNames[i] = null; + } else if (CPPVisitor.findAncestorWithType(name, ICPPASTUsingDeclaration.class) != null) { + if (usingDeclarations == null) + usingDeclarations = new ArrayList<IASTName>(1); + usingDeclarations.add(name); + astNames[i] = null; + } + } + IName[] declNames = ArrayUtil.removeNulls(astNames); + if (declNames.length == 0) { + declNames = index.findNames(binding, IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); + } + // 'using' declarations are considered only when there are no other + // declarations. + if (declNames.length == 0 && usingDeclarations != null) { + declNames = usingDeclarations.toArray(new IName[usingDeclarations.size()]); + } + return declNames; + } + + private IName[] findNames(IIndex index, IASTTranslationUnit ast, StepIntoSelectionLocation.NameKind kind, IBinding binding) throws CoreException { + IName[] declNames; + if (kind == NameKind.DEFINITION) { + declNames = findDeclarations(index, ast, binding); + } + else { + declNames = findDefinitions(index, ast, kind, binding); + } + + if (declNames.length == 0) { + if (kind == NameKind.DEFINITION) { + declNames = findDefinitions(index, ast, kind, binding); + } + else { + declNames = findDeclarations(index, ast, binding); + } + } + return declNames; + } + + private IName[] findDeclNames(IASTTranslationUnit ast, StepIntoSelectionLocation.NameKind kind, IBinding binding) throws CoreException { + IName[] declNames = findNames(project_index, ast, kind, binding); + while (declNames.length == 0 && binding instanceof ICPPSpecialization) { + binding = ((ICPPSpecialization) binding).getSpecializedBinding(); + if (binding != null && !(binding instanceof IProblemBinding)) { + declNames = findNames(project_index, ast, NameKind.DEFINITION, binding); + } + } + if (declNames.length == 0 && binding instanceof ICPPMethod) { + ICPPMethod method = (ICPPMethod) binding; + if (method.isImplicit()) { + IBinding clsBinding = method.getClassOwner(); + if (clsBinding != null && !(clsBinding instanceof IProblemBinding)) { + declNames = findNames(project_index, ast, NameKind.REFERENCE, clsBinding); + } + } + } + return declNames; + } + + /* + * Returns definitions of bindings referenced by implicit name at the given location. + */ + private IName[] findImplicitTargets(IASTTranslationUnit ast, IASTNodeSelector nodeSelector, int offset, int length) throws CoreException { + IName[] definitions = IName.EMPTY_ARRAY; + IASTName firstName = nodeSelector.findEnclosingImplicitName(offset, length); + if (firstName != null) { + IASTImplicitNameOwner owner = (IASTImplicitNameOwner) firstName.getParent(); + for (IASTImplicitName name : owner.getImplicitNames()) { + if (((ASTNode) name).getOffset() == ((ASTNode) firstName).getOffset()) { + IBinding binding = name.resolveBinding(); // Guaranteed to + // resolve. + IName[] declNames = findDeclNames(ast, NameKind.REFERENCE, binding); + definitions = ArrayUtil.addAll(definitions, declNames); + } + } + } + return ArrayUtil.trim(definitions); + } + + private static IBinding getBinding(IName name) { + if (name instanceof IASTName) { + return ((IASTName) name).resolveBinding(); + } + else if (name instanceof IIndexFragmentName) { + try { + return ((IIndexFragmentName) name).getBinding(); + } + catch (CoreException e) { + // Fall through to return null. + } + } + return null; + } + + private static StepIntoSelectionLocation.NameKind getNameKind(IName name) { + if (name.isDefinition()) { + if (getBinding(name) instanceof ICPPUsingDeclaration) { + return NameKind.USING_DECL; + } + else { + return NameKind.DEFINITION; + } + } + else if (name.isDeclaration()) { + return NameKind.DECLARATION; + } + return NameKind.REFERENCE; + } + + private boolean areOverlappingNames(IName n1, IName n2) { + if (n1 == n2) + return true; + + IASTFileLocation loc1 = n1.getFileLocation(); + IASTFileLocation loc2 = n2.getFileLocation(); + if (loc1 == null || loc2 == null) return false; + return loc1.getFileName().equals(loc2.getFileName()) + && max(loc1.getNodeOffset(), loc2.getNodeOffset()) < min(loc1.getNodeOffset() + loc1.getNodeLength(), loc2.getNodeOffset() + loc2.getNodeLength()); + } + + private static IASTDeclaration getEnclosingFunctionDefinition(IASTNode node) { + while (node != null && !(node instanceof IASTFunctionDefinition)) { + node = node.getParent(); + } + return (IASTDeclaration) node; + } + + private static boolean isInSameFunction(IASTName refName, IName funcDeclName) { + if (funcDeclName instanceof IASTName) { + IASTDeclaration fdef = getEnclosingFunctionDefinition((IASTNode) funcDeclName); + return fdef != null && fdef.contains(refName); + } + return false; + } + + private static IASTDeclaration getEnclosingTemplateDeclaration(IASTNode node) { + while (node != null && !(node instanceof ICPPASTTemplateDeclaration)) { + node = node.getParent(); + } + return (IASTDeclaration) node; + } + + private static boolean isInSameTemplate(IASTName refName, IName templateDeclName) { + if (templateDeclName instanceof IASTName) { + IASTDeclaration template = getEnclosingTemplateDeclaration(refName); + return template != null && template.contains(refName); + } + return false; + } + + private ICElementHandle getCElementForName(ICProject project, IIndex index, IName declName) throws CoreException { + if (declName instanceof IIndexName) { + return IndexUI.getCElementForName(project, index, (IIndexName) declName); + } + if (declName instanceof IASTName) { + IASTName astName = (IASTName) declName; + IBinding binding = astName.resolveBinding(); + if (binding != null) { + ITranslationUnit tu = IndexUI.getTranslationUnit(project, astName); + if (tu != null) { + IASTFileLocation loc = astName.getFileLocation(); + IRegion region = new Region(loc.getNodeOffset(), loc.getNodeLength()); + return CElementHandleFactory.create(tu, binding, astName.isDefinition(), region, 0); + } + } + return null; + } + return null; + } + + private void filterToFunctions(ICProject project, IIndex index, IName[] declNames, List<IFunctionDeclaration> functionElements) { + for (IName declName : declNames) { + try { + ICElement elem = getCElementForName(project, index, declName); + if (elem instanceof IFunctionDeclaration) { + functionElements.add((IFunctionDeclaration) elem); + } + } + catch (CoreException e) { + CUIPlugin.log(e); + } + } + } + + void getTargetFunction(IDebugCommandRequest request) { + getTextLocation(request); + if (text_selection == null) return; + text_line = text_selection.getStartLine() + 1; + if (editor instanceof CEditor) { + compilation_unit = ((CEditor)editor).getInputCElement(); + if (compilation_unit == null) return; + try { + project_index = CCorePlugin.getIndexManager().getIndex(compilation_unit.getCProject(), + IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_DEPENDENT | IIndexManager.ADD_EXTENSION_FRAGMENTS_NAVIGATION); + } + catch (Exception x) { + request.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + IStatus.ERROR, TCFModel.getErrorMessage(x, true), x)); + return; + } + IStatus status = ASTProvider.getASTProvider().runOnAST(compilation_unit, ASTProvider.WAIT_NO, null, new ASTRunnable() { + @Override + public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException { + if (ast == null) return Status.OK_STATUS; + + int selection_start = text_selection.getOffset(); + int selection_length = text_selection.getLength(); + + final IASTNodeSelector node_selector = ast.getNodeSelector(null); + + IASTName source_name = node_selector.findEnclosingName(selection_start, selection_length); + if (source_name == null) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, + "Unable to resolve the selection to a semantic object"); + } + + IName[] implicitTargets = findImplicitTargets(ast, node_selector, selection_start, selection_length); + + StepIntoSelectionLocation.NameKind kind = getNameKind(source_name); + IBinding b = source_name.resolveBinding(); + IBinding[] bindings = new IBinding[] { b }; + if (b instanceof IProblemBinding) { + IBinding[] candidateBindings = ((IProblemBinding) b).getCandidateBindings(); + if (candidateBindings.length != 0) { + bindings = candidateBindings; + } + } + else if (kind == NameKind.DEFINITION && b instanceof IType) { + // No resolution of type definitions. + return Status.OK_STATUS; + } + + IName[] targets = IName.EMPTY_ARRAY; + String file_path = ast.getFilePath(); + for (IBinding binding : bindings) { + if (binding != null && !(binding instanceof IProblemBinding)) { + IName[] names = findDeclNames(ast, kind, binding); + for (final IName name : names) { + if (name != null) { + if (name instanceof IIndexName && file_path.equals(((IIndexName)name).getFileLocation().getFileName())) { + // Exclude index names from the current file. + } + else if (areOverlappingNames(name, source_name)) { + // Exclude the current location. + } + else if (binding instanceof IParameter) { + if (isInSameFunction(source_name, name)) { + targets = ArrayUtil.append(targets, name); + } + } + else if (binding instanceof ICPPTemplateParameter) { + if (isInSameTemplate(source_name, name)) { + targets = ArrayUtil.append(targets, name); + } + } + else { + targets = ArrayUtil.append(targets, name); + } + } + } + } + } + + targets = ArrayUtil.trim(ArrayUtil.addAll(targets, implicitTargets)); + + final ArrayList<IFunctionDeclaration> functionElements = new ArrayList<IFunctionDeclaration>(); + filterToFunctions(compilation_unit.getCProject(), project_index, targets, functionElements); + + // save the resolved function declarations + resolved_functions = functionElements.toArray(new IFunctionDeclaration[functionElements.size()]); + + return Status.OK_STATUS; + } + }); + if (status.getSeverity() != Status.OK) request.setStatus(status); + } + if (resolved_functions != null && resolved_functions.length == 1 && resolved_functions[0] != null) { + target_function = resolved_functions[0]; + } + } + + boolean isValid() { + return request != null && request.getStatus() == null && text_file != null && text_line > 0; + } +} diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/TCFStepIntoSelectionHandler.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/TCFStepIntoSelectionHandler.java new file mode 100644 index 000000000..ba39ed595 --- /dev/null +++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/commands/TCFStepIntoSelectionHandler.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2015 Xilinx, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Xilinx - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.internal.cdt.ui.commands; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandHandler; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.tcf.internal.cdt.ui.Activator; +import org.eclipse.tcf.internal.debug.actions.TCFAction; +import org.eclipse.tcf.internal.debug.model.TCFContextState; +import org.eclipse.tcf.internal.debug.ui.model.TCFModel; +import org.eclipse.tcf.protocol.IChannel; +import org.eclipse.tcf.protocol.IToken; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.services.IBreakpoints; +import org.eclipse.tcf.services.IRunControl; +import org.eclipse.tcf.services.IRunControl.RunControlContext; +import org.eclipse.tcf.services.IRunControl.RunControlListener; +import org.eclipse.tcf.util.TCFDataCache; + +public class TCFStepIntoSelectionHandler implements IDebugCommandHandler { + + @Override + public void canExecute(final IEnabledStateRequest request) { + final StepIntoSelectionLocation l = new StepIntoSelectionLocation(); + l.getTextLocation(request); + + if (!l.isValid()) { + request.setEnabled(false); + request.done(); + return; + } + + Protocol.invokeLater(new Runnable() { + @Override + public void run() { + if (l.node.isDisposed()) { + done(null, false); + return; + } + TCFDataCache<TCFContextState> cache = l.node.getState(); + if (!cache.validate(this)) return; + if (cache.getError() != null) { + done(cache.getError(), false); + return; + } + TCFContextState state = cache.getData(); + done(null, state != null && state.is_suspended); + } + private void done(Throwable e, boolean enabled) { + if (e != null) { + request.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + IStatus.ERROR, TCFModel.getErrorMessage(e, true), e)); + } + request.setEnabled(enabled); + request.done(); + } + }); + } + + @Override + public boolean execute(final IDebugCommandRequest request) { + final StepIntoSelectionLocation l = new StepIntoSelectionLocation(); + l.getTargetFunction(request); + + if (!l.isValid()) { + request.done(); + return true; + } + + Protocol.invokeLater(new Runnable() { + boolean run_to_line_done; + boolean req_done; + String bp_id; + @Override + public void run() { + if (l.node.isDisposed()) { + done(null); + return; + } + IChannel channel = l.node.getChannel(); + if (bp_id == null) { + IBreakpoints breakpoints = channel.getRemoteService(IBreakpoints.class); + if (breakpoints == null) { + done(new Exception("Cannot set breakpoint.")); + return; + } + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put(IBreakpoints.PROP_FILE, l.text_file); + properties.put(IBreakpoints.PROP_LINE, l.text_line); + if (run_to_line_done) { + assert l.target_function != null; + properties.put(IBreakpoints.PROP_LOCATION, l.target_function.getElementName()); + properties.put(IBreakpoints.PROP_SKIP_PROLOGUE, true); + } + properties.put(IBreakpoints.PROP_CONTEXT_IDS, new String[] { l.node.getID() }); + properties.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE); + bp_id = TCFAction.STEP_BREAKPOINT_PREFIX + l.node.getID(); + properties.put(IBreakpoints.PROP_ID, bp_id); + breakpoints.add(properties, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) { + bp_id = null; + done(error); + } + else { + run(); + } + } + }); + return; + } + final IRunControl run_ctrl = channel.getRemoteService(IRunControl.class); + if (run_ctrl == null) { + done(new Exception("Cannot resume.")); + return; + } + TCFDataCache<TCFContextState> state_cache = l.node.getState(); + if (!state_cache.validate(this)) return; + if (state_cache.getError() != null) { + done(state_cache.getError()); + return; + } + TCFContextState state = state_cache.getData(); + if (state == null || !state.is_suspended) { + done(null); + return; + } + TCFDataCache<IRunControl.RunControlContext> ctx_cache = l.node.getRunContext(); + if (!ctx_cache.validate(this)) return; + if (ctx_cache.getError() != null) { + done(ctx_cache.getError()); + return; + } + final String node_id = l.node.getID(); + run_ctrl.addListener(new RunControlListener() { + private void suspended() { + run_ctrl.removeListener(this); + if (!run_to_line_done) { + run_to_line_done = true; + if (l.target_function != null) { + assert bp_id != null; + IChannel channel = l.node.getChannel(); + IBreakpoints breakpoints = channel.getRemoteService(IBreakpoints.class); + breakpoints.remove(new String[] { bp_id }, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) done(error); + else run(); + } + }); + bp_id = null; + return; + } + } + done(null); + } + public void contextSuspended(String context, String pc, String reason, Map<String,Object> params) { + if (node_id.equals(context)) { + suspended(); + } + } + public void contextResumed(String context) { + } + public void contextRemoved(String[] context_ids) { + for (String context : context_ids) { + if (node_id.equals(context)) { + suspended(); + return; + } + } + } + public void contextException(String context, String msg) { + } + public void contextChanged(RunControlContext[] contexts) { + } + public void contextAdded(RunControlContext[] contexts) { + } + public void containerSuspended(String context, String pc, String reason, Map<String,Object> params, String[] suspended_ids) { + for (String context2 : suspended_ids) { + if (node_id.equals(context2)) { + suspended(); + return; + } + } + } + public void containerResumed(String[] context_ids) { + } + }); + IRunControl.RunControlContext ctx = ctx_cache.getData(); + ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) { + done(error); + } + else if (!req_done) { + req_done = true; + request.done(); + } + } + }); + } + private void done(Throwable e) { + if (bp_id != null) { + IChannel channel = l.node.getChannel(); + IBreakpoints breakpoints = channel.getRemoteService(IBreakpoints.class); + breakpoints.remove(new String[] { bp_id }, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + done(error); + } + }); + bp_id = null; + return; + } + if (!req_done) { + if (e != null) { + request.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + IStatus.ERROR, TCFModel.getErrorMessage(e, true), e)); + } + req_done = true; + request.done(); + } + } + }); + return true; + } +} |