mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 374155 - Source hover should display deduced type of "auto"
variables
This commit is contained in:
parent
31e3729d82
commit
2db77fef98
1 changed files with 125 additions and 46 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002, 2011 QNX Software Systems and others.
|
||||
* Copyright (c) 2002, 2012 QNX Software Systems 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
|
||||
|
@ -8,6 +8,7 @@
|
|||
* Contributors:
|
||||
* QNX Software Systems - Initial API and implementation
|
||||
* Anton Leherbauer (Wind River Systems)
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text.c.hover;
|
||||
|
||||
|
@ -47,12 +48,20 @@ import org.eclipse.ui.part.IWorkbenchPartOrientation;
|
|||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.IName;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
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.IASTParameterDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||
|
@ -62,9 +71,14 @@ import org.eclipse.cdt.core.dom.ast.IFunction;
|
|||
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IParameter;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.ITypedef;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
|
||||
|
@ -77,12 +91,14 @@ import org.eclipse.cdt.core.model.ILanguage;
|
|||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.core.parser.KeywordSetKey;
|
||||
import org.eclipse.cdt.core.parser.Keywords;
|
||||
import org.eclipse.cdt.core.parser.ParserFactory;
|
||||
import org.eclipse.cdt.core.parser.ParserLanguage;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.IWorkingCopyManager;
|
||||
import org.eclipse.cdt.ui.text.ICPartitions;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
|
||||
import org.eclipse.cdt.internal.corext.util.Strings;
|
||||
|
||||
|
@ -117,16 +133,19 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
protected static class ComputeSourceRunnable implements ASTRunnable {
|
||||
private final ITranslationUnit fTU;
|
||||
private final IRegion fTextRegion;
|
||||
private final String fSelection;
|
||||
private final IProgressMonitor fMonitor;
|
||||
private String fSource;
|
||||
|
||||
/**
|
||||
* @param tUnit
|
||||
* @param textRegion
|
||||
* @param tUnit the translation unit
|
||||
* @param textRegion the selected region
|
||||
* @param selection the text of the selected region without
|
||||
*/
|
||||
public ComputeSourceRunnable(ITranslationUnit tUnit, IRegion textRegion) {
|
||||
public ComputeSourceRunnable(ITranslationUnit tUnit, IRegion textRegion, String selection) {
|
||||
fTU= tUnit;
|
||||
fTextRegion= textRegion;
|
||||
fSelection = selection;
|
||||
fMonitor= new NullProgressMonitor();
|
||||
fSource= null;
|
||||
}
|
||||
|
@ -138,40 +157,70 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
|
||||
if (ast != null) {
|
||||
try {
|
||||
IASTName name= ast.getNodeSelector(null).findEnclosingName(fTextRegion.getOffset(), fTextRegion.getLength());
|
||||
if (name != null) {
|
||||
IBinding binding= name.resolveBinding();
|
||||
if (binding != null) {
|
||||
// Check for implicit names first, could be an implicit constructor call
|
||||
if (name.getParent() instanceof IASTImplicitNameOwner) {
|
||||
IASTImplicitNameOwner iastImplicitNameOwner = (IASTImplicitNameOwner) name.getParent();
|
||||
IASTName [] implicitNames = iastImplicitNameOwner.getImplicitNames();
|
||||
if (implicitNames.length == 1) {
|
||||
IBinding implicitNameBinding = implicitNames[0].resolveBinding();
|
||||
if (implicitNameBinding instanceof ICPPConstructor) {
|
||||
binding = implicitNameBinding;
|
||||
IASTNodeSelector nodeSelector = ast.getNodeSelector(null);
|
||||
if (fSelection.equals(Keywords.AUTO)) {
|
||||
IASTNode node = nodeSelector.findEnclosingNode(fTextRegion.getOffset(), fTextRegion.getLength());
|
||||
if (node instanceof ICPPASTDeclSpecifier) {
|
||||
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) node;
|
||||
IASTNode parent = declSpec.getParent();
|
||||
IASTDeclarator[] declarators = IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
|
||||
if (parent instanceof IASTSimpleDeclaration) {
|
||||
declarators = ((IASTSimpleDeclaration) parent).getDeclarators();
|
||||
} else if (parent instanceof IASTParameterDeclaration) {
|
||||
declarators = new IASTDeclarator[] { ((IASTParameterDeclaration) parent).getDeclarator() };
|
||||
} else if (parent instanceof ICPPASTTypeId) {
|
||||
declarators = new IASTDeclarator[] { ((ICPPASTTypeId) parent).getAbstractDeclarator() };
|
||||
}
|
||||
IType type = null;
|
||||
for (IASTDeclarator declarator : declarators) {
|
||||
IType t = CPPVisitor.createType(declarator);
|
||||
if (type == null) {
|
||||
type = t;
|
||||
} else if (!type.isSameType(t)) {
|
||||
// Type varies between declarators - don't display anything.
|
||||
type = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type != null && !(type instanceof IProblemType))
|
||||
fSource = ASTTypeUtil.getType(type, false);
|
||||
}
|
||||
} else {
|
||||
IASTName name= nodeSelector.findEnclosingName(fTextRegion.getOffset(), fTextRegion.getLength());
|
||||
if (name != null) {
|
||||
IBinding binding= name.resolveBinding();
|
||||
if (binding != null) {
|
||||
// Check for implicit names first, could be an implicit constructor call.
|
||||
if (name.getParent() instanceof IASTImplicitNameOwner) {
|
||||
IASTImplicitNameOwner implicitNameOwner = (IASTImplicitNameOwner) name.getParent();
|
||||
IASTName[] implicitNames = implicitNameOwner.getImplicitNames();
|
||||
if (implicitNames.length == 1) {
|
||||
IBinding implicitNameBinding = implicitNames[0].resolveBinding();
|
||||
if (implicitNameBinding instanceof ICPPConstructor) {
|
||||
binding = implicitNameBinding;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (binding instanceof IProblemBinding) {
|
||||
// Report problem as source comment
|
||||
if (DEBUG) {
|
||||
IProblemBinding problem= (IProblemBinding) binding;
|
||||
fSource= "/* Indexer Problem!\n" + //$NON-NLS-1$
|
||||
" * " + problem.getMessage() + //$NON-NLS-1$
|
||||
"\n */"; //$NON-NLS-1$
|
||||
|
||||
if (binding instanceof IProblemBinding) {
|
||||
// Report problem as source comment.
|
||||
if (DEBUG) {
|
||||
IProblemBinding problem= (IProblemBinding) binding;
|
||||
fSource= "/* Problem:\n" + //$NON-NLS-1$
|
||||
" * " + problem.getMessage() + //$NON-NLS-1$
|
||||
"\n */"; //$NON-NLS-1$
|
||||
}
|
||||
} else if (binding instanceof IMacroBinding) {
|
||||
fSource= computeSourceForMacro(ast, name, binding);
|
||||
} else {
|
||||
fSource= computeSourceForBinding(ast, binding);
|
||||
}
|
||||
} else if (binding instanceof IMacroBinding) {
|
||||
fSource= computeSourceForMacro(ast, name, binding);
|
||||
} else {
|
||||
fSource= computeSourceForBinding(ast, binding);
|
||||
}
|
||||
if (fSource != null) {
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fSource != null) {
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
return e.getStatus();
|
||||
} catch (DOMException e) {
|
||||
|
@ -269,13 +318,13 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
IPath location= Path.fromOSString(fileName);
|
||||
LocationKind locationKind= LocationKind.LOCATION;
|
||||
if (name instanceof IASTName && !name.isReference()) {
|
||||
IASTName astName= (IASTName)name;
|
||||
IASTName astName= (IASTName) name;
|
||||
if (astName.getTranslationUnit().getFilePath().equals(fileName)) {
|
||||
int hoverOffset = fTextRegion.getOffset();
|
||||
if (hoverOffset <= nodeOffset && nodeOffset < hoverOffset + fTextRegion.getLength() ||
|
||||
hoverOffset >= nodeOffset && hoverOffset < nodeOffset + nodeLength) {
|
||||
// Bug 359352 - don't show source if its the same we are hovering on.
|
||||
return null;
|
||||
return computeHoverForDeclaration(astName);
|
||||
}
|
||||
if (fTU.getResource() != null) {
|
||||
// Reuse editor buffer for names local to the translation unit
|
||||
|
@ -350,6 +399,37 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the hover containing the deduced type for a declaration based on {@code auto}
|
||||
* keyword.
|
||||
*
|
||||
* @param name the name of the declarator
|
||||
* @return the hover text, if the declaration is based on {@code auto} keyword,
|
||||
* otherwise {@code null}.
|
||||
*/
|
||||
private String computeHoverForDeclaration(IASTName name) {
|
||||
ICPPASTDeclarator declarator =
|
||||
CPPVisitor.findAncestorWithType(name, ICPPASTDeclarator.class);
|
||||
if (declarator == null)
|
||||
return null;
|
||||
IASTDeclaration declaration =
|
||||
CPPVisitor.findAncestorWithType(declarator, IASTDeclaration.class);
|
||||
IASTDeclSpecifier declSpec = null;
|
||||
if (declaration instanceof IASTSimpleDeclaration) {
|
||||
declSpec = ((IASTSimpleDeclaration) declaration).getDeclSpecifier();
|
||||
} else if (declaration instanceof IASTParameterDeclaration) {
|
||||
declSpec = ((IASTParameterDeclaration) declaration).getDeclSpecifier();
|
||||
}
|
||||
if (!(declSpec instanceof ICPPASTSimpleDeclSpecifier) ||
|
||||
((ICPPASTSimpleDeclSpecifier) declSpec).getType() != IASTSimpleDeclSpecifier.t_auto) {
|
||||
return null;
|
||||
}
|
||||
IType type = CPPVisitor.createType(declarator);
|
||||
if (type instanceof IProblemType)
|
||||
return null;
|
||||
return ASTTypeUtil.getType(type, false) + " " + name.getRawSignature(); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the name is part of a KnR function definition.
|
||||
* @param name
|
||||
|
@ -601,12 +681,12 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
if (editor != null) {
|
||||
IEditorInput input= editor.getEditorInput();
|
||||
IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager();
|
||||
IWorkingCopy copy = manager.getWorkingCopy(input);
|
||||
IWorkingCopy workingCopy = manager.getWorkingCopy(input);
|
||||
try {
|
||||
if (copy == null || !copy.isConsistent()) {
|
||||
if (workingCopy == null || !workingCopy.isConsistent()) {
|
||||
return null;
|
||||
}
|
||||
} catch (CModelException exc) {
|
||||
} catch (CModelException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -617,14 +697,13 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
if (expression.isEmpty())
|
||||
return null;
|
||||
|
||||
// Before trying a search lets make sure that the user is not hovering over a keyword
|
||||
if (selectionIsKeyword(expression))
|
||||
// Before trying a search lets make sure that the user is not hovering
|
||||
// over a keyword other than 'auto'.
|
||||
if (selectionIsKeyword(expression) && !expression.equals(Keywords.AUTO))
|
||||
return null;
|
||||
|
||||
String source= null;
|
||||
|
||||
// Try with the indexer
|
||||
source= searchInIndex(copy, hoverRegion);
|
||||
// Try with the indexer.
|
||||
String source= searchInIndex(workingCopy, hoverRegion, expression);
|
||||
|
||||
if (source == null || source.trim().isEmpty())
|
||||
return null;
|
||||
|
@ -741,8 +820,8 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
return source.substring(i);
|
||||
}
|
||||
|
||||
protected String searchInIndex(final ITranslationUnit tUnit, IRegion textRegion) {
|
||||
final ComputeSourceRunnable computer= new ComputeSourceRunnable(tUnit, textRegion);
|
||||
protected String searchInIndex(final ITranslationUnit tUnit, IRegion textRegion, String selection) {
|
||||
final ComputeSourceRunnable computer= new ComputeSourceRunnable(tUnit, textRegion, selection);
|
||||
Job job= new Job(CHoverMessages.CSourceHover_jobTitle) {
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
|
@ -764,7 +843,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
job.schedule();
|
||||
try {
|
||||
job.join();
|
||||
} catch (InterruptedException exc) {
|
||||
} catch (InterruptedException e) {
|
||||
job.cancel();
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue