From cf46cbf117bc0e3b7bd334d785de0b56e079ab00 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Mon, 12 Dec 2016 01:21:35 -0500 Subject: [PATCH] Bug 508216 - Enclosing definition for macro reference name Compute and store in the index an enclosing definition for macro reference names. This allows showing the enclosing definition when such a name appears in a search result. Change-Id: I91eee4ad80c86d7ef90c69c1436387393fca2a19 --- .../eclipse/cdt/internal/core/pdom/PDOM.java | 9 ++- .../cdt/internal/core/pdom/PDOMWriter.java | 11 +++- .../cdt/internal/core/pdom/dom/PDOMFile.java | 7 +- .../core/pdom/dom/PDOMMacroReferenceName.java | 12 +++- .../core/pdom/indexer/IndexerASTVisitor.java | 66 +++++++++++++++++-- .../ui/tests/search/FindReferencesTest.java | 25 +++++++ .../cdt/ui/tests/search/SearchTestBase.java | 8 ++- 7 files changed, 118 insertions(+), 20 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index e86f25ffe89..1f02d646a29 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -278,10 +278,13 @@ public class PDOM extends PlatformObject implements IPDOM { * 204.0 - Do not store return expression in index, follow-up to bug 490475. * 205.0 - Reworked storage of annotations, bug 505832. * 206.0 - DependentValue split out from IntegralValue. + * + * CDT 9.3 development (versions not supported on the 9.2.x branch) + * 207.0 - Store a caller record for macro reference names. */ - private static final int MIN_SUPPORTED_VERSION= version(206, 0); - private static final int MAX_SUPPORTED_VERSION= version(206, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(206, 0); + private static final int MIN_SUPPORTED_VERSION= version(207, 0); + private static final int MAX_SUPPORTED_VERSION= version(207, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(207, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java index 4ca5d94b10c..44b2f42bbf7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java @@ -503,8 +503,13 @@ public abstract class PDOMWriter implements IPDOMASTProcessor { } }; ast.accept(visitor); - + if ((fSkipReferences & SKIP_MACRO_REFERENCES) == 0) { + + // Get a tree of definitions built by IndexerASTVisitor during its traversal. + // This is used to find enclosing definitions for macro references. + IndexerASTVisitor.Definition definitionTree = visitor.getDefinitionTree(); + LocationMap lm= ast.getAdapter(LocationMap.class); if (lm != null) { IASTName[] refs= lm.getMacroReferences(); @@ -512,7 +517,9 @@ public abstract class PDOMWriter implements IPDOMASTProcessor { IASTFileLocation nameLoc = name.getFileLocation(); if (nameLoc != null) { IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement(); - symbols.add(owner, name, null); + IASTName enclosingDefinition = definitionTree.search(nameLoc.getNodeOffset(), + nameLoc.getNodeLength()); + symbols.add(owner, name, enclosingDefinition); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java index 83818f5084e..b7f20283ebf 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java @@ -510,7 +510,7 @@ public class PDOMFile implements IIndexFragmentFile { try { if (binding instanceof IMacroBinding || (binding == null && name.getPropertyInParent() == IASTPreprocessorStatement.MACRO_NAME)) { - return createPDOMMacroReferenceName(linkage, name); + return createPDOMMacroReferenceName(linkage, name, caller); } PDOMBinding pdomBinding = linkage.addBinding(name); if (pdomBinding != null) { @@ -529,9 +529,10 @@ public class PDOMFile implements IIndexFragmentFile { return null; } - private IIndexFragmentName createPDOMMacroReferenceName(PDOMLinkage linkage, IASTName name) throws CoreException { + private IIndexFragmentName createPDOMMacroReferenceName(PDOMLinkage linkage, IASTName name, + PDOMName caller) throws CoreException { PDOMMacroContainer cont= linkage.getMacroContainer(name.getSimpleID()); - return new PDOMMacroReferenceName(fLinkage, name, this, cont); + return new PDOMMacroReferenceName(fLinkage, name, this, cont, caller); } public void clear() throws CoreException { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java index da498af685c..489f319a015 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java @@ -42,11 +42,12 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil private static final int CONTAINER_NEXT_OFFSET = 16; private static final int NODE_OFFSET_OFFSET = 20; private static final int NODE_LENGTH_OFFSET = 24; + private static final int CALLER_REC_OFFSET = 26; - private static final int RECORD_SIZE = 26; + private static final int RECORD_SIZE = 30; // 30 yields a 32-byte block. (31 would trigger a 40-byte block) public PDOMMacroReferenceName(PDOMLinkage linkage, IASTName name, PDOMFile file, - PDOMMacroContainer container) throws CoreException { + PDOMMacroContainer container, PDOMName caller) throws CoreException { this.linkage = linkage; Database db = linkage.getDB(); record = db.malloc(RECORD_SIZE); @@ -59,6 +60,10 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil db.putInt(record + NODE_OFFSET_OFFSET, fileloc.getNodeOffset()); db.putShort(record + NODE_LENGTH_OFFSET, (short) fileloc.getNodeLength()); container.addReference(this); + + if (caller != null) { + db.putRecPtr(record + CALLER_REC_OFFSET, caller.getRecord()); + } } public PDOMMacroReferenceName(PDOMLinkage linkage, long nameRecord) { @@ -296,6 +301,7 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil @Override public IIndexName getEnclosingDefinition() throws CoreException { - return null; + long namerec = linkage.getDB().getRecPtr(record + CALLER_REC_OFFSET); + return namerec != 0 ? new PDOMName(linkage, namerec) : null; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java index 79d56e6af7d..4dd1aa86f5d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java @@ -35,17 +35,54 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +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.cpp.semantics.CPPVisitor; abstract public class IndexerASTVisitor extends ASTVisitor { - private static class Definition { + /** + * Represents a definition of a class or function. + * IndexerASTVisitor builds a tree of these definitions, used for tracking enclosing + * definitions of names. + */ + public static class Definition { Definition(IASTName name, IASTNode node) { fName= name; fNode= node; } - IASTName fName; - IASTNode fNode; + IASTName fName; // The name of the entity being defined. + IASTNode fNode; // The AST node for the entire definition. + List fChildren; // Definitions contained within this one. + + /** + * Search the subtree of definitions rooted at this one for the nearest + * definition that encloses the range defined by 'offset' and 'length'. + * The name of the resulting definition is returned. + * This function assumes that 'this.matches(offset, length)' is true. + */ + public IASTName search(int offset, int length) { + if (fChildren != null) { + for (Definition child : fChildren) { + if (child.matches(offset, length)) { + return child.search(offset, length); + } + } + } + return fName; + } + + /** + * Check whether this definition encloses the range defined by 'offset' and 'length'. + */ + boolean matches(int offset, int length) { + if (!(fNode instanceof ASTNode)) { + return false; + } + ASTNode node = (ASTNode) fNode; + int nodeOffset = node.getOffset(); + int nodeLength = node.getLength(); + return nodeOffset <= offset && (nodeOffset + nodeLength) >= (offset + length); + } } private IASTName fDefinitionName; @@ -61,6 +98,9 @@ abstract public class IndexerASTVisitor extends ASTVisitor { shouldVisitDeclSpecifiers= true; shouldVisitProblems= true; shouldVisitExpressions= true; + + // Root node representing the entire file + fStack.add(new Definition(null, null)); } public List getProblems() { @@ -80,9 +120,14 @@ abstract public class IndexerASTVisitor extends ASTVisitor { } private void push(IASTName name, IASTNode node) { - if (fDefinitionName != null) { - fStack.add(new Definition(fDefinitionName, fDefinitionNode)); + assert !fStack.isEmpty(); + Definition def = new Definition(name, node); + Definition parent = fStack.get(fStack.size() - 1); + if (parent.fChildren == null) { + parent.fChildren = new ArrayList<>(); } + parent.fChildren.add(def); + fStack.add(def); name = getLastInQualified(name); fDefinitionName= name; fDefinitionNode= node; @@ -94,12 +139,14 @@ abstract public class IndexerASTVisitor extends ASTVisitor { private void pop(IASTNode node) { if (node == fDefinitionNode) { + assert !fStack.isEmpty(); + fStack.remove(fStack.size() - 1); if (fStack.isEmpty()) { fDefinitionName= null; fDefinitionNode= null; } else { - Definition old= fStack.remove(fStack.size()-1); + Definition old= fStack.get(fStack.size()-1); fDefinitionName= old.fName; fDefinitionNode= old.fNode; } @@ -199,7 +246,12 @@ abstract public class IndexerASTVisitor extends ASTVisitor { } return PROCESS_CONTINUE; } - + + public Definition getDefinitionTree() { + assert !fStack.isEmpty(); + return fStack.get(0); + } + private int visit(final ICPPASTLambdaExpression lambdaExpr) { // Captures for (ICPPASTCapture cap : lambdaExpr.getCaptures()) { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/FindReferencesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/FindReferencesTest.java index b2b61ce9aed..491f2c043b6 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/FindReferencesTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/FindReferencesTest.java @@ -20,7 +20,10 @@ import org.eclipse.cdt.ui.testplugin.EditorTestHelper; import org.eclipse.cdt.internal.ui.editor.CEditor; import org.eclipse.cdt.internal.ui.search.CSearchQuery; +import org.eclipse.cdt.internal.ui.search.CSearchResult; import org.eclipse.cdt.internal.ui.search.CSearchTextSelectionQuery; +import org.eclipse.cdt.internal.ui.search.LineSearchElement; +import org.eclipse.cdt.internal.ui.search.LineSearchElement.Match; import junit.framework.TestSuite; @@ -70,4 +73,26 @@ public class FindReferencesTest extends SearchTestBase { CSearchQuery query = makeProjectQuery(offset, 5); assertOccurrences(query, 1); } + + + // #define waldo() + // + // struct S { + // void foo() { + // waldo(); + // } + // }; + + // // empty file + public void testEnclosingDefinitionOfMacroReference_508216() throws Exception { + int offset = fHeaderContents.indexOf("define waldo") + 7; + CSearchQuery query = makeProjectQuery(offset, 5); + CSearchResult result = getSearchResult(query); + Object[] elements = result.getElements(); + assertEquals(1, elements.length); + assertInstance(elements[0], LineSearchElement.class); + Match[] matches = ((LineSearchElement) elements[0]).getMatches(); + assertEquals(1, matches.length); + assertNotNull(matches[0].getEnclosingElement()); + } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/SearchTestBase.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/SearchTestBase.java index 272706458a3..4c294fd225b 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/SearchTestBase.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/SearchTestBase.java @@ -56,9 +56,13 @@ public abstract class SearchTestBase extends BaseUITestCase { super.tearDown(); } - protected void assertOccurrences(CSearchQuery query, int expected) { + protected CSearchResult getSearchResult(CSearchQuery query) { query.run(npm()); - CSearchResult result= (CSearchResult) query.getSearchResult(); + return (CSearchResult) query.getSearchResult(); + } + + protected void assertOccurrences(CSearchQuery query, int expected) { + CSearchResult result= getSearchResult(query); assertEquals(expected, result.getMatchCount()); } }