mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 17:56: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:
parent
e31d51988d
commit
cf46cbf117
7 changed files with 118 additions and 20 deletions
|
@ -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.
|
* 204.0 - Do not store return expression in index, follow-up to bug 490475.
|
||||||
* 205.0 - Reworked storage of annotations, bug 505832.
|
* 205.0 - Reworked storage of annotations, bug 505832.
|
||||||
* 206.0 - DependentValue split out from IntegralValue.
|
* 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 MIN_SUPPORTED_VERSION= version(207, 0);
|
||||||
private static final int MAX_SUPPORTED_VERSION= version(206, Short.MAX_VALUE);
|
private static final int MAX_SUPPORTED_VERSION= version(207, Short.MAX_VALUE);
|
||||||
private static final int DEFAULT_VERSION = version(206, 0);
|
private static final int DEFAULT_VERSION = version(207, 0);
|
||||||
|
|
||||||
private static int version(int major, int minor) {
|
private static int version(int major, int minor) {
|
||||||
return (major << 16) + minor;
|
return (major << 16) + minor;
|
||||||
|
|
|
@ -505,6 +505,11 @@ public abstract class PDOMWriter implements IPDOMASTProcessor {
|
||||||
ast.accept(visitor);
|
ast.accept(visitor);
|
||||||
|
|
||||||
if ((fSkipReferences & SKIP_MACRO_REFERENCES) == 0) {
|
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);
|
LocationMap lm= ast.getAdapter(LocationMap.class);
|
||||||
if (lm != null) {
|
if (lm != null) {
|
||||||
IASTName[] refs= lm.getMacroReferences();
|
IASTName[] refs= lm.getMacroReferences();
|
||||||
|
@ -512,7 +517,9 @@ public abstract class PDOMWriter implements IPDOMASTProcessor {
|
||||||
IASTFileLocation nameLoc = name.getFileLocation();
|
IASTFileLocation nameLoc = name.getFileLocation();
|
||||||
if (nameLoc != null) {
|
if (nameLoc != null) {
|
||||||
IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement();
|
IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement();
|
||||||
symbols.add(owner, name, null);
|
IASTName enclosingDefinition = definitionTree.search(nameLoc.getNodeOffset(),
|
||||||
|
nameLoc.getNodeLength());
|
||||||
|
symbols.add(owner, name, enclosingDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
try {
|
try {
|
||||||
if (binding instanceof IMacroBinding
|
if (binding instanceof IMacroBinding
|
||||||
|| (binding == null && name.getPropertyInParent() == IASTPreprocessorStatement.MACRO_NAME)) {
|
|| (binding == null && name.getPropertyInParent() == IASTPreprocessorStatement.MACRO_NAME)) {
|
||||||
return createPDOMMacroReferenceName(linkage, name);
|
return createPDOMMacroReferenceName(linkage, name, caller);
|
||||||
}
|
}
|
||||||
PDOMBinding pdomBinding = linkage.addBinding(name);
|
PDOMBinding pdomBinding = linkage.addBinding(name);
|
||||||
if (pdomBinding != null) {
|
if (pdomBinding != null) {
|
||||||
|
@ -529,9 +529,10 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
return null;
|
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());
|
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 {
|
public void clear() throws CoreException {
|
||||||
|
|
|
@ -42,11 +42,12 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil
|
||||||
private static final int CONTAINER_NEXT_OFFSET = 16;
|
private static final int CONTAINER_NEXT_OFFSET = 16;
|
||||||
private static final int NODE_OFFSET_OFFSET = 20;
|
private static final int NODE_OFFSET_OFFSET = 20;
|
||||||
private static final int NODE_LENGTH_OFFSET = 24;
|
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,
|
public PDOMMacroReferenceName(PDOMLinkage linkage, IASTName name, PDOMFile file,
|
||||||
PDOMMacroContainer container) throws CoreException {
|
PDOMMacroContainer container, PDOMName caller) throws CoreException {
|
||||||
this.linkage = linkage;
|
this.linkage = linkage;
|
||||||
Database db = linkage.getDB();
|
Database db = linkage.getDB();
|
||||||
record = db.malloc(RECORD_SIZE);
|
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.putInt(record + NODE_OFFSET_OFFSET, fileloc.getNodeOffset());
|
||||||
db.putShort(record + NODE_LENGTH_OFFSET, (short) fileloc.getNodeLength());
|
db.putShort(record + NODE_LENGTH_OFFSET, (short) fileloc.getNodeLength());
|
||||||
container.addReference(this);
|
container.addReference(this);
|
||||||
|
|
||||||
|
if (caller != null) {
|
||||||
|
db.putRecPtr(record + CALLER_REC_OFFSET, caller.getRecord());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PDOMMacroReferenceName(PDOMLinkage linkage, long nameRecord) {
|
public PDOMMacroReferenceName(PDOMLinkage linkage, long nameRecord) {
|
||||||
|
@ -296,6 +301,7 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName, IASTFil
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IIndexName getEnclosingDefinition() throws CoreException {
|
public IIndexName getEnclosingDefinition() throws CoreException {
|
||||||
return null;
|
long namerec = linkage.getDB().getRecPtr(record + CALLER_REC_OFFSET);
|
||||||
|
return namerec != 0 ? new PDOMName(linkage, namerec) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.ICPPASTFunctionDeclarator;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
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.ASTQueries;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||||
|
|
||||||
abstract public class IndexerASTVisitor extends ASTVisitor {
|
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) {
|
Definition(IASTName name, IASTNode node) {
|
||||||
fName= name;
|
fName= name;
|
||||||
fNode= node;
|
fNode= node;
|
||||||
}
|
}
|
||||||
IASTName fName;
|
IASTName fName; // The name of the entity being defined.
|
||||||
IASTNode fNode;
|
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;
|
private IASTName fDefinitionName;
|
||||||
|
@ -61,6 +98,9 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
|
||||||
shouldVisitDeclSpecifiers= true;
|
shouldVisitDeclSpecifiers= true;
|
||||||
shouldVisitProblems= true;
|
shouldVisitProblems= true;
|
||||||
shouldVisitExpressions= true;
|
shouldVisitExpressions= true;
|
||||||
|
|
||||||
|
// Root node representing the entire file
|
||||||
|
fStack.add(new Definition(null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IASTProblem> getProblems() {
|
public List<IASTProblem> getProblems() {
|
||||||
|
@ -80,9 +120,14 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void push(IASTName name, IASTNode node) {
|
private void push(IASTName name, IASTNode node) {
|
||||||
if (fDefinitionName != null) {
|
assert !fStack.isEmpty();
|
||||||
fStack.add(new Definition(fDefinitionName, fDefinitionNode));
|
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);
|
name = getLastInQualified(name);
|
||||||
fDefinitionName= name;
|
fDefinitionName= name;
|
||||||
fDefinitionNode= node;
|
fDefinitionNode= node;
|
||||||
|
@ -94,12 +139,14 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
|
||||||
|
|
||||||
private void pop(IASTNode node) {
|
private void pop(IASTNode node) {
|
||||||
if (node == fDefinitionNode) {
|
if (node == fDefinitionNode) {
|
||||||
|
assert !fStack.isEmpty();
|
||||||
|
fStack.remove(fStack.size() - 1);
|
||||||
if (fStack.isEmpty()) {
|
if (fStack.isEmpty()) {
|
||||||
fDefinitionName= null;
|
fDefinitionName= null;
|
||||||
fDefinitionNode= null;
|
fDefinitionNode= null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Definition old= fStack.remove(fStack.size()-1);
|
Definition old= fStack.get(fStack.size()-1);
|
||||||
fDefinitionName= old.fName;
|
fDefinitionName= old.fName;
|
||||||
fDefinitionNode= old.fNode;
|
fDefinitionNode= old.fNode;
|
||||||
}
|
}
|
||||||
|
@ -200,6 +247,11 @@ abstract public class IndexerASTVisitor extends ASTVisitor {
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Definition getDefinitionTree() {
|
||||||
|
assert !fStack.isEmpty();
|
||||||
|
return fStack.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
private int visit(final ICPPASTLambdaExpression lambdaExpr) {
|
private int visit(final ICPPASTLambdaExpression lambdaExpr) {
|
||||||
// Captures
|
// Captures
|
||||||
for (ICPPASTCapture cap : lambdaExpr.getCaptures()) {
|
for (ICPPASTCapture cap : lambdaExpr.getCaptures()) {
|
||||||
|
|
|
@ -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.editor.CEditor;
|
||||||
import org.eclipse.cdt.internal.ui.search.CSearchQuery;
|
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.CSearchTextSelectionQuery;
|
||||||
|
import org.eclipse.cdt.internal.ui.search.LineSearchElement;
|
||||||
|
import org.eclipse.cdt.internal.ui.search.LineSearchElement.Match;
|
||||||
|
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
@ -70,4 +73,26 @@ public class FindReferencesTest extends SearchTestBase {
|
||||||
CSearchQuery query = makeProjectQuery(offset, 5);
|
CSearchQuery query = makeProjectQuery(offset, 5);
|
||||||
assertOccurrences(query, 1);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,9 +56,13 @@ public abstract class SearchTestBase extends BaseUITestCase {
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertOccurrences(CSearchQuery query, int expected) {
|
protected CSearchResult getSearchResult(CSearchQuery query) {
|
||||||
query.run(npm());
|
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());
|
assertEquals(expected, result.getMatchCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue