1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 422681: Allow references to bindings in other linkages

The existing PDOMBinding and PDOMName implementations do not allow
references between linkages.  This feature is needed so that the new Qt
linkage can reference elements in the C++ linkage.  It will also allow
the C++ implementation for extern "C" to be cleaned up (see
PDOM.getCrossLanguageBindings).

Prior to this change, a PDOMBinding held three lists of names.  One for
each of declarations, definitions, and references.  This change adds a
fourth list for external references.  External references are stored as
a linked list of nodes.  Each node holds:

    - The linkage id.
    - A pointer to the next node (or 0 for end-of-list).
    - A pointer to the record of first name in the list.

The linkage id is held separately because a PDOMName does not have any
field of it's own for linkage.  By grouping elements in this way, we can
reuse most of the existing list-related code.

External references are accessed through a new PDOMIterator class.  This
is needed so that we can advance to the next linkage node when we get to
the end of one node's list of names.

This also adds a unit test for the new API.

Change-Id: Ie2b14848db7409905beda0cec752080d5f42eec8
Signed-off-by: Andrew Eidsness <eclipse@jfront.com>
Reviewed-on: https://git.eclipse.org/r/18979
Tested-by: Hudson CI
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
Andrew Eidsness 2013-11-27 09:44:16 -05:00 committed by Doug Schaefer
parent a205557db0
commit f887c8e671
9 changed files with 422 additions and 49 deletions

View file

