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