From f546a833d6f62ba84d9dfc94f79f6306390ca9b5 Mon Sep 17 00:00:00 2001 From: Michael Woski Date: Sat, 12 Aug 2017 23:19:51 +0200 Subject: [PATCH] Bug 520913 - hover / open declaration for decltype and typeof keywords Change-Id: I15db25080aa476e3e0e6f9c6ce063e9bd1e2b2b4 Signed-off-by: Michael Woski --- .../parser/cpp/semantics/CPPSemantics.java | 52 +++++++++++ .../parser/cpp/semantics/SemanticUtil.java | 4 + .../selection/CPPSelectionTestsNoIndexer.java | 29 ++++++- .../ui/editor/CElementHyperlinkDetector.java | 87 +++++++++++++------ .../search/actions/OpenDeclarationsJob.java | 49 +++++------ .../ui/text/c/hover/CSourceHover.java | 45 +++------- 6 files changed, 175 insertions(+), 91 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 241eacb07fc..10490e6fdcd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -110,6 +110,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; 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.ICPPASTDecltypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression; @@ -130,6 +131,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; @@ -139,6 +141,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; @@ -4449,4 +4452,53 @@ public class CPPSemantics { } return expressionType; } + + /** + * This method performs type deduction for auto, decltype or typeof + * declarations. This is used by {@code CSourceHover} and + * {@code OpenDeclarationsJob} after checking (see + * {@code SemanticUtil#isAutoOrDecltype(String)}) whether the selected text + * equals any of the mentioned keywords. + * + * @param node + * The decl-specifier or decltype-specifier in which the 'auto' + * or 'decltype' occurs. + * @return the deduced type or null + */ + public static IType resolveDecltypeOrAutoType(IASTNode node) { + IType type = null; + if (node instanceof ICPPASTDecltypeSpecifier) { + type = ((ICPPASTDecltypeSpecifier) node).getDecltypeExpression().getExpressionType(); + } + if (node instanceof ICPPASTSimpleDeclSpecifier) { + int builtin = ((ICPPASTSimpleDeclSpecifier) node).getType(); + if (builtin == ICPPASTSimpleDeclSpecifier.t_auto || builtin == ICPPASTSimpleDeclSpecifier.t_typeof + || builtin == ICPPASTSimpleDeclSpecifier.t_decltype) { + IASTNode parent = node.getParent(); + IASTDeclarator declarator = null; + if (parent instanceof IASTSimpleDeclaration) { + IASTDeclarator[] declarators = ((IASTSimpleDeclaration) parent).getDeclarators(); + // It's invalid for different declarators to deduce + // different types with 'auto', so just get the type based on the + // first declarator. + if (declarators.length > 0) + declarator = declarators[0]; + } else if (parent instanceof IASTParameterDeclaration + && builtin != ICPPASTSimpleDeclSpecifier.t_auto) { + declarator = ((IASTParameterDeclaration) parent).getDeclarator(); + } else if (parent instanceof ICPPASTTypeId && builtin != ICPPASTSimpleDeclSpecifier.t_auto) { + declarator = ((ICPPASTTypeId) parent).getAbstractDeclarator(); + } else if (parent instanceof ICPPASTFunctionDefinition) { + declarator = ((ICPPASTFunctionDefinition) parent).getDeclarator(); + } + if (declarator != null) { + type = CPPVisitor.createType(declarator); + if (type instanceof ICPPFunctionType) { + type = ((ICPPFunctionType) type).getReturnType(); + } + } + } + } + return type; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java index 15f78fb1fdf..7cdbb6819ac 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java @@ -739,6 +739,10 @@ public class SemanticUtil { return false; } + public static boolean isAutoOrDecltype(String code) { + return (code.equals(Keywords.AUTO) || code.equals(Keywords.TYPEOF) || code.equals(Keywords.DECLTYPE)); + } + public static boolean isEmptyParameterList(IType[] parameters) { if (parameters.length == 0) { return true; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java index ea46ee12f56..5ec750985a0 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java @@ -1311,4 +1311,31 @@ public class CPPSelectionTestsNoIndexer extends BaseSelectionTests { IASTNode target = testF3(file, offset); assertInstance(target, IASTName.class); } -} + + // struct Waldo {}; + // template + // struct Basket{}; + // Waldo find(); + // Waldo myFriend; + // int main(decltype(myFriend) p) { + // auto waldo = find(); + // Basket basket; + // decltype(waldo) wuff; + // } + public void testDeclType_520913() throws Exception { + String code = getAboveComment(); + IFile file = importFile("testBug520913.cpp", code); + + int offset = code.indexOf("main") + 10; + IASTNode target = testF3(file, offset); + assertInstance(target, IASTName.class); + + offset = code.indexOf("typeof"); + target = testF3(file, offset); + assertInstance(target, IASTName.class); + assertEquals("Waldo", ((IASTName) target).toString()); + + offset = code.indexOf("wuff") - 10; + target = testF3(file, offset); + assertInstance(target, IASTName.class); + }} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CElementHyperlinkDetector.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CElementHyperlinkDetector.java index 15b49eff20b..7421dc5988a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CElementHyperlinkDetector.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CElementHyperlinkDetector.java @@ -34,6 +34,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.model.ICLanguageKeywords; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.IWorkingCopy; @@ -41,6 +42,8 @@ import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.ICModelBasedEditor; import org.eclipse.cdt.ui.text.ICPartitions; +import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; import org.eclipse.cdt.internal.formatter.scanner.Scanner; import org.eclipse.cdt.internal.formatter.scanner.Token; @@ -76,33 +79,10 @@ public class CElementHyperlinkDetector extends AbstractHyperlinkDetector { public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { if (ast == null) return Status.CANCEL_STATUS; - final int offset= region.getOffset(); - final int length= Math.max(1, region.getLength()); - final IASTNodeSelector nodeSelector= ast.getNodeSelector(null); - IASTNode linkASTNode = null; + + IASTNode linkASTNode = getLinkASTNode(document, ast, region); + IASTNodeLocation linkLocation = null; - - IASTName selectedName= nodeSelector.findEnclosingName(offset, length); - if (selectedName != null) { // found a name - // Prefer include statement over the include name - if (selectedName.getParent() instanceof IASTPreprocessorIncludeStatement) { - linkASTNode = selectedName.getParent(); - } else { - linkASTNode = selectedName; - } - } else { - final IASTNode implicit = nodeSelector.findEnclosingImplicitName(offset, length); - if (implicit != null) { - linkASTNode = implicit; - } else { - // Search for include statement - final IASTNode cand= nodeSelector.findEnclosingNode(offset, length); - if (cand instanceof IASTPreprocessorIncludeStatement) { - linkASTNode = cand; - } - } - } - if (linkASTNode != null) { if (linkASTNode instanceof IASTName) { IASTName astName = (IASTName) linkASTNode; @@ -167,6 +147,55 @@ public class CElementHyperlinkDetector extends AbstractHyperlinkDetector { return new IHyperlink[] { new CElementHyperlink(hyperlinkRegion[0], openAction) }; } + private static IASTNode getLinkASTNode(IDocument document, IASTTranslationUnit ast, IRegion region) { + final int offset= region.getOffset(); + final int length= Math.max(1, region.getLength()); + + final IASTNodeSelector nodeSelector= ast.getNodeSelector(null); + if (isOverAutoOrDecltype(document, offset)) { + IASTNode node = nodeSelector.findEnclosingNode(offset, length); + IASTTypeId enclosingTypeId = ASTQueries.findAncestorWithType(node, IASTTypeId.class); + if (enclosingTypeId != null) { + return enclosingTypeId; + } + } + + IASTName selectedName= nodeSelector.findEnclosingName(offset, length); + if (selectedName != null) { // found a name + // Prefer include statement over the include name + if (selectedName.getParent() instanceof IASTPreprocessorIncludeStatement) { + return selectedName.getParent(); + } else { + return selectedName; + } + } else { + final IASTNode implicit = nodeSelector.findEnclosingImplicitName(offset, length); + if (implicit != null) { + return implicit; + } else { + // Search for include statement + final IASTNode cand= nodeSelector.findEnclosingNode(offset, length); + if (cand instanceof IASTPreprocessorIncludeStatement) { + return cand; + } + } + } + return null; + } + + private static boolean isOverAutoOrDecltype(IDocument document, int offset) { + try { + IRegion wordRegion = CWordFinder.findWord(document, offset); + if (wordRegion != null && wordRegion.getLength() > 0) { + String word = document.get(wordRegion.getOffset(), wordRegion.getLength()); + return SemanticUtil.isAutoOrDecltype(word); + } + } catch (BadLocationException e) { + // Fall through and return false. + } + return false; + } + /** * Returns the identifier at the given offset, or {@code null} if the there is no identifier * at the offset. @@ -175,8 +204,10 @@ public class CElementHyperlinkDetector extends AbstractHyperlinkDetector { IRegion wordRegion= CWordFinder.findWord(document, offset); if (wordRegion != null && wordRegion.getLength() > 0) { String word = document.get(wordRegion.getOffset(), wordRegion.getLength()); - if (!Character.isDigit(word.charAt(0)) && !isLanguageKeyword(language, word)) { - return wordRegion; + if (!Character.isDigit(word.charAt(0))) { + if (SemanticUtil.isAutoOrDecltype(word) || !isLanguageKeyword(language, word)) { + return wordRegion; + } } } return null; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java index bc43c5cc8c3..4fdd9a3db97 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java @@ -15,8 +15,8 @@ package org.eclipse.cdt.internal.ui.search.actions; import static java.lang.Math.max; import static java.lang.Math.min; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.PTR; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; import java.util.ArrayList; import java.util.Arrays; @@ -63,7 +63,6 @@ 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.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit; @@ -101,6 +100,7 @@ import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.HeuristicResolver; @@ -246,13 +246,11 @@ class OpenDeclarationsJob extends Job implements ASTRunnable { final IASTNodeSelector nodeSelector = ast.getNodeSelector(null); - IASTName sourceName= nodeSelector.findEnclosingName(selectionStart, selectionLength); + IASTName sourceName = nodeSelector.findEnclosingName(selectionStart, selectionLength); IName[] implicitTargets = findImplicitTargets(ast, nodeSelector, selectionStart, selectionLength); - if (sourceName == null) { - if (implicitTargets.length > 0) { - if (navigateViaCElements(fTranslationUnit.getCProject(), fIndex, implicitTargets)) - return Status.OK_STATUS; - } + if (sourceName == null || SemanticUtil.isAutoOrDecltype(fSelectedText)) { + if (navigateViaCElements(fTranslationUnit.getCProject(), fIndex, implicitTargets)) + return Status.OK_STATUS; } else { boolean found= false; final IASTNode parent = sourceName.getParent(); @@ -479,28 +477,21 @@ class OpenDeclarationsJob extends Job implements ASTRunnable { definitions = ArrayUtil.addAll(definitions, declNames); } } - } else { + } else if (SemanticUtil.isAutoOrDecltype(fSelectedText)) { IASTNode enclosingNode = nodeSelector.findEnclosingNode(offset, length); - if (enclosingNode instanceof ICPPASTSimpleDeclSpecifier) { - if (((ICPPASTSimpleDeclSpecifier) enclosingNode).getType() == ICPPASTSimpleDeclSpecifier.t_auto) { - if (enclosingNode.getParent() instanceof IASTSimpleDeclaration) { - IASTDeclarator[] declarators = ((IASTSimpleDeclaration) enclosingNode.getParent()).getDeclarators(); - if (declarators.length > 0) { - // It's invalid for different declarators to deduce different - // types with 'auto', so just get the type based on the first - // declarator. - IType type = CPPVisitor.createType(declarators[0]); - // Strip qualifiers, references, and pointers, but NOT - // typedefs, since for typedefs we want to navigate to the - // typedef declaration. - type = SemanticUtil.getNestedType(type, CVTYPE | REF | PTR); - if (type instanceof IBinding) { - IName[] declNames = findDeclNames(ast, NameKind.REFERENCE, (IBinding) type); - definitions = ArrayUtil.addAll(definitions, declNames); - } - } - } - } + IType type = CPPSemantics.resolveDecltypeOrAutoType(enclosingNode); + if (type instanceof ICPPUnknownType) { + IType hType = HeuristicResolver.resolveUnknownType((ICPPUnknownType) type, enclosingNode); + if (hType != null) + type = hType; + } + // Strip qualifiers, references, and pointers, but NOT + // typedefs, since for typedefs we want to refer to the + // typedef declaration. + type = SemanticUtil.getNestedType(type, CVTYPE | REF | PTR); + if (type instanceof IBinding) { + IName[] declNames = findDeclNames(ast, NameKind.REFERENCE, (IBinding) type); + definitions = ArrayUtil.addAll(definitions, declNames); } } return ArrayUtil.trim(definitions); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java index 53d78cfa6f5..a64990de9d7 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java @@ -53,7 +53,6 @@ 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; @@ -76,11 +75,9 @@ 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.ICPPASTTemplateId; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplateInstance; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; @@ -94,7 +91,6 @@ 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; @@ -103,8 +99,12 @@ import org.eclipse.cdt.ui.text.ICPartitions; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.HeuristicResolver; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.TypeOfDependentExpression; import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; import org.eclipse.cdt.internal.corext.util.Strings; @@ -161,33 +161,12 @@ public class CSourceHover extends AbstractCEditorTextHover { if (ast != null) { try { 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); - } + if (SemanticUtil.isAutoOrDecltype(fSelection)) { + IASTNode node = nodeSelector.findEnclosingNode(fTextRegion.getOffset(), + fTextRegion.getLength()); + IType type = CPPSemantics.resolveDecltypeOrAutoType(node); + if (type != null && !(type instanceof IProblemType)) + fSource = ASTTypeUtil.getType(type, false); } else { IASTName name= nodeSelector.findEnclosingName(fTextRegion.getOffset(), fTextRegion.getLength()); if (name != null) { @@ -742,8 +721,8 @@ public class CSourceHover extends AbstractCEditorTextHover { return null; // 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)) + // over a keyword other than 'auto', 'decltype' or 'typeof'. + if (selectionIsKeyword(expression) && !SemanticUtil.isAutoOrDecltype(expression)) return null; // Try with the indexer.