1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 06:02:11 +02:00

Bug 522010 - Completion of non-type template parameter in ambiguous template argument

This works around the fact that the optimization introduced in bug 316704
inteferes with the mechanism for offering completions for both alternatives
in an ambiguous context.

Change-Id: Ibe14c1b4f2f9c9b3394d4635c87424a25fbd7a53
This commit is contained in:
Nathan Ridge 2017-11-05 21:06:42 -05:00
parent b090f32e64
commit 301de3d40e
6 changed files with 111 additions and 11 deletions

View file

@ -20,7 +20,7 @@ import org.eclipse.cdt.core.parser.IToken;
*/
public class ASTCompletionNode implements IASTCompletionNode {
private final IToken completionToken;
private final List<IASTName> names = new ArrayList<>();
private final List<CompletionNameEntry> 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

View file

@ -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,11 +57,29 @@ 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.
*/

View file

@ -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);
}
}
}

View file

@ -2032,4 +2032,12 @@ public class CompletionTests extends CompletionTestBase {
public void testPartialSpecializationWithDeferredClassInstance_456224b() throws Exception {
assertCompletionResults(new String[] { "Result" });
}
// template<int TestParam>
// struct A {
// using type_t = A<Te/*cursor*/>
// };
public void testNonTypeTemplateParameterCompletion_522010() throws Exception {
assertCompletionResults(new String[] { "TestParam" });
}
}

View file

@ -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.
*

View file

@ -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<IASTName> names = new LinkedList<IASTName>();
private final List<CompletionNameEntry> 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;
}
@ -101,5 +105,18 @@ public class ASTCompletionNode implements IASTCompletionNode {
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()]);
}
}