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:
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.
|
||||
* 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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue