diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTNodeSelectorTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTNodeSelectorTest.java
index 00514d9e301..b5e76d31cf9 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTNodeSelectorTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTNodeSelectorTest.java
@@ -427,4 +427,12 @@ public class ASTNodeSelectorTest extends AST2BaseTest {
testContainedNode(x1-1, x1+2, "O");
}
+ // #define MACRO void m
+ // MACRO();
+ public void testEnclosingAMacro() {
+ int x1= fCode.indexOf("MACRO(");
+ int x2= x1 + "MACRO(".length();
+ testContainedName(x1, x2, "MACRO");
+ testEnclosingNode(x1, x2, "MACRO();");
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNodeSelector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNodeSelector.java
index 0f304633edb..5583793598f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNodeSelector.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTNodeSelector.java
@@ -15,6 +15,7 @@ package org.eclipse.cdt.core.dom.ast;
* for one file contained in a translation-unit, can be obtained using
* {@link IASTTranslationUnit#getNodeSelector(String)}.
*
+ * @noimplement This interface is not intended to be implemented by clients.
* @since 5.0
*/
public interface IASTNodeSelector {
@@ -59,6 +60,33 @@ public interface IASTNodeSelector {
*/
IASTNode findFirstContainedNode(int offset, int length);
+ /**
+ * Returns the node for the exact given range, or null
if there is no such node.
+ *
+ * The method never returns a macro expansion ({@link IASTPreprocessorMacroExpansion}) or the name for
+ * an expansion. Rather than that the expansion itself is searched for a matching node.
+ * @since 5.1
+ */
+ IASTNode findNodeInExpansion(int offset, int length);
+
+ /**
+ * Returns the smallest node enclosing the range, or null
if there is no such node.
+ *
+ * The method never returns a macro expansion ({@link IASTPreprocessorMacroExpansion}) or the name for
+ * an expansion. Rather than that the expansion itself is searched for a matching node.
+ * @since 5.1
+ */
+ IASTNode findEnclosingNodeInExpansion(int offset, int length);
+
+ /**
+ * Returns the first node contained in the given expansion, or null
if there is no such node.
+ *
+ * The method never returns a macro expansion ({@link IASTPreprocessorMacroExpansion}) or the name for
+ * an expansion. Rather than that the expansion itself is searched for a matching node.
+ * @since 5.1
+ */
+ IASTNode findFirstContainedNodeInExpansion(int offset, int length);
+
/**
* Returns a macro expansion enclosing the given range, or null
.
*/
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java
index f41a78e031e..9309ac30e04 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
@@ -45,10 +46,15 @@ public class ASTNodeSelector implements IASTNodeSelector {
return false;
}
+ private T findNode(int offsetInFile, int lengthInFile, Relation relation, Class requiredClass) {
+ return findNode(offsetInFile, lengthInFile, relation, requiredClass, false);
+ }
+
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getNode(int, int)
*/
- private T findNode(int offsetInFile, int lengthInFile, Relation relation, Class requiredClass) {
+ private T findNode(int offsetInFile, int lengthInFile, Relation relation,
+ Class requiredClass, boolean searchInExpansion) {
if (!fIsValid) {
return null;
}
@@ -79,10 +85,11 @@ public class ASTNodeSelector implements IASTNodeSelector {
}
}
final ASTNodeSpecification nodeSpec= new ASTNodeSpecification(relation, requiredClass, offsetInFile, lengthInFile);
- nodeSpec.setRangeInSequence(sequenceNumber, sequenceLength);
+ nodeSpec.setRangeInSequence(sequenceNumber, sequenceLength, false);
+ nodeSpec.setSearchInExpansion(searchInExpansion);
getNode(nodeSpec);
if (altSequenceNumber != -1) {
- nodeSpec.setRangeInSequence(altSequenceNumber, sequenceLength);
+ nodeSpec.setRangeInSequence(altSequenceNumber, sequenceLength, true);
getNode(nodeSpec);
}
return nodeSpec.getBestNode();
@@ -91,6 +98,21 @@ public class ASTNodeSelector implements IASTNodeSelector {
private T getNode(ASTNodeSpecification nodeSpec) {
fLocationResolver.findPreprocessorNode(nodeSpec);
if (!nodeSpec.requiresClass(IASTPreprocessorMacroExpansion.class)) {
+ // adjust sequence number for search in the expansion of macros
+ int seqbegin= nodeSpec.getSequenceStart();
+ int seqend= nodeSpec.getSequenceEnd();
+ IASTPreprocessorMacroExpansion expansion= nodeSpec.findLeadingMacroExpansion(this);
+ if (expansion != null) {
+ IASTFileLocation floc= expansion.getFileLocation();
+ seqbegin= fLocationResolver.getSequenceNumberForFileOffset(fFilePath, floc.getNodeOffset() + floc.getNodeLength()-1)+1;
+ }
+ expansion= nodeSpec.findTrailingMacroExpansion(this);
+ if (expansion != null) {
+ IASTFileLocation floc= expansion.getFileLocation();
+ seqend= fLocationResolver.getSequenceNumberForFileOffset(fFilePath, floc.getNodeOffset() + floc.getNodeLength())-1;
+ }
+ nodeSpec.setRangeInSequence(seqbegin, seqend-seqbegin);
+
FindNodeForOffsetAction nodeFinder= new FindNodeForOffsetAction(nodeSpec);
fTu.accept(nodeFinder);
}
@@ -117,7 +139,28 @@ public class ASTNodeSelector implements IASTNodeSelector {
public IASTNode findEnclosingNode(int offset, int length) {
return findNode(offset, length, Relation.ENCLOSING, IASTNode.class);
}
-
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getFirstContainedNode(int, int)
+ */
+ public IASTNode findFirstContainedNodeInExpansion(int offset, int length) {
+ return findNode(offset, length, Relation.FIRST_CONTAINED, IASTNode.class, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getNode(int, int)
+ */
+ public IASTNode findNodeInExpansion(int offset, int length) {
+ return findNode(offset, length, Relation.EXACT_MATCH, IASTNode.class, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getSurroundingNode(int, int)
+ */
+ public IASTNode findEnclosingNodeInExpansion(int offset, int length) {
+ return findNode(offset, length, Relation.ENCLOSING, IASTNode.class, true);
+ }
+
/* (non-Javadoc)
* @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getFirstContainedNode(int, int)
*/
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSpecification.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSpecification.java
index d0ba18aa31b..ffa994ab2fd 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSpecification.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSpecification.java
@@ -12,7 +12,9 @@ package org.eclipse.cdt.internal.core.dom.parser;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
+import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
/**
* For searching ast-nodes by offset and length, instances of this class can be used to
@@ -32,6 +34,8 @@ public class ASTNodeSpecification {
private int fBestOffset;
private int fBestEndOffset;
private T fBestNode;
+ private boolean fSearchInExpansion;
+ private boolean fZeroToLeft= false;
public ASTNodeSpecification(Relation relation, Class clazz, int fileOffset, int fileLength) {
fRelation= relation;
@@ -39,12 +43,21 @@ public class ASTNodeSpecification {
fFileOffset= fileOffset;
fFileEndOffset= fileOffset+fileLength;
}
-
+
public void setRangeInSequence(int offsetInSeq, int lengthInSeq) {
fSeqNumber= offsetInSeq;
fSeqEndNumber= offsetInSeq+lengthInSeq;
}
+
+ public void setRangeInSequence(int offsetInSeq, int lengthInSeq, boolean zeroRangeToLeft) {
+ setRangeInSequence(offsetInSeq, lengthInSeq);
+ fZeroToLeft= zeroRangeToLeft;
+ }
+ public void setSearchInExpansion(boolean searchInExpansion) {
+ fSearchInExpansion= searchInExpansion;
+ }
+
public Relation getRelationToSelection() {
return fRelation;
}
@@ -99,7 +112,16 @@ public class ASTNodeSpecification {
}
public boolean isAcceptableNode(IASTNode astNode) {
- return astNode != null && fClass.isAssignableFrom(astNode.getClass());
+ if (astNode == null || !fClass.isAssignableFrom(astNode.getClass()))
+ return false;
+
+ if (fSearchInExpansion) {
+ IASTNode check= astNode instanceof IASTName ? astNode.getParent() : astNode;
+ if (check instanceof IASTPreprocessorMacroExpansion) {
+ return false;
+ }
+ }
+ return true;
}
/**
@@ -177,4 +199,12 @@ public class ASTNodeSpecification {
}
return false;
}
+
+ public IASTPreprocessorMacroExpansion findLeadingMacroExpansion(ASTNodeSelector nodeSelector) {
+ return nodeSelector.findEnclosingMacroExpansion(fZeroToLeft ? fFileOffset-1 : fFileOffset, 1);
+ }
+
+ public IASTPreprocessorMacroExpansion findTrailingMacroExpansion(ASTNodeSelector nodeSelector) {
+ return nodeSelector.findEnclosingMacroExpansion(fZeroToLeft ? fFileEndOffset : fFileEndOffset-1, 1);
+ }
}
\ No newline at end of file
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
index ce76be4612e..91f4ff55ade 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
@@ -137,7 +137,8 @@ class LocationCtxContainer extends LocationCtx {
addFileLocation(offset, endSequenceNumber-sequenceNumber, locations);
return true;
}
- addFileLocation(offset, child.fOffsetInParent-offset, locations);
+ if (offset < child.fOffsetInParent)
+ addFileLocation(offset, child.fOffsetInParent-offset, locations);
sequenceNumber= child.fSequenceNumber;
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/callhierarchy/CallHierarchyBugs.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/callhierarchy/CallHierarchyBugs.java
index ae423f5d01b..022472194be 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/callhierarchy/CallHierarchyBugs.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/callhierarchy/CallHierarchyBugs.java
@@ -337,4 +337,34 @@ public class CallHierarchyBugs extends CallHierarchyBaseTest {
}
+ // #define MACRO(name) void PREFIX_ ## name(char *a , char *b)
+ // #define CALL(x) call(x)
+ //
+ // void call(int);
+ // MACRO(Test) {
+ // CALL(0);
+ // }
+ public void testMacrosHidingCall_249801() throws Exception {
+ String content= getContentsForTest(1)[0].toString();
+ IFile file= createFile(getProject(), "file249801.cpp", content);
+ waitForIndexer(fIndex, file, CallHierarchyBaseTest.INDEXER_WAIT_TIME);
+
+ final CHViewPart ch= (CHViewPart) activateView(CUIPlugin.ID_CALL_HIERARCHY);
+ final IWorkbenchWindow workbenchWindow = ch.getSite().getWorkbenchWindow();
+
+ // open editor, check outline
+ CEditor editor= openEditor(file);
+ int idx = content.indexOf("MACRO(Test");
+ editor.selectAndReveal(idx, 0);
+ openCallHierarchy(editor, false);
+
+ Tree chTree= checkTreeNode(ch, 0, "PREFIX_Test(char *, char *)").getParent();
+ TreeItem ti= checkTreeNode(chTree, 0, 0, "call(int)");
+
+ idx = content.indexOf("CALL(0");
+ editor.selectAndReveal(idx+4, 0);
+ openCallHierarchy(editor, true);
+ chTree= checkTreeNode(ch, 0, "call(int)").getParent();
+ ti= checkTreeNode(chTree, 0, 0, "PREFIX_Test(char *, char *)");
+ }
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTest_SingleName_NoPrefix.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTest_SingleName_NoPrefix.java
index 4b8c51c0335..187744188f7 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTest_SingleName_NoPrefix.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTest_SingleName_NoPrefix.java
@@ -39,6 +39,9 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
"xOtherClass",
"AStruct",
"XStruct",
+ "__FUNCTION__ : const char *",
+ "__PRETTY_FUNCTION__ : const char *",
+ "__func__ : const char *",
"aNamespace",
"xNamespace",
"anEnumeration",
@@ -65,6 +68,7 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getCompletionPosition()
*/
+ @Override
protected int getCompletionPosition() {
return getBuffer().indexOf(" ") + 2;
}
@@ -72,6 +76,7 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getExpectedPrefix()
*/
+ @Override
protected String getExpectedPrefix() {
return expectedPrefix;
}
@@ -79,6 +84,7 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getExpectedResultsValues()
*/
+ @Override
protected String[] getExpectedResultsValues() {
return expectedResults;
}
@@ -86,6 +92,7 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getFileName()
*/
+ @Override
protected String getFileName() {
return fileName;
}
@@ -93,12 +100,14 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getFileFullPath()
*/
+ @Override
protected String getFileFullPath() {
return fileFullPath;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getHeaderFileFullPath()
*/
+ @Override
protected String getHeaderFileFullPath() {
return headerFileFullPath;
}
@@ -106,6 +115,7 @@ public class CompletionTest_SingleName_NoPrefix extends CompletionProposalsBase
/* (non-Javadoc)
* @see org.eclipse.cdt.core.codeassist.tests.CompletionProposalsTest#getHeaderFileName()
*/
+ @Override
protected String getHeaderFileName() {
return headerFileName;
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/IndexUI.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/IndexUI.java
index 1346017323c..d88e4d0e52f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/IndexUI.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/IndexUI.java
@@ -32,8 +32,17 @@ import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IPositionConverter;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
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.IASTPreprocessorMacroExpansion;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
@@ -70,6 +79,7 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IWorkingCopy;
import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
import org.eclipse.cdt.internal.core.model.ext.CElementHandleFactory;
import org.eclipse.cdt.internal.core.model.ext.ICElementHandle;
@@ -386,7 +396,34 @@ public class IndexUI {
ASTProvider.getASTProvider().runOnAST(workingCopy, ASTProvider.WAIT_YES, null, new ASTRunnable() {
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
if (ast != null) {
- result[0]= ast.getNodeSelector(null).findEnclosingName(offset, length);
+ final IASTNodeSelector nodeSelector = ast.getNodeSelector(null);
+ IASTName name= nodeSelector.findEnclosingName(offset, length);
+ if (name != null && name.getParent() instanceof IASTPreprocessorMacroExpansion) {
+ IASTFileLocation floc= name.getParent().getFileLocation();
+ IASTNode node= nodeSelector.findEnclosingNodeInExpansion(floc.getNodeOffset(), floc.getNodeLength());
+ if (node instanceof IASTName) {
+ name= (IASTName) node;
+ } else if (node instanceof IASTFunctionCallExpression){
+ IASTExpression expr= ((IASTFunctionCallExpression) node).getFunctionNameExpression();
+ if (expr instanceof IASTIdExpression) {
+ name= ((IASTIdExpression) expr).getName();
+ }
+ } else {
+ if (node instanceof IASTSimpleDeclaration) {
+ IASTNode[] dtors= ((IASTSimpleDeclaration) node).getDeclarators();
+ if (dtors != null && dtors.length > 0) {
+ node= dtors[0];
+ }
+ } else if (node instanceof IASTFunctionDefinition) {
+ node= ((IASTFunctionDefinition) node).getDeclarator();
+ }
+ if (node instanceof IASTDeclarator) {
+ IASTDeclarator dtor= CPPVisitor.findTypeRelevantDeclarator((IASTDeclarator) node);
+ name= dtor.getName();
+ }
+ }
+ }
+ result[0]= name;
}
return Status.OK_STATUS;
}