1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-06 17:26:01 +02:00

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
This commit is contained in:
Nathan Ridge 2016-12-12 01:21:35 -05:00
parent e31d51988d
commit cf46cbf117
7 changed files with 118 additions and 20 deletions

View file

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

View file

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

View file

@ -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 {

View file

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

View file

@ -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<Definition> 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<IASTProblem> 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()) {

View file

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

View file

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