@ -12,6 +12,7 @@
package org.eclipse.cdt.internal.pdom.tests; package org.eclipse.cdt.internal.pdom.tests;
import java.io.File; import java.io.File;
import java.util.regex.Pattern;
import junit.framework.Test; import junit.framework.Test;
@ -49,11 +50,11 @@ import org.eclipse.core.runtime.NullProgressMonitor;
*/ */
public class PDOMCPPBugsTest extends BaseTestCase { public class PDOMCPPBugsTest extends BaseTestCase {
ICProject cproject; ICProject cproject;
public static Test suite() { public static Test suite() {
return suite(PDOMCPPBugsTest.class); return suite(PDOMCPPBugsTest.class);
} }
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
@ -74,6 +75,7 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.acquireWriteLock(0); pdom.acquireWriteLock(0);
try { try {
WritablePDOM wpdom = (WritablePDOM) pdom; WritablePDOM wpdom = (WritablePDOM) pdom;
IIndexBinding[] b = wpdom.findBindings(Pattern.compile(".+"), false, IndexFilter.ALL, null);
wpdom.setProperty("a", "b"); wpdom.setProperty("a", "b");
assertEquals("b", wpdom.getProperty("a")); assertEquals("b", wpdom.getProperty("a"));
wpdom.setProperty("c", "d"); wpdom.setProperty("c", "d");
@ -84,16 +86,16 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.releaseWriteLock(0, true); pdom.releaseWriteLock(0, true);
} }
} }
public void testProjectPDOMProperties() throws Exception { public void testProjectPDOMProperties() throws Exception {
PDOM pdom = (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject); PDOM pdom = (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject);
pdom.acquireReadLock(); pdom.acquireReadLock();
try { try {
String id= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID); String id= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID);
assertNotNull(id); assertNotNull(id);
CCoreInternals.getPDOMManager().reindex(cproject); CCoreInternals.getPDOMManager().reindex(cproject);
String id2= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID); String id2= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID);
assertNotNull(id2); assertNotNull(id2);
assertEquals(id, id2); assertEquals(id, id2);
@ -101,33 +103,33 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.releaseReadLock(); pdom.releaseReadLock();
} }
} }
public void testProjectPDOMPropertiesOnExport() throws Exception { public void testProjectPDOMPropertiesOnExport() throws Exception {
// this test is currently failing on the cdt test build machine, but // this test is currently failing on the cdt test build machine, but
// not on my local linux or windows boxes. // not on my local linux or windows boxes.
File tmp= new File(System.getProperty("java.io.tmpdir")+"/temp"+System.currentTimeMillis()+".pdom"); File tmp= new File(System.getProperty("java.io.tmpdir")+"/temp"+System.currentTimeMillis()+".pdom");
IIndexLocationConverter cvr= new ResourceContainerRelativeLocationConverter(cproject.getProject()); IIndexLocationConverter cvr= new ResourceContainerRelativeLocationConverter(cproject.getProject());
final PDOMManager pdomManager = CCoreInternals.getPDOMManager(); final PDOMManager pdomManager = CCoreInternals.getPDOMManager();
pdomManager.exportProjectPDOM(cproject, tmp, cvr); pdomManager.exportProjectPDOM(cproject, tmp, cvr);
IWritableIndexFragment pdom = new WritablePDOM(tmp, cvr, new ChunkCache(), LanguageManager.getInstance().getPDOMLinkageFactoryMappings()); IWritableIndexFragment pdom = new WritablePDOM(tmp, cvr, new ChunkCache(), LanguageManager.getInstance().getPDOMLinkageFactoryMappings());
pdom.acquireReadLock(); pdom.acquireReadLock();
try { try {
String id= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID); String id= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID);
assertNotNull("Exported pdom ID is null", id); assertNotNull("Exported pdom ID is null", id);
String id2 = getFragmentID(cproject); String id2 = getFragmentID(cproject);
assertNotNull("Project pdom ID is null", id2); assertNotNull("Project pdom ID is null", id2);
assertFalse("Project pdom ID equals export PDOM id", id2.equals(id)); assertFalse("Project pdom ID equals export PDOM id", id2.equals(id));
pdomManager.reindex(cproject); pdomManager.reindex(cproject);
waitForIndexer(cproject); waitForIndexer(cproject);
String id3= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID); String id3= pdom.getProperty(IIndexFragment.PROPERTY_FRAGMENT_ID);
assertNotNull("Exported pdom ID is null after project reindex", id3); assertNotNull("Exported pdom ID is null after project reindex", id3);
assertEquals("Exported pdom ID hasChanged during reindex", id, id3); assertEquals("Exported pdom ID hasChanged during reindex", id, id3);
String id4= getFragmentID(cproject); String id4= getFragmentID(cproject);
assertNotNull("Reindexed project pdom ID is null", id4); assertNotNull("Reindexed project pdom ID is null", id4);
assertFalse("Reindexex project pdom ID equals exported pdom ID", id4.equals(id)); assertFalse("Reindexex project pdom ID equals exported pdom ID", id4.equals(id));
@ -149,7 +151,7 @@ public class PDOMCPPBugsTest extends BaseTestCase {
} }
return id2; return id2;
} }
public void testInterruptingAcquireReadLock() throws Exception { public void testInterruptingAcquireReadLock() throws Exception {
final PDOM pdom= (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject); final PDOM pdom= (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject);
final boolean[] ok= {false}; final boolean[] ok= {false};
@ -162,7 +164,7 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.acquireReadLock(); pdom.acquireReadLock();
} catch (InterruptedException e) { } catch (InterruptedException e) {
ok[0]= true; ok[0]= true;
} }
} }
}; };
other.start(); other.start();
@ -176,7 +178,7 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.acquireWriteLock(); pdom.acquireWriteLock();
pdom.releaseWriteLock(); pdom.releaseWriteLock();
} }
public void testInterruptingAcquireWriteLock() throws Exception { public void testInterruptingAcquireWriteLock() throws Exception {
final WritablePDOM pdom= (WritablePDOM) CCoreInternals.getPDOMManager().getPDOM(cproject); final WritablePDOM pdom= (WritablePDOM) CCoreInternals.getPDOMManager().getPDOM(cproject);
final boolean[] ok= {false}; final boolean[] ok= {false};
@ -191,7 +193,7 @@ public class PDOMCPPBugsTest extends BaseTestCase {
} catch (InterruptedException e) { } catch (InterruptedException e) {
ok[0]= true; ok[0]= true;
pdom.releaseReadLock(); pdom.releaseReadLock();
} }
} }
}; };
other.start(); other.start();
@ -205,20 +207,20 @@ public class PDOMCPPBugsTest extends BaseTestCase {
pdom.acquireWriteLock(); pdom.acquireWriteLock();
pdom.releaseWriteLock(); pdom.releaseWriteLock();
} }
public void test191679() throws Exception { public void test191679() throws Exception {
IProject project= cproject.getProject(); IProject project= cproject.getProject();
IFolder cHeaders= cproject.getProject().getFolder("cHeaders"); IFolder cHeaders= cproject.getProject().getFolder("cHeaders");
cHeaders.create(true, true, npm()); cHeaders.create(true, true, npm());
LanguageManager lm= LanguageManager.getInstance(); LanguageManager lm= LanguageManager.getInstance();
IFile cHeader= TestSourceReader.createFile(cHeaders, "cSource.c", "void foo(int i){}"); IFile cHeader= TestSourceReader.createFile(cHeaders, "cSource.c", "void foo(int i){}");
IFile cppSource= TestSourceReader.createFile(cHeaders, "cppSource.cpp", "extern \"C\" void foo(int i); void ref() {foo(1);}"); IFile cppSource= TestSourceReader.createFile(cHeaders, "cppSource.cpp", "extern \"C\" void foo(int i); void ref() {foo(1);}");
IndexerPreferences.set(project, IndexerPreferences.KEY_INDEXER_ID, IPDOMManager.ID_FAST_INDEXER); IndexerPreferences.set(project, IndexerPreferences.KEY_INDEXER_ID, IPDOMManager.ID_FAST_INDEXER);
CCorePlugin.getIndexManager().reindex(cproject); CCorePlugin.getIndexManager().reindex(cproject);
waitForIndexer(cproject); waitForIndexer(cproject);
final PDOM pdom= (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject); final PDOM pdom= (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject);
pdom.acquireReadLock(); pdom.acquireReadLock();
try { try {
@ -230,17 +232,17 @@ public class PDOMCPPBugsTest extends BaseTestCase {
} }
assertTrue(ib[0] instanceof IFunction); assertTrue(ib[0] instanceof IFunction);
assertFalse(ib[0] instanceof ICPPBinding); assertFalse(ib[0] instanceof ICPPBinding);
assertTrue(ib[1] instanceof IFunction); assertTrue(ib[1] instanceof IFunction);
assertTrue(ib[1] instanceof ICPPBinding); assertTrue(ib[1] instanceof ICPPBinding);
IName[] nms= pdom.findNames(ib[0], IIndexFragment.FIND_REFERENCES | IIndexFragment.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); IName[] nms= pdom.findNames(ib[0], IIndexFragment.FIND_REFERENCES | IIndexFragment.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
assertEquals(1, nms.length); assertEquals(1, nms.length);
assertTrue(nms[0].getFileLocation().getFileName().endsWith(".cpp")); assertTrue(nms[0].getFileLocation().getFileName().endsWith(".cpp"));
nms= pdom.findNames(ib[0], IIndexFragment.FIND_REFERENCES); nms= pdom.findNames(ib[0], IIndexFragment.FIND_REFERENCES);
assertEquals(0, nms.length); assertEquals(0, nms.length);
nms= pdom.findNames(ib[1], IIndexFragment.FIND_DEFINITIONS | IIndexFragment.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); nms= pdom.findNames(ib[1], IIndexFragment.FIND_DEFINITIONS | IIndexFragment.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
assertEquals(1, nms.length); assertEquals(1, nms.length);
assertTrue(nms[0].getFileLocation().getFileName().endsWith(".c")); assertTrue(nms[0].getFileLocation().getFileName().endsWith(".c"));

View file

@ -0,0 +1,105 @@
package org.eclipse.cdt.internal.pdom.tests;
import junit.framework.Test;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.NullProgressMonitor;
public class PDOMNameTests extends BaseTestCase {
private ICProject cproject;
public static Test suite() {
return suite(PDOMNameTests.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
cproject= CProjectHelper.createCCProject("PDOMNameTest"+System.currentTimeMillis(), "bin", IPDOMManager.ID_FAST_INDEXER);
waitForIndexer(cproject);
}
@Override
protected void tearDown() throws Exception {
if (cproject != null) {
cproject.getProject().delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, new NullProgressMonitor());
}
super.tearDown();
}
public void testExternalReferences() throws Exception {
IProject project = cproject.getProject();
TestSourceReader.createFile(project, "file.cpp", "extern void func_cpp() { func_cpp(); }");
TestSourceReader.createFile(project, "file.c", "extern void func_c() { func_c(); }");
IndexerPreferences.set(project, IndexerPreferences.KEY_INDEXER_ID, IPDOMManager.ID_FAST_INDEXER);
CCorePlugin.getIndexManager().reindex(cproject);
waitForIndexer(cproject);
PDOM pdom = (PDOM) CCoreInternals.getPDOMManager().getPDOM(cproject);
pdom.acquireWriteLock();
try {
IIndexBinding[] bindings = pdom.findBindings(new char[][]{"func_cpp".toCharArray()}, IndexFilter.ALL, npm());
assertEquals(1, bindings.length);
assertTrue(bindings[0] instanceof PDOMBinding);
PDOMBinding binding_cpp = (PDOMBinding) bindings[0];
PDOMName name_cpp = binding_cpp.getFirstReference();
assertNotNull(name_cpp);
assertSame(binding_cpp.getLinkage(), name_cpp.getLinkage());
bindings = pdom.findBindings(new char[][]{"func_c".toCharArray()}, IndexFilter.ALL, npm());
assertEquals(1, bindings.length);
assertTrue(bindings[0] instanceof PDOMBinding);
PDOMBinding binding_c = (PDOMBinding) bindings[0];
PDOMName name_c = binding_c.getFirstReference();
assertNotNull(name_c);
assertSame(binding_c.getLinkage(), name_c.getLinkage());
// Check that the external references list is currently empty.
IPDOMIterator<PDOMName> extNames = binding_cpp.getExternalReferences();
assertNotNull(extNames);
assertFalse(extNames.hasNext());
// Make sure the C++ binding and the C name are in different linkages, then add the name
// as an external reference of the binding.
assertNotSame(binding_cpp.getLinkage(), name_c.getLinkage());
binding_cpp.addReference(name_c);
// Make sure there is an external reference, then retrieve it. Then make sure there
// aren't anymore external references.
extNames = binding_cpp.getExternalReferences();
assertNotNull(extNames);
assertTrue(extNames.hasNext());
PDOMName extRef = extNames.next();
assertNotNull(extRef);
assertFalse(extNames.hasNext());
// Check that the external reference is the same as the C name that was added, that the
// external reference does not have the same linkage as the binding, and that it does
// have the same linkage as the initial name.
assertSame(name_c.getLinkage(), extRef.getLinkage());
assertEquals(name_c.getRecord(), extRef.getRecord());
assertNotSame(binding_cpp.getLinkage(), extRef.getLinkage());
assertSame(binding_c.getLinkage(), extRef.getLinkage());
} finally {
pdom.releaseWriteLock();
}
}
}

View file

@ -30,6 +30,7 @@ public class PDOMTests extends TestSuite {
suite.addTest(PDOMCPPBugsTest.suite()); suite.addTest(PDOMCPPBugsTest.suite());
suite.addTest(PDOMSearchTest.suite()); suite.addTest(PDOMSearchTest.suite());
suite.addTest(PDOMLocationTests.suite()); suite.addTest(PDOMLocationTests.suite());
suite.addTest(PDOMNameTests.suite());
suite.addTest(PDOMProviderTests.suite()); suite.addTest(PDOMProviderTests.suite());
suite.addTest(EnumerationTests.suite()); suite.addTest(EnumerationTests.suite());
suite.addTest(ClassTests.suite()); suite.addTest(ClassTests.suite());

View file

@ -76,6 +76,7 @@ import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector; import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector;
import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; import org.eclipse.cdt.internal.core.pdom.dom.FindBinding;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerCollector; import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerCollector;
import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerPatternCollector; import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerPatternCollector;
@ -242,10 +243,11 @@ public class PDOM extends PlatformObject implements IPDOM {
* *
* CDT 8.3 development (versions not supported on the 8.2.x branch) * CDT 8.3 development (versions not supported on the 8.2.x branch)
* 160.0 - Store specialized template parameters of class/function template specializations, bug 407497. * 160.0 - Store specialized template parameters of class/function template specializations, bug 407497.
* 161.0 - Allow reference to PDOMBinding from other PDOMLinkages, bug xyz.
*/ */
private static final int MIN_SUPPORTED_VERSION= version(160, 0); private static final int MIN_SUPPORTED_VERSION= version(161, 0);
private static final int MAX_SUPPORTED_VERSION= version(160, Short.MAX_VALUE); private static final int MAX_SUPPORTED_VERSION= version(161, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(160, 0); private static final int DEFAULT_VERSION = version(161, 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;
@ -1166,6 +1168,12 @@ public class PDOM extends PlatformObject implements IPDOM {
names.add(name); names.add(name);
} }
} }
IPDOMIterator<PDOMName> iterator = pdomBinding.getExternalReferences();
while(iterator.hasNext()) {
name = iterator.next();
if (isCommitted(name))
names.add(name);
}
} }
} }

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.core.pdom.db;
import java.util.NoSuchElementException;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.core.runtime.CoreException;
/**
* A utility class for storing a list of external references. An external reference is
* a PDOMName that references a PDOMBinding in a different linkage.
* <p>
* External references are stored in a singly linked list with one node for each linkage.
* Each node stores a list of PDOMNames. The PDOMName.BindingList is used to store the
* list.
* <p>
* Each node has three fields:
* {
* INT_SIZE linkageId;
* PTR_SIZE nextNode;
* PTR_SIZE nameListHead;
* }
* <p>
* An iterator is provided to examine all names in the list. An iterator is needed (instead
* of a simple list) so that we have a chance to move to the next linkage's node when we get
* to the end of a name list.
*/
public class PDOMExternalReferencesList {
private final PDOM pdom;
private final long record;
/**
* Create a new instance at the given location in the given PDOM.
*/
public PDOMExternalReferencesList(PDOM pdom, long record) throws CoreException {
this.pdom = pdom;
this.record = record;
}
/**
* Return an iterator for examining all names in the external references list. Does
* not return null.
*/
public IPDOMIterator<PDOMName> getIterator() throws CoreException {
return new Iterator(record);
}
/**
* Add the given name to this list.
*/
public void add(PDOMName name) throws CoreException {
// External references are stored in a linked list of linkages. Each node in that list
// is a list that uses the PDOMName binding list.
PDOMLinkage nameLinkage = name.getLinkage();
int nameLinkageID = nameLinkage.getLinkageID();
// Search through the nodes to find the one for the new name's linkage. Keep track of
// the record that held the last examined node so that a new node can be appended if
// needed.
long lastAddr = record;
long nodeRec = 0;
while((nodeRec = pdom.getDB().getRecPtr(lastAddr)) != 0) {
// Each node looks like { int linkageID; recPtr nextNode; recPtr headOfList; }
int linkageID = pdom.getDB().getInt(nodeRec);
if (linkageID == nameLinkageID)
break;
lastAddr = nodeRec + Database.INT_SIZE;
}
// If there isn't already a node for this linkage, then create a new one.
if (nodeRec == 0) {
nodeRec = pdom.getDB().malloc(Database.INT_SIZE + Database.PTR_SIZE + Database.PTR_SIZE);
// Setup the new node for this linkage and initialize the list ptr with an empty list.
pdom.getDB().putInt(nodeRec, nameLinkageID);
pdom.getDB().putRecPtr(nodeRec + Database.INT_SIZE, 0);
pdom.getDB().putRecPtr(nodeRec + Database.INT_SIZE + Database.PTR_SIZE, 0);
// Finally insert the new node right after the last one that was examined.
pdom.getDB().putRecPtr(lastAddr, nodeRec);
}
// If the list is not empty then modify the first element to be right after the name that
// is being inserted.
long namerec = pdom.getDB().getRecPtr(nodeRec + Database.INT_SIZE + Database.PTR_SIZE);
if (namerec != 0) {
PDOMName first = new PDOMName(nameLinkage, namerec);
first.setPrevInBinding(name);
name.setNextInBinding(first);
}
// Finally, make the new name the first element in the list.
pdom.getDB().putRecPtr(nodeRec + Database.INT_SIZE + Database.PTR_SIZE, name.getRecord());
}
private class Iterator implements IPDOMIterator<PDOMName> {
private long nodeAddr;
private long node;
private PDOMName next;
public Iterator(long record) throws CoreException {
this.nodeAddr = record;
this.node = 0;
// Initialize next by advancing to the first name.
this.next = advance();
}
@Override
public boolean hasNext() throws CoreException {
return next != null;
}
@Override
public PDOMName next() throws CoreException {
if (next == null)
throw new NoSuchElementException();
PDOMName ret = next;
next = ret.getNextInBinding();
if (next == null)
next = advance();
return ret;
}
/**
* Advance to the next linkage node that has a non-empty list of names. Return the
* PDOMName at the head of the list. This is the next name that should be returned
* from #next(). Return null if there are no more linkage nodes.
*/
private PDOMName advance() throws CoreException {
// Look through all linkage nodes to find the next one that has a non-empty
// names list.
while(true) {
// Skip over all nodes that don't have any names in their list.
long nextNameRec = 0;
while(nodeAddr != 0) {
node = pdom.getDB().getRecPtr(nodeAddr);
if (node == 0)
return null;
nextNameRec = pdom.getDB().getRecPtr(node + Database.INT_SIZE + Database.PTR_SIZE);
if (nextNameRec != 0)
break;
nodeAddr = node + Database.INT_SIZE;
}
// If nothing is found then there is no more iterating.
if (nodeAddr == 0
|| nextNameRec == 0)
return null;
// If a node is found that has a name in the list, then update this iterator to
// point to the next linkage's node (this is so the next call to advance starts
// at the right place).
nodeAddr = pdom.getDB().getRecPtr(node + Database.INT_SIZE);
// Load node's linkage and use it to return the first name in this node's list.
int linkageID = pdom.getDB().getInt(node);
PDOMLinkage linkage = pdom.getLinkage(linkageID);
if (linkage != null)
return new PDOMName(linkage, nextNameRec);
// Generate a log message about the linkageID that is no longer valid, but continue
// to the next node.
CCorePlugin.log("Could not load linkage for external reference from linkageID " + linkageID); //$NON-NLS-1$
}
}
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.internal.core.pdom.dom;
import java.util.NoSuchElementException;
import org.eclipse.core.runtime.CoreException;
/**
* A generic interface for iterating through lists that are stored in the PDOM. The
* difference between this interface and the standard one in java.util is that this
* one can throw a CoreException from either method. Also, this one does not provide
* a way to remove elements.
*/
public interface IPDOMIterator<T> {
/**
* Return true if the next call to #next will yield a value and false otherwise.
*
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() throws CoreException;
/**
* Return the next element in the iteration. Throws {@link NoSuchElementException} if
* there are no elements left in the iteration.
*
* @see java.util.Iterator#next
*/
public T next() throws CoreException;
}

View file

@ -37,6 +37,7 @@ import org.eclipse.cdt.internal.core.index.IIndexScope;
import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.db.Database; import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IString; import org.eclipse.cdt.internal.core.pdom.db.IString;
import org.eclipse.cdt.internal.core.pdom.db.PDOMExternalReferencesList;
import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable; import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
@ -46,13 +47,14 @@ import org.eclipse.core.runtime.CoreException;
public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding { public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding {
public static final PDOMBinding[] EMPTY_PDOMBINDING_ARRAY = {}; public static final PDOMBinding[] EMPTY_PDOMBINDING_ARRAY = {};
private static final int FIRST_DECL_OFFSET = PDOMNamedNode.RECORD_SIZE + 0; // size 4 private static final int FIRST_DECL_OFFSET = PDOMNamedNode.RECORD_SIZE + 0; // size 4
private static final int FIRST_DEF_OFFSET = PDOMNamedNode.RECORD_SIZE + 4; // size 4 private static final int FIRST_DEF_OFFSET = PDOMNamedNode.RECORD_SIZE + 4; // size 4
private static final int FIRST_REF_OFFSET = PDOMNamedNode.RECORD_SIZE + 8; // size 4 private static final int FIRST_REF_OFFSET = PDOMNamedNode.RECORD_SIZE + 8; // size 4
private static final int LOCAL_TO_FILE = PDOMNamedNode.RECORD_SIZE + 12; // size 4 private static final int LOCAL_TO_FILE = PDOMNamedNode.RECORD_SIZE + 12; // size 4
private static final int FIRST_EXTREF_OFFSET = PDOMNamedNode.RECORD_SIZE + 16; // size 4
@SuppressWarnings("hiding") @SuppressWarnings("hiding")
protected static final int RECORD_SIZE = PDOMNamedNode.RECORD_SIZE + 16; protected static final int RECORD_SIZE = PDOMNamedNode.RECORD_SIZE + 20;
private byte hasDeclaration= -1; private byte hasDeclaration= -1;
protected PDOMBinding(PDOMLinkage linkage, PDOMNode parent, char[] name) throws CoreException { protected PDOMBinding(PDOMLinkage linkage, PDOMNode parent, char[] name) throws CoreException {
@ -95,7 +97,8 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
Database db = pdom.getDB(); Database db = pdom.getDB();
return db.getRecPtr(record + FIRST_DECL_OFFSET) == 0 return db.getRecPtr(record + FIRST_DECL_OFFSET) == 0
&& db.getRecPtr(record + FIRST_DEF_OFFSET) == 0 && db.getRecPtr(record + FIRST_DEF_OFFSET) == 0
&& db.getRecPtr(record + FIRST_REF_OFFSET) == 0; && db.getRecPtr(record + FIRST_REF_OFFSET) == 0
&& db.getRecPtr(record + FIRST_EXTREF_OFFSET) == 0;
} }
@Override @Override
@ -132,6 +135,14 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
} }
public final void addReference(PDOMName name) throws CoreException { public final void addReference(PDOMName name) throws CoreException {
// This needs to filter between the local and external lists because it can be used in
// contexts that don't know which type of list they are iterating over. E.g., this is
// used when deleting names from a PDOMFile.
if (!getLinkage().equals(name.getLinkage())) {
new PDOMExternalReferencesList(getPDOM(), record + FIRST_EXTREF_OFFSET).add(name);
return;
}
PDOMName first = getFirstReference(); PDOMName first = getFirstReference();
if (first != null) { if (first != null) {
first.setPrevInBinding(name); first.setPrevInBinding(name);
@ -165,7 +176,25 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null; return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null;
} }
/**
* Returns an iterator over the names in other linkages that reference this binding. Does
* not return null.
*/
public IPDOMIterator<PDOMName> getExternalReferences() throws CoreException {
return new PDOMExternalReferencesList(getPDOM(), record + FIRST_EXTREF_OFFSET).getIterator();
}
public void setFirstReference(PDOMName name) throws CoreException { public void setFirstReference(PDOMName name) throws CoreException {
// This needs to filter between the local and external lists because it can be used in
// contexts that don't know which type of list they are iterating over. E.g., this is
// used when deleting names from a PDOMFile.
if (name != null
&& !getLinkage().equals(name.getLinkage())) {
new PDOMExternalReferencesList(getPDOM(), record + FIRST_EXTREF_OFFSET).add(name);
return;
}
// Otherwise put the reference into list of locals.
long namerec = name != null ? name.getRecord() : 0; long namerec = name != null ? name.getRecord() : 0;
getDB().putRecPtr(record + FIRST_REF_OFFSET, namerec); getDB().putRecPtr(record + FIRST_REF_OFFSET, namerec);
} }

View file

@ -33,7 +33,7 @@ import org.eclipse.core.runtime.IPath;
public final class PDOMName implements IIndexFragmentName, IASTFileLocation { public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
private final PDOMLinkage linkage; private final PDOMLinkage linkage;
private final long record; private final long record;
private static final int FILE_REC_OFFSET = 0; private static final int FILE_REC_OFFSET = 0;
private static final int FILE_NEXT_OFFSET = 4; private static final int FILE_NEXT_OFFSET = 4;
private static final int CALLER_REC_OFFSET = 8; private static final int CALLER_REC_OFFSET = 8;
@ -42,7 +42,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
private static final int BINDING_NEXT_OFFSET = 20; private static final int BINDING_NEXT_OFFSET = 20;
private static final int NODE_OFFSET_OFFSET = 24; // 3-byte unsigned int (sufficient for files <= 16mb) private static final int NODE_OFFSET_OFFSET = 24; // 3-byte unsigned int (sufficient for files <= 16mb)
private static final int NODE_LENGTH_OFFSET = 27; // short (sufficient for names <= 32k) private static final int NODE_LENGTH_OFFSET = 27; // short (sufficient for names <= 32k)
private static final int FLAGS = 29; private static final int FLAGS = 29;
private static final int RECORD_SIZE = 30; // 30 yields a 32-byte block. (31 would trigger a 40-byte block) private static final int RECORD_SIZE = 30; // 30 yields a 32-byte block. (31 would trigger a 40-byte block)
@ -58,7 +58,6 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
public static final int READ_ACCESS = 0x20; public static final int READ_ACCESS = 0x20;
public static final int WRITE_ACCESS = 0x40; public static final int WRITE_ACCESS = 0x40;
public PDOMName(PDOMLinkage linkage, IASTName name, PDOMFile file, PDOMBinding binding, PDOMName caller) public PDOMName(PDOMLinkage linkage, IASTName name, PDOMFile file, PDOMBinding binding, PDOMName caller)
throws CoreException { throws CoreException {
this.linkage = linkage; this.linkage = linkage;
@ -67,7 +66,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
// What kind of name are we // What kind of name are we
int flags= getRoleOfName(name); int flags= getRoleOfName(name);
flags |= binding.getAdditionalNameFlags(flags, name); flags |= binding.getAdditionalNameFlags(flags, name);
db.putByte(record + FLAGS, (byte) flags); db.putByte(record + FLAGS, (byte) flags);
@ -85,7 +84,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
} }
db.putRecPtr(record + BINDING_REC_OFFSET, binding.getRecord()); db.putRecPtr(record + BINDING_REC_OFFSET, binding.getRecord());
db.putRecPtr(record + FILE_REC_OFFSET, file.getRecord()); db.putRecPtr(record + FILE_REC_OFFSET, file.getRecord());
if (caller != null) { if (caller != null) {
db.putRecPtr(record + CALLER_REC_OFFSET, caller.getRecord()); db.putRecPtr(record + CALLER_REC_OFFSET, caller.getRecord());
@ -100,18 +99,22 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
private int getRoleOfName(IASTName name) { private int getRoleOfName(IASTName name) {
if (name.isDefinition()) { if (name.isDefinition()) {
return IS_DEFINITION; return IS_DEFINITION;
} }
if (name.isDeclaration()) { if (name.isDeclaration()) {
return IS_DECLARATION; return IS_DECLARATION;
} }
return IS_REFERENCE; return IS_REFERENCE;
} }
public PDOMName(PDOMLinkage linkage, long nameRecord) { public PDOMName(PDOMLinkage linkage, long nameRecord) {
this.linkage = linkage; this.linkage = linkage;
this.record = nameRecord; this.record = nameRecord;
} }
public PDOMLinkage getLinkage() {
return linkage;
}
public long getRecord() { public long getRecord() {
return record; return record;
} }
@ -127,7 +130,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
public PDOM getPDOM() { public PDOM getPDOM() {
return linkage.getPDOM(); return linkage.getPDOM();
} }
@Override @Override
public PDOMBinding getBinding() throws CoreException { public PDOMBinding getBinding() throws CoreException {
long bindingrec = getRecField(BINDING_REC_OFFSET); long bindingrec = getRecField(BINDING_REC_OFFSET);
@ -160,11 +163,11 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
public PDOMName getNextInBinding() throws CoreException { public PDOMName getNextInBinding() throws CoreException {
return getNameField(BINDING_NEXT_OFFSET); return getNameField(BINDING_NEXT_OFFSET);
} }
public void setNextInBinding(PDOMName name) throws CoreException { public void setNextInBinding(PDOMName name) throws CoreException {
setNameField(BINDING_NEXT_OFFSET, name); setNameField(BINDING_NEXT_OFFSET, name);
} }
@Override @Override
public PDOMFile getFile() throws CoreException { public PDOMFile getFile() throws CoreException {
long filerec = linkage.getDB().getRecPtr(record + FILE_REC_OFFSET); long filerec = linkage.getDB().getRecPtr(record + FILE_REC_OFFSET);
@ -188,11 +191,11 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
long getEnclosingDefinitionRecord() throws CoreException { long getEnclosingDefinitionRecord() throws CoreException {
return linkage.getDB().getRecPtr(record + CALLER_REC_OFFSET); return linkage.getDB().getRecPtr(record + CALLER_REC_OFFSET);
} }
public PDOMName getNextInFile() throws CoreException { public PDOMName getNextInFile() throws CoreException {
return getNameField(FILE_NEXT_OFFSET); return getNameField(FILE_NEXT_OFFSET);
} }
public void setNextInFile(PDOMName name) throws CoreException { public void setNextInFile(PDOMName name) throws CoreException {
setNameField(FILE_NEXT_OFFSET, name); setNameField(FILE_NEXT_OFFSET, name);
} }
@ -223,7 +226,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
public String toString() { public String toString() {
return new String(getSimpleID()); return new String(getSimpleID());
} }
private int getFlags(int mask) throws CoreException { private int getFlags(int mask) throws CoreException {
return linkage.getDB().getByte(record + FLAGS) & mask; return linkage.getDB().getByte(record + FLAGS) & mask;
} }
@ -254,7 +257,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
public boolean isBaseSpecifier() throws CoreException { public boolean isBaseSpecifier() throws CoreException {
return getFlags(INHERIT_FRIEND_INLINE_MASK) == IS_INHERITANCE_SPEC; return getFlags(INHERIT_FRIEND_INLINE_MASK) == IS_INHERITANCE_SPEC;
} }
@Override @Override
public boolean isInlineNamespaceDefinition() throws CoreException { public boolean isInlineNamespaceDefinition() throws CoreException {
return getFlags(INHERIT_FRIEND_INLINE_MASK) == IS_INLINE_NAMESPACE; return getFlags(INHERIT_FRIEND_INLINE_MASK) == IS_INLINE_NAMESPACE;

View file

@ -26,6 +26,7 @@ import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.pdom.IPDOM; import org.eclipse.cdt.internal.core.pdom.IPDOM;
import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile; import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacro; import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacro;
@ -59,11 +60,11 @@ public class CountNodeAction extends IndexAction {
static final int REFS = 3; static final int REFS = 3;
static final int DECLS = 4; static final int DECLS = 4;
static final int DEFS = 5; static final int DEFS = 5;
@Override @Override
public void run() { public void run() {
final int[] count = new int[6]; final int[] count = new int[6];
try { try {
ISelection selection = viewer.getSelection(); ISelection selection = viewer.getSelection();
if (!(selection instanceof IStructuredSelection)) if (!(selection instanceof IStructuredSelection))
@ -115,6 +116,10 @@ public class CountNodeAction extends IndexAction {
.getFirstReference(); name != null; name = name .getFirstReference(); name != null; name = name
.getNextInBinding()) .getNextInBinding())
++count[REFS]; ++count[REFS];
for (IPDOMIterator<PDOMName> i = binding.getExternalReferences();
i.hasNext();
i.next())
++count[REFS];
for (PDOMName name = binding for (PDOMName name = binding
.getFirstDeclaration(); name != null; name = name .getFirstDeclaration(); name != null; name = name
.getNextInBinding()) .getNextInBinding())
@ -141,7 +146,7 @@ public class CountNodeAction extends IndexAction {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return; return;
} }
MessageDialog.openInformation(null, MessageDialog.openInformation(null,
CUIPlugin.getResourceString("IndexView.CountSymbols.title"), //$NON-NLS-1$ CUIPlugin.getResourceString("IndexView.CountSymbols.title"), //$NON-NLS-1$
CUIPlugin.getFormattedString("IndexView.CountSymbols.message", //$NON-NLS-1$ CUIPlugin.getFormattedString("IndexView.CountSymbols.message", //$NON-NLS-1$