From 8956d2c7e6e1227083f39df6f9121db9cdd92bff Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Thu, 12 Jan 2017 23:04:43 -0500 Subject: [PATCH] Bug 72809 - Improve content assist inside inactive code Change-Id: If24e354d00aaf886da1571fc525b556e08c94897 --- .../cdt/core/dom/ast/INodeFactory.java | 9 ++- .../parser/AbstractGNUSourceCodeParser.java | 18 +++++- .../parser/IASTInactiveCompletionName.java | 17 ++++++ .../parser/c/CASTInactiveCompletionName.java | 56 +++++++++++++++++++ .../core/dom/parser/c/CNodeFactory.java | 6 ++ .../cpp/CPPASTInactiveCompletionName.java | 47 ++++++++++++++++ .../core/dom/parser/cpp/CPPNodeFactory.java | 7 +++ .../parser/cpp/semantics/CPPSemantics.java | 26 ++++++++- .../internal/core/parser/scanner/Lexer.java | 2 +- .../text/contentassist2/CompletionTests.java | 10 ++++ .../CompletionTests_PlainC.java | 10 ++++ .../contentassist2/HelpProposalTests.java | 9 +++ .../DOMCompletionProposalComputer.java | 6 +- .../HelpCompletionProposalComputer.java | 8 ++- 14 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IASTInactiveCompletionName.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTInactiveCompletionName.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInactiveCompletionName.java diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java index 80c3668e7ff..b19af914f6a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/INodeFactory.java @@ -19,6 +19,7 @@ import org.eclipse.cdt.core.dom.ast.gnu.IGCCASTAttributeList; import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; /** * Factory for creating AST nodes. This interface contains factory methods @@ -133,6 +134,12 @@ public interface INodeFactory { public IASTIfStatement newIfStatement(IASTExpression condition, IASTStatement then, IASTStatement elseClause); + /** + * @since 6.3 + * @noreference This method is not intended to be referenced by clients. + */ + public IASTInactiveCompletionName newInactiveCompletionName(char[] name, IASTTranslationUnit ast); + public IASTInitializerList newInitializerList(); public IASTLabelStatement newLabelStatement(IASTName name, IASTStatement nestedStatement); @@ -148,7 +155,7 @@ public interface INodeFactory { /** @since 5.11 */ public IASTName newName(String name); - + public IASTNullStatement newNullStatement(); public IASTParameterDeclaration newParameterDeclaration(IASTDeclSpecifier declSpec, IASTDeclarator declarator); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 348f77dca8a..d90b8680f0d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -295,7 +295,23 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } catch (OffsetLimitReachedException olre) { if (mode != ParserMode.COMPLETION_PARSE) throw new EndOfFileException(olre.getEndOffset()); - createCompletionNode(olre.getFinalToken()); + IToken completionToken = olre.getFinalToken(); + createCompletionNode(completionToken); + if (olre.getOriginator() == OffsetLimitReachedException.ORIGIN_INACTIVE_CODE) { + // If completion is invoked inside inactive code, there is no AST from which + // to give the completion node a completion name, so we invent a name. + // The invented name is not hooked up to the AST, but does have an offset + // and length, so it can provide an accurate point of reference in + // declaredBefore(). + IASTName completionName = nodeFactory.newInactiveCompletionName( + completionToken.getCharImage(), getTranslationUnit()); + ((ASTNode) completionName).setOffsetAndLength(completionToken.getOffset(), + completionToken.getLength()); + completionNode.addName(completionName); + + // Consume the completion token so we don't try to parse an AST fragment from it. + consume(); + } throw olre; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IASTInactiveCompletionName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IASTInactiveCompletionName.java new file mode 100644 index 00000000000..72ed676a1f6 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/IASTInactiveCompletionName.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser; + +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +import org.eclipse.cdt.core.dom.ast.IASTName; + +/** + * Interface for a name representing a prefix being completed inside inactive code. + */ +public interface IASTInactiveCompletionName extends IASTName, IASTCompletionContext { +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTInactiveCompletionName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTInactiveCompletionName.java new file mode 100644 index 00000000000..d0e049b0c83 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTInactiveCompletionName.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.c; + +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +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.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; + +public class CASTInactiveCompletionName extends CASTName implements IASTInactiveCompletionName { + private IASTTranslationUnit fAst; + + public CASTInactiveCompletionName(char[] name, IASTTranslationUnit ast) { + super(name); + fAst = ast; + } + + @Override + public IASTCompletionContext getCompletionContext() { + return this; + } + + @Override + public IBinding[] findBindings(IASTName name, boolean isPrefix) { + // 'name' (which is the same as 'this') is not hooked up to the AST, but it + // does have a location (offset and length) which we use to compute the + // containing scope. + IASTNodeSelector sel = fAst.getNodeSelector(null); + IASTNode node = sel.findEnclosingNode(getOffset(), getLength()); + IScope lookupScope = CVisitor.getContainingScope(node); + if (lookupScope == null) { + lookupScope = fAst.getScope(); + } + IBinding[] result = null; + try { + if (isPrefix) { + result = CVisitor.lookupPrefix(lookupScope, name); + } else { + result = new IBinding[] { CVisitor.lookup(lookupScope, name) }; + } + } catch (DOMException e) { + } + return ArrayUtil.trim(IBinding.class, result); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java index 4a81d8f03b4..5cc846e6f35 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CNodeFactory.java @@ -87,6 +87,7 @@ import org.eclipse.cdt.core.dom.ast.gnu.c.IGCCASTArrayRangeDesignator; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.internal.core.dom.parser.ASTToken; import org.eclipse.cdt.internal.core.dom.parser.ASTTokenList; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; import org.eclipse.cdt.internal.core.dom.parser.NodeFactory; import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor; @@ -328,6 +329,11 @@ public class CNodeFactory extends NodeFactory implements ICNodeFactory { return new CASTIfStatement(expr, thenStat, elseClause); } + @Override + public IASTInactiveCompletionName newInactiveCompletionName(char[] name, IASTTranslationUnit ast) { + return new CASTInactiveCompletionName(name, ast); + } + @Override @Deprecated public org.eclipse.cdt.core.dom.ast.IASTInitializerExpression newInitializerExpression(IASTExpression expression) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInactiveCompletionName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInactiveCompletionName.java new file mode 100644 index 00000000000..90f6af68905 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInactiveCompletionName.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +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.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; + +public class CPPASTInactiveCompletionName extends CPPASTName implements IASTInactiveCompletionName { + private IASTTranslationUnit fAst; + + public CPPASTInactiveCompletionName(char[] name, IASTTranslationUnit ast) { + super(name); + fAst = ast; + } + + @Override + public IASTCompletionContext getCompletionContext() { + return this; + } + + @Override + public IBinding[] findBindings(IASTName name, boolean isPrefix) { + // 'name' (which is the same as 'this') is not hooked up to the AST, but it + // does have a location (offset and length) which we use to compute the + // containing scope. + IASTNodeSelector sel = fAst.getNodeSelector(null); + IASTNode node = sel.findEnclosingNode(getOffset(), getLength()); + IScope lookupScope = CPPVisitor.getContainingScope(node); + if (lookupScope == null) { + lookupScope = fAst.getScope(); + } + return CPPSemantics.findBindingsForContentAssist(name.getLookupKey(), isPrefix, lookupScope, name); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java index 2492e217808..e06ec2566ff 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java @@ -52,6 +52,7 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTToken; import org.eclipse.cdt.core.dom.ast.IASTTokenList; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdInitializerExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration; @@ -138,6 +139,7 @@ import org.eclipse.cdt.core.dom.parser.cpp.ICPPASTAttributeSpecifier; import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.internal.core.dom.parser.ASTToken; import org.eclipse.cdt.internal.core.dom.parser.ASTTokenList; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; import org.eclipse.cdt.internal.core.dom.parser.NodeFactory; import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor; @@ -511,6 +513,11 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory { return new CPPASTIfStatement(condition, then, elseClause); } + @Override + public IASTInactiveCompletionName newInactiveCompletionName(char[] name, IASTTranslationUnit ast) { + return new CPPASTInactiveCompletionName(name, ast); + } + @Override @Deprecated public org.eclipse.cdt.core.dom.ast.IASTInitializerExpression newInitializerExpression(IASTExpression expression) { 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 3eb9d85df60..4a301a5ecf7 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 @@ -3933,7 +3933,27 @@ public class CPPSemantics { } return contentAssistLookup(data, nsScopes); } - + + /** + * Similar to {@link CPPSemantics#findBindingsForContentAssist(IASTName, boolean, String[])}, + * but in lieu of a name hooked up to the AST, accepts just a string, a position in the file + * (represented as an IASTNode, and used to serve as the point of reference for the lookup), + * and a starting scope (which is required). + */ + public static IBinding[] findBindingsForContentAssist(char[] name, boolean prefixLookup, + IScope lookupScope, IASTNode point) { + LookupData data = new LookupData(name, null, point); + data.contentAssist = true; + data.fHeuristicBaseLookup = true; + data.setPrefixLookup(prefixLookup); + data.foundItems = new CharArrayObjectMap<>(2); + try { + CPPSemantics.lookup(data, lookupScope); + } catch (DOMException e) { + } + return collectContentAssistBindings(data); + } + private static IScope getLookupScope(IASTNode node) { if (node == null) return null; @@ -4082,6 +4102,10 @@ public class CPPSemantics { } } catch (DOMException e) { } + return collectContentAssistBindings(data); + } + + private static IBinding[] collectContentAssistBindings(LookupData data) { @SuppressWarnings("unchecked") CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; IBinding[] result = IBinding.EMPTY_BINDING_ARRAY; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java index 894350a30ca..99b1872cd86 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java @@ -244,7 +244,7 @@ final public class Lexer implements ITokenSequence { t0= t1; t1= fetchToken(); final int tt1 = t1.getType(); - if (tt1 == IToken.tEND_OF_INPUT) + if (tt1 == IToken.tEND_OF_INPUT || tt1 == IToken.tCOMPLETION) break; if (tt1 == IToken.tPOUND) { final int tt0= t0.getType(); 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 aa0f913e862..2a954648500 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 @@ -483,6 +483,16 @@ public class CompletionTests extends CompletionTestBase { final String[] expected= { "defined" }; assertCompletionResults(fCursorOffset, expected, ID); } + + // int waldo; + // void foo() { + // #ifdef SOME_UNDEFINED_MACRO + // wald/*cursor*/ + // #endif + // } + public void testInactiveCodeBlock_72809() throws Exception { + assertCompletionResults(new String[] { "waldo" }); + } //void gfunc(){TClass t(0); t.a/*cursor*/ public void testTemplateClassMethod() throws Exception { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java index 46f3547672b..c450c7bb045 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java @@ -387,6 +387,16 @@ public class CompletionTests_PlainC extends AbstractContentAssistTest { assertCompletionResults(expected); } + // int waldo; + // void foo() { + // #ifdef SOME_UNDEFINED_MACRO + // wald/*cursor*/ + // #endif + // } + public void testInactiveCodeBlock_72809() throws Exception { + assertCompletionResults(new String[] { "waldo" }); + } + //void fooFunction() //{ // AStructType* c; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/HelpProposalTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/HelpProposalTests.java index 67e5fe7aa02..c0441eb472b 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/HelpProposalTests.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/HelpProposalTests.java @@ -70,4 +70,13 @@ public class HelpProposalTests extends CompletionTestBase { String[] expected = new String[] { "Waldo(const Waldo &)", "Waldo(int, int)" }; assertCompletionResults(fCursorOffset, expected, ID); } + + // void foo() { + // #ifdef MYMACRO + // setv/*cursor*/ + // #endif + // } + public void testInactiveCodeBlock_72809() throws Exception { + assertCompletionResults(new String[] { "setvbuf()" }); + } } 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 152814a9621..bdf4c766438 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 @@ -97,6 +97,7 @@ import org.eclipse.cdt.ui.text.ICPartitions; 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.IASTInactiveCompletionName; import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinParameter; import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinVariable; import org.eclipse.cdt.internal.core.dom.parser.c.CImplicitFunction; @@ -162,8 +163,11 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer IASTName[] names = completionNode.getNames(); for (IASTName name : names) { - if (name.getTranslationUnit() == null) { + 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 + // (because there is no AST for the inactive code), but we still want to + // attempt completion for them. continue; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/HelpCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/HelpCompletionProposalComputer.java index 4be7afc935c..cc1e7f4bd21 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/HelpCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/HelpCompletionProposalComputer.java @@ -29,6 +29,8 @@ import org.eclipse.cdt.ui.IFunctionSummary; import org.eclipse.cdt.ui.text.ICHelpInvocationContext; import org.eclipse.cdt.ui.text.IContentAssistHelpInvocationContext; +import org.eclipse.cdt.internal.core.dom.parser.IASTInactiveCompletionName; + import org.eclipse.cdt.internal.ui.CHelpProviderManager; import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider; @@ -46,8 +48,10 @@ public class HelpCompletionProposalComputer extends ParsingBasedProposalComputer for (int i = 0; i < names.length; ++i) { IASTName name = names[i]; - // ignore if not connected - if (name.getTranslationUnit() == null) + // Ignore if not connected. + // See the corresponding code in DOMCompletionProposalComputer for why + // inactive completion names are special. + if (name.getTranslationUnit() == null && !(name instanceof IASTInactiveCompletionName)) continue; // ignore if this is a member access