Skip to content

Commit

Permalink
Bug 522010 - Completion of non-type template parameter in ambiguous t…
Browse files Browse the repository at this point in the history
…emplate 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
  • Loading branch information
HighCommander4 committed Nov 13, 2017
1 parent b090f32 commit 301de3d
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/
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) {
Expand All @@ -29,7 +29,7 @@ public ASTCompletionNode(IToken completionToken, IASTTranslationUnit translation
}

public void addName(IASTName name) {
names.add(name);
entries.add(new CompletionNameEntry(name, name.getParent()));
}

@Override
Expand All @@ -42,9 +42,28 @@ public int getLength() {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@
* @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.
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand Down Expand Up @@ -785,6 +786,14 @@ private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileExc
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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2032,4 +2032,12 @@ public void testPartialSpecializationWithDeferredClassInstance_456224a() throws
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" });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@
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;
Expand Down Expand Up @@ -160,9 +162,10 @@ protected List<ICompletionProposal> computeCompletionProposals(CContentAssistInv
}
} 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
Expand All @@ -171,7 +174,7 @@ protected List<ICompletionProposal> computeCompletionProposals(CContentAssistInv
continue;
}

IASTCompletionContext astContext = name.getCompletionContext();
IASTCompletionContext astContext = getCompletionContext(name, entry.fParent);
if (astContext == null) {
continue;
} else if (astContext instanceof IASTIdExpression
Expand Down Expand Up @@ -203,6 +206,13 @@ protected List<ICompletionProposal> computeCompletionProposals(CContentAssistInv
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -38,7 +38,7 @@
*/
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;
Expand All @@ -62,7 +62,7 @@ public ASTCompletionNode(String prefix) {


public void addName(IASTName name) {
names.add(name);
entries.add(new CompletionNameEntry(name, name.getParent()));
}


Expand All @@ -77,7 +77,11 @@ public int getLength() {

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


Expand All @@ -100,6 +104,19 @@ public void setTranslationUnit(IASTTranslationUnit tu) {
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()]);
}
}

0 comments on commit 301de3d

Please sign in to comment.