diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTCompletionNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTCompletionNode.java index 607379e3d8f..733ecf946bc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTCompletionNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTCompletionNode.java @@ -20,7 +20,7 @@ import org.eclipse.cdt.core.parser.IToken; */ public class ASTCompletionNode implements IASTCompletionNode { private final IToken completionToken; - private final List names = new ArrayList<>(); + private final List entries = new ArrayList<>(); private final IASTTranslationUnit translationUnit; public ASTCompletionNode(IToken completionToken, IASTTranslationUnit translationUnit) { @@ -29,7 +29,7 @@ public class ASTCompletionNode implements IASTCompletionNode { } public void addName(IASTName name) { - names.add(name); + entries.add(new CompletionNameEntry(name, name.getParent())); } @Override @@ -42,9 +42,28 @@ public class ASTCompletionNode implements IASTCompletionNode { return completionToken.getLength(); } + @Override + public boolean containsName(IASTName name) { + for (CompletionNameEntry entry : entries) { + if (entry.fName == name) { + return true; + } + } + return false; + } + @Override public IASTName[] getNames() { - return names.toArray(new IASTName[names.size()]); + IASTName[] names = new IASTName[entries.size()]; + for (int i = 0; i < entries.size(); ++i) { + names[i] = entries.get(i).fName; + } + return names; + } + + @Override + public CompletionNameEntry[] getEntries() { + return entries.toArray(new CompletionNameEntry[entries.size()]); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTCompletionNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTCompletionNode.java index 237b49d38ee..8c9d983ae32 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTCompletionNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTCompletionNode.java @@ -25,6 +25,25 @@ package org.eclipse.cdt.core.dom.ast; * @noimplement This interface is not intended to be implemented by clients. */ public interface IASTCompletionNode { + /** + * Represents a name that fits in this context, and its parent. + * The parent is stored separately because two entries can have + * the same name but different parents. (This is due to the + * parser sometimes re-using nodes between alternatives in an + * ambiguous node.) + * + * @since 6.4 + */ + public class CompletionNameEntry { + public CompletionNameEntry(IASTName name, IASTNode parent) { + fName = name; + fParent = parent; + } + + public IASTName fName; + public IASTNode fParent; + } + /** * If the point of completion was at the end of a potential identifier, this * string contains the text of that identifier. @@ -38,10 +57,28 @@ public interface IASTCompletionNode { */ public int getLength(); + /** + * Returns true if this completion node contains a {@link CompletionNameEntry} + * with the given name. + * + * @since 6.4 + */ + public boolean containsName(IASTName name); + /** * Returns a list of names that fit in this context. + * If doing computations based on the name's parent, prefer calling getEntries() instead + * and obtaining the parent from there. */ public IASTName[] getNames(); + + /** + * Returns a list of names that fir in this context, along with their parents. + * See {@link CompletionNameEntry} for more details. + * + * @since 6.4 + */ + public CompletionNameEntry[] getEntries(); /** * Returns the translation unit for this completion. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index a2b01fec885..2fc22a307cb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.eclipse.cdt.core.dom.ast.ASTCompletionNode; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTAlignmentSpecifier; @@ -785,6 +786,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { name = namedTypeSpec.getName(); if (name.contains(typeId)) { idExpression = setRange(getNodeFactory().newIdExpression(name), name); + + // If the name was one of the completion names, add it to the completion + // node again now that it has a new parent. This ensures that completion + // proposals are offered for both contexts that the name appears in. + ASTCompletionNode completionNode = (ASTCompletionNode) getCompletionNode(); + if (completionNode != null && completionNode.containsName(name)) { + completionNode.addName(name); + } } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java index ebe55719a8f..59cf69b2312 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java @@ -2032,4 +2032,12 @@ public class CompletionTests extends CompletionTestBase { public void testPartialSpecializationWithDeferredClassInstance_456224b() throws Exception { assertCompletionResults(new String[] { "Result" }); } + + // template + // struct A { + // using type_t = A + // }; + public void testNonTypeTemplateParameterCompletion_522010() throws Exception { + assertCompletionResults(new String[] { "TestParam" }); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java index 71f17585c8d..8016c3db7a7 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java @@ -36,11 +36,13 @@ import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.swt.graphics.Image; import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.ASTCompletionNode; import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; +import org.eclipse.cdt.core.dom.ast.IASTCompletionNode.CompletionNameEntry; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionStyleMacroParameter; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; @@ -160,9 +162,10 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer } } else { boolean handleMacros= false; - IASTName[] names = completionNode.getNames(); + CompletionNameEntry[] entries = ((ASTCompletionNode) completionNode).getEntries(); - for (IASTName name : names) { + for (CompletionNameEntry entry : entries) { + IASTName name = entry.fName; if (name.getTranslationUnit() == null && !(name instanceof IASTInactiveCompletionName)) { // The node isn't properly hooked up, must have backtracked out of this node. // Inactive completion names are special in that they are not hooked up @@ -171,7 +174,7 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer continue; } - IASTCompletionContext astContext = name.getCompletionContext(); + IASTCompletionContext astContext = getCompletionContext(name, entry.fParent); if (astContext == null) { continue; } else if (astContext instanceof IASTIdExpression @@ -203,6 +206,13 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer return proposals; } + private static IASTCompletionContext getCompletionContext(IASTName name, IASTNode parent) { + if (parent instanceof IASTCompletionContext) { + return (IASTCompletionContext) parent; + } + return name.getCompletionContext(); + } + /** * Checks whether the invocation offset is inside or before the preprocessor directive keyword. * diff --git a/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/ASTCompletionNode.java b/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/ASTCompletionNode.java index 6ac50613317..b021de30609 100644 --- a/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/ASTCompletionNode.java +++ b/lrparser/org.eclipse.cdt.core.lrparser/src/org/eclipse/cdt/core/dom/lrparser/action/ASTCompletionNode.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.cdt.core.dom.lrparser.action; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; @@ -38,7 +38,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; */ public class ASTCompletionNode implements IASTCompletionNode { - private final List names = new LinkedList(); + private final List entries = new ArrayList<>(); private final String prefix; private IASTTranslationUnit tu; @@ -62,7 +62,7 @@ public class ASTCompletionNode implements IASTCompletionNode { public void addName(IASTName name) { - names.add(name); + entries.add(new CompletionNameEntry(name, name.getParent())); } @@ -77,7 +77,11 @@ public class ASTCompletionNode implements IASTCompletionNode { @Override public IASTName[] getNames() { - return names.toArray(new IASTName[names.size()]); + IASTName[] names = new IASTName[entries.size()]; + for (int i = 0; i < entries.size(); ++i) { + names[i] = entries.get(i).fName; + } + return names; } @@ -100,6 +104,19 @@ public class ASTCompletionNode implements IASTCompletionNode { public IASTTranslationUnit getTranslationUnit() { return tu; } - + @Override + public boolean containsName(IASTName name) { + for (CompletionNameEntry entry : entries) { + if (entry.fName == name) { + return true; + } + } + return false; + } + + @Override + public CompletionNameEntry[] getEntries() { + return entries.toArray(new CompletionNameEntry[entries.size()]); + } }