summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Eidsness2013-02-26 16:53:28 (EST)
committerDoug Schaefer2013-02-26 21:17:01 (EST)
commit6c6ab24c2355b454aa529361c9e0ee06d4166d35 (patch)
treefe409daf20ec25c4f79688ce91e62df67f064cc1
parent29efae531167786ab6e563c67c29a948525ff73e (diff)
downloadorg.eclipse.cdt-6c6ab24c2355b454aa529361c9e0ee06d4166d35.zip
org.eclipse.cdt-6c6ab24c2355b454aa529361c9e0ee06d4166d35.tar.gz
org.eclipse.cdt-6c6ab24c2355b454aa529361c9e0ee06d4166d35.tar.bz2
Bug 400020: Allow tagging of IBindingsrefs/changes/59/10659/3
Addresses review comments from https://git.eclipse.org/r/#/c/10648. Fixes the junit problems by making sure that the dummy PDOM acquires its write lock before calling exercising the tag index. Original commit message: This new extension point allows contributors to put their own information into the PDOM and to later retrieve it for their own purposes. There are many details in the bug. The idea is that contributors provide an implementation of IBindingTagger, which is given a chance to examine IBindings when they are created. The ITagWriter interface allows the contributor to create a new tag which can then have data written to it. The ITagService interface (accessible from CCorePlugin.getTagService() provides a way for the contributor to later get an instance of ITagReader to retrieve tags from bindings. ITags are copied to the PDOM when the associated binding is persisteed. Contributors use a unique id (based on their plugin id), so that multiple contributors are able to independently tag a given binding. In-memory tags are not cached. I've done some timing tests using my sample implementation and found no measurable difference. The full log lines look like: !MESSAGE Indexed 'simple-01' (2 sources, 184 headers) in <see below> sec: 21,550 declarations; 35,394 references; 0 unresolved inclusions; 1 syntax errors; 0 unresolved names (0.00%) I did 5 tests using the current master (no tagging-related code), the times were: 18.86 sec 9.17 sec 5.91 sec 4.79 sec 4.83 sec And then I ran the same sequence of tests using the code in this commit: 18.73 sec 9.39 sec 6.50 sec 4.78 sec 5.27 sec If performance does become a problem, then caching could be introduced with a new implementation of ITaggableService. The two problems are finding a key other than the identity of the IBinding (since IBindings are re-created often) and properly evicting stale entries when the binding is no longer valid. The process of copying tags from an in-memory IBinding to a PDOMBinding, is a synchronization. This means that tags that are no longer applicable, will be removed from the persistent store. While developing this I found that PDOMBindings are not deleted from the Database (only the names that reference them are deleted), so there is no provision for deleting all tags at once. New database locks are not needed. By the time the persistent tags are accessed, higher levels of code have already taken a read or write lock as appropriate. There are new unit tests covering the changes to the PDOM. Change-Id: I6ae1afc949082f7f4484b3faa1550670be43312f Reviewed-on: https://git.eclipse.org/r/10659 Reviewed-by: Doug Schaefer <dschaefer@qnx.com> IP-Clean: Doug Schaefer <dschaefer@qnx.com> Tested-by: Doug Schaefer <dschaefer@qnx.com>
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java76
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java147
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java4
-rw-r--r--core/org.eclipse.cdt.core/META-INF/MANIFEST.MF4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java39
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java44
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java35
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java33
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java39
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java33
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java89
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java79
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java103
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java36
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java196
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java5
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java22
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java190
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java86
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java14
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java24
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java87
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java323
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java269
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java104
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java51
-rw-r--r--core/org.eclipse.cdt.core/plugin.properties1
-rw-r--r--core/org.eclipse.cdt.core/plugin.xml1
-rw-r--r--core/org.eclipse.cdt.core/schema/tagger.exsd139
-rw-r--r--core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java11
-rw-r--r--qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java4
32 files changed, 2241 insertions, 53 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java
new file mode 100644
index 0000000..9d3431b
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java
@@ -0,0 +1,76 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.pdom.tests;
+
+import java.io.File;
+
+import junit.framework.Test;
+
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.internal.core.pdom.db.ChunkCache;
+import org.eclipse.cdt.internal.core.pdom.db.Database;
+import org.eclipse.cdt.internal.core.pdom.db.PDOMStringSet;
+
+// copy/pasted from BTreeTests
+public class PDOMStringSetTests extends BaseTestCase {
+ protected File dbFile;
+ protected Database db;
+ protected PDOMStringSet stringSet;
+ protected int rootRecord;
+
+ public static Test suite() {
+ return suite(PDOMStringSetTests.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ dbFile = File.createTempFile("pdomstringsettest", "db");
+ db = new Database(dbFile, new ChunkCache(), 0, false);
+ db.setExclusiveLock();
+ rootRecord = Database.DATA_AREA;
+ stringSet = new PDOMStringSet(db, rootRecord);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ db.close();
+ dbFile.deleteOnExit();
+
+ super.tearDown();
+ }
+
+ // Quick tests to exercise the basic functionality.
+ public void testInterface() throws Exception {
+ long val1_rec_a = stringSet.add("val1");
+ long val2_rec_a = stringSet.add("val2");
+ long val1_rec_b = stringSet.add("val1");
+ assertTrue(val1_rec_a != 0);
+ assertTrue(val2_rec_a != 0);
+ assertEquals(val1_rec_a, val1_rec_b);
+
+ long val1_find = stringSet.find("val1");
+ long val2_find = stringSet.find("val2");
+ assertEquals(val1_rec_a, val1_find);
+ assertEquals(val2_rec_a, val2_find);
+
+ long val1_rm = stringSet.remove("val1");
+ assertEquals(val1_rec_a, val1_rm);
+ assertEquals(0, stringSet.find("val1"));
+ assertEquals(val2_rec_a, stringSet.find("val2"));
+
+ stringSet.clearCaches();
+ assertEquals(val2_rec_a, stringSet.find("val2"));
+ assertEquals(0, stringSet.find("val1"));
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java
new file mode 100644
index 0000000..47a0053
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.pdom.tests;
+
+import java.io.File;
+import java.util.Arrays;
+
+import junit.framework.Test;
+
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.index.IIndexFileLocation;
+import org.eclipse.cdt.core.index.IIndexLocationConverter;
+import org.eclipse.cdt.core.model.LanguageManager;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.internal.core.dom.ast.tag.Tag;
+import org.eclipse.cdt.internal.core.pdom.PDOM;
+import org.eclipse.cdt.internal.core.pdom.WritablePDOM;
+import org.eclipse.cdt.internal.core.pdom.tag.PDOMTag;
+import org.eclipse.cdt.internal.core.pdom.tag.PDOMTagIndex;
+
+// copy/pasted from BTreeTests
+public class PDOMTagIndexTests extends BaseTestCase {
+ private PDOM pdom;
+
+ public static Test suite() {
+ return suite(PDOMTagIndexTests.class);
+ }
+
+ private static class MockIndexLocationConverter implements
+ IIndexLocationConverter {
+ @Override
+ public IIndexFileLocation fromInternalFormat(String raw) {
+ return null;
+ }
+
+ @Override
+ public String toInternalFormat(IIndexFileLocation location) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Create a dummy instance of the PDOM for the various tests to operate
+ // upon. Also acquire the PDOM's write lock to simulate the condition
+ // under which the tag index is normally accessed.
+ File tmpFile = File.createTempFile(getClass().getSimpleName() + '.'
+ + Double.toString(Math.random()).substring(2), null);
+ pdom = new WritablePDOM(tmpFile, new MockIndexLocationConverter(),
+ LanguageManager.getInstance().getPDOMLinkageFactoryMappings());
+ pdom.acquireWriteLock();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ pdom.close();
+ super.tearDown();
+ }
+
+ // return the nearest valid record that is less than the specified base
+ private static long lastRecordBase = 1000;
+
+ private static long computeValidRecord() {
+ lastRecordBase += 1000;
+ return (lastRecordBase & ~7L) | 2;
+ }
+
+ // A quick sanity test to confirm basic functionality.
+ public void testSimple() throws Exception {
+ String tagger = "tagger_a";
+ long rec = computeValidRecord();
+
+ assertNotNull(PDOMTagIndex.createTag(pdom, rec, tagger, 1));
+ assertNotNull(PDOMTagIndex.getTag(pdom, rec, tagger));
+ }
+
+ public void testMultipleTaggers() throws Exception {
+ String tagger_a = "tagger_a";
+ String tagger_b = "tagger_b";
+ long rec1 = computeValidRecord();
+ long rec2 = computeValidRecord();
+
+ assertNotNull(PDOMTagIndex.createTag(pdom, rec1, tagger_a, 1));
+ assertNotNull(PDOMTagIndex.createTag(pdom, rec1, tagger_b, 1));
+ assertNotNull(PDOMTagIndex.createTag(pdom, rec2, tagger_a, 1));
+
+ assertNotNull(PDOMTagIndex.getTag(pdom, rec2, tagger_a));
+ assertNull(PDOMTagIndex.getTag(pdom, rec2, tagger_b));
+
+ Iterable<ITag> tags1 = PDOMTagIndex.getTags(pdom, rec1);
+ int tag_count = 0;
+ for (ITag tag : tags1) {
+ ++tag_count;
+ assertTrue(tag.getTaggerId().equals(tagger_a)
+ || tag.getTaggerId().equals(tagger_b));
+ assertEquals(1, tag.getDataLen());
+ }
+ assertEquals(2, tag_count);
+ }
+
+ public void testReplaceTags() throws Exception {
+ String tagger_a = "tagger_a";
+ String tagger_b = "tagger_b";
+ long rec = computeValidRecord();
+
+ ITag taga = PDOMTagIndex.createTag(pdom, rec, tagger_a, 2);
+ assertNotNull(taga);
+ assertTrue(taga instanceof PDOMTag);
+ PDOMTag taga_pdom = (PDOMTag) taga;
+ ITag tagb = PDOMTagIndex.createTag(pdom, rec, tagger_a, 2);
+ assertNotNull(tagb);
+
+ // replacement should delete tags for taggers that are no longer present
+ // and shorter tags
+ // should be modified in place
+ PDOMTagIndex.setTags(pdom, rec,
+ Arrays.<ITag> asList(new Tag(tagger_a, 1)));
+ assertNull(PDOMTagIndex.getTag(pdom, rec, tagger_b));
+ ITag shorter_ = PDOMTagIndex.getTag(pdom, rec, tagger_a);
+ assertNotNull(shorter_);
+ assertTrue(shorter_ instanceof PDOMTag);
+ PDOMTag shorter_pdom = (PDOMTag) shorter_;
+ assertEquals(taga_pdom.getRecord(), shorter_pdom.getRecord());
+
+ // longer tags should create a new record
+ PDOMTagIndex.setTags(pdom, rec,
+ Arrays.<ITag> asList(new Tag(tagger_a, 4)));
+ ITag longer_ = PDOMTagIndex.getTag(pdom, rec, tagger_a);
+ assertNotNull(longer_);
+ assertTrue(longer_ instanceof PDOMTag);
+ PDOMTag longer_pdom = (PDOMTag) longer_;
+ assertTrue(taga_pdom.getRecord() != longer_pdom.getRecord());
+
+ // TODO figure out how to confirm that the original tag was free'd
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java
index f244ec3..3640bbe 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java
@@ -38,7 +38,9 @@ public class PDOMTests extends TestSuite {
suite.addTest(OverloadsWithinSingleTUTests.suite());
suite.addTest(OverloadsWithinCommonHeaderTests.suite());
suite.addTest(BTreeTests.suite());
- suite.addTest(FilesOnReindexTests.suite());
+ suite.addTest(PDOMStringSetTests.suite());
+ suite.addTest(PDOMTagIndexTests.suite());
+ suite.addTest(FilesOnReindexTests.suite());
suite.addTest(GeneratePDOMApplicationTest.suite());
suite.addTest(CPPFieldTests.suite());
diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
index 9130967..b4de801 100644
--- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
@@ -16,6 +16,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.core.dom.ast.gnu,
org.eclipse.cdt.core.dom.ast.gnu.c,
org.eclipse.cdt.core.dom.ast.gnu.cpp,
+ org.eclipse.cdt.core.dom.ast.tag,
org.eclipse.cdt.core.dom.parser,
org.eclipse.cdt.core.dom.parser.c,
org.eclipse.cdt.core.dom.parser.cpp,
@@ -52,6 +53,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.internal.core.browser;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.cdtvariables;x-internal:=true,
org.eclipse.cdt.internal.core.dom;x-internal:=true,
+ org.eclipse.cdt.internal.core.dom.ast.tag;x-internal:=true,
org.eclipse.cdt.internal.core.dom.parser;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.dom.parser.c;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.dom.parser.cpp;x-friends:="org.eclipse.cdt.ui",
@@ -84,6 +86,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.internal.core.pdom.dom.cpp;x-internal:=true,
org.eclipse.cdt.internal.core.pdom.export;x-internal:=true,
org.eclipse.cdt.internal.core.pdom.indexer;x-friends:="org.eclipse.cdt.ui",
+ org.eclipse.cdt.internal.core.pdom.tag;x-internal:=true,
org.eclipse.cdt.internal.core.resources;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.make.core,org.eclipse.cdt.codan.ui.cxx",
org.eclipse.cdt.internal.core.settings.model;x-internal:=true,
org.eclipse.cdt.internal.core.util;x-internal:=true,
@@ -111,6 +114,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.utils.xcoff,
org.eclipse.cdt.utils.xcoff.parser
Require-Bundle: org.eclipse.core.contenttype;bundle-version="[3.3.0,4.0.0)",
+ org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)",
org.eclipse.core.filebuffers;bundle-version="[3.2.0,4.0.0)",
org.eclipse.core.filesystem;bundle-version="[1.1.0,2.0.0)",
org.eclipse.core.resources;bundle-version="[3.2.0,4.0.0)",
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java
new file mode 100644
index 0000000..57df74e
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java
@@ -0,0 +1,39 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+
+/**
+ * Implementations are contributed with the org.eclipse.cdt.core.tagger extension-point. The implementation is
+ * responsible for populating the tag's data using a given input binding.
+ *
+ * @see #process(ITagWriter, IBinding, IASTName)
+ * @since 5.5
+ */
+public interface IBindingTagger {
+ /**
+ * Examines the given input binding to decide if a tag should be created. Use the given tagWriter to
+ * create data if needed. Return the tag if one was created and null otherwise. A tagger (as identified by
+ * it's unique id string) is allowed to create only one tag for each binding.
+ *
+ * @param tagWriter
+ * the writer to use for creating new tags
+ * @param binding
+ * the binding to examine when populating the tag (if needed)
+ * @param ast
+ * the AST name from which the binding was created
+ * @return the tag if one was created and null otherwise
+ */
+ public ITag process(ITagWriter tagWriter, IBinding binding, IASTName ast);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java
new file mode 100644
index 0000000..027b4af
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+/**
+ * Tags are used to annotate {@link ITagReader}'s with extra information. They are created by implementations
+ * of {@link IBindingTagger} which are contributed using the org.eclipse.cdt.core.tagger extension point. The
+ * base tag interface is read-only, it is extended by the writable {@link IWritableTag}.
+ *
+ * @see IBindingTagger
+ * @see ITagReader
+ * @see IWritableTag
+ * @since 5.5
+ */
+public interface ITag {
+ /** A constant that is returned to indicate a read failure. */
+ public static final int FAIL = -1;
+
+ /** Return the number of bytes in the tag's data payload. */
+ public int getDataLen();
+
+ /** Return the globally unique id of the tagger that created the receiver. */
+ public String getTaggerId();
+
+ /** Return the byte from the specified offset or {@link #FAIL} on failure. */
+ public int getByte(int offset);
+
+ /**
+ * Return the specified number of bytes from the specified offset. Specify len of -1 to read all bytes
+ * from the specified offset to the end of the payload. Return null if the given range is not valid. This
+ * would be expected if the version of the contributor has changed in a way that changes the structure of
+ * the data that it stores. Contributors must be able to deal with that case.
+ */
+ public byte[] getBytes(int offset, int len);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java
new file mode 100644
index 0000000..fd7ca0b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java
@@ -0,0 +1,35 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+/**
+ * An interface that provides read-only access to the tags associated with a particular binding.
+ *
+ * @see ITag
+ * @see ITagService
+ * @since 5.5
+ */
+public interface ITagReader {
+ /**
+ * Look for a tag for the receiver, returns null if there is no such tag.
+ *
+ * @param id
+ * A string that uniquely identifies the tag to be returned. This value was provided by the
+ * contributor when the tag was created (see {@link ITagWriter#createTag(String, int)}).
+ */
+ public ITag getTag(String id);
+
+ /**
+ * Return all tags known to the receiver. Does not return null.
+ */
+ public Iterable<ITag> getTags();
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java
new file mode 100644
index 0000000..237fc48
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java
@@ -0,0 +1,33 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+
+/**
+ * Provides ITagReaders for specific bindings. The kind of the reader will vary based on the kind of the input
+ * binding.
+ *
+ * @see ITag
+ * @see ITagReader
+ * @since 5.5
+ */
+public interface ITagService {
+ /**
+ * Finds or creates a tag reader for the specified binding or null if a reader cannot be associated with
+ * this binding.
+ *
+ * @param binding
+ * could be null
+ */
+ public ITagReader findTagReader(IBinding binding);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java
new file mode 100644
index 0000000..f77deac
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java
@@ -0,0 +1,39 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+/**
+ * An interface that allows tag creation and modification.
+ *
+ * @see ITag
+ * @see ITagService
+ * @since 5.5
+ */
+public interface ITagWriter {
+ /**
+ * Create and return a new tag for the receiver. E.g., if this writer is associated with a persistent
+ * binding, then returned tag will read and write from the PDOM database.
+ *
+ * @param id
+ * A string that uniquely identifies the tag to be returned. This value will be used by the
+ * contributor when to find the tag (see {@link ITagReader#getTag(String)}).
+ * @param len
+ * The number of bytes that should be allocated to store the tag's data.
+ */
+ public IWritableTag createTag(String id, int len);
+
+ /**
+ * Sets the receiver's tags to only the ones provided. Deletes existing tags that are not in the argument
+ * list.
+ */
+ public boolean setTags(Iterable<ITag> tags);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java
new file mode 100644
index 0000000..adf1d8b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java
@@ -0,0 +1,33 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.core.dom.ast.tag;
+
+/**
+ * Tags are used to annotate {@link ITagWriter}'s with extra information. They are created by implementations
+ * of {@link IBindingTagger} which are contributed using the org.eclipse.cdt.core.tagger extension point.
+ *
+ * @see IBindingTagger
+ * @see ITagReader
+ * @see ITagWriter
+ * @since 5.5
+ */
+public interface IWritableTag extends ITag {
+ /** Write the given byte to the given offset in the tag. Return true if successful and false otherwise. */
+ public boolean putByte(int offset, byte data);
+
+ /**
+ * Write the argument buffer into the receiver's payload starting at the specified offset. Write the
+ * specified number of bytes or the full buffer when len is -1. Return true if successful and false
+ * otherwise.
+ */
+ public boolean putBytes(int offset, byte data[], int len);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java
new file mode 100644
index 0000000..8683da4
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java
@@ -0,0 +1,89 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.dom.ast.tag;
+
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.ITagReader;
+import org.eclipse.cdt.core.dom.ast.tag.ITagWriter;
+import org.eclipse.cdt.core.dom.ast.tag.IWritableTag;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
+
+public class NonCachedTaggable implements ITagReader, ITagWriter {
+ private final IBinding binding;
+ private IASTName ast;
+
+ public NonCachedTaggable(IBinding binding) {
+ this.binding = binding;
+ }
+
+ @Override
+ public IWritableTag createTag(String id, int len) {
+ return new Tag(id, len);
+ }
+
+ @Override
+ public ITag getTag(String id) {
+ return TagManager.getInstance().process(id, this, binding, getAST());
+ }
+
+ @Override
+ public Iterable<ITag> getTags() {
+ return TagManager.getInstance().process(this, binding, getAST());
+ }
+
+ @Override
+ public boolean setTags(Iterable<ITag> tags) {
+ // this non-caching implementation has nothing to set, the tags will be regenerated
+ // when they are queried
+ return true;
+ }
+
+ private IASTName getAST() {
+ if (ast != null)
+ return ast;
+
+ if (!(binding instanceof ICPPInternalBinding))
+ return null;
+
+ IASTNode node = getPhysicalNode((ICPPInternalBinding) binding);
+ if (node == null)
+ return null;
+
+ return ast = getName(node);
+ }
+
+ private static IASTNode getPhysicalNode(ICPPInternalBinding binding) {
+ IASTNode node = binding.getDefinition();
+ if (node != null)
+ return node;
+
+ IASTNode[] nodes = binding.getDeclarations();
+ if (nodes == null || nodes.length <= 0)
+ return null;
+ return nodes[0];
+ }
+
+ private static IASTName getName(IASTNode node) {
+ if (node instanceof IASTName)
+ return (IASTName) node;
+ if (node instanceof ICPPASTCompositeTypeSpecifier)
+ return ((ICPPASTCompositeTypeSpecifier) node).getName();
+ if (node instanceof IASTDeclarator)
+ return ((IASTDeclarator) node).getName();
+ return null;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java
new file mode 100644
index 0000000..7b9430d
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java
@@ -0,0 +1,79 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.dom.ast.tag;
+
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.IWritableTag;
+
+/**
+ * A trivial implementation that stores all data in memory.
+ *
+ * @see NonCachedTaggable
+ */
+public class Tag implements IWritableTag {
+ private final String taggerId;
+ private final byte[] buff;
+
+ public Tag(String taggerId, int dataLen) {
+ this.taggerId = taggerId;
+ this.buff = new byte[dataLen];
+ }
+
+ @Override
+ public String getTaggerId() {
+ return taggerId;
+ }
+
+ @Override
+ public int getDataLen() {
+ return buff.length;
+ }
+
+ private boolean isInBounds(int offset, int len) {
+ return offset >= 0 && offset < buff.length && (offset + len) <= buff.length;
+ }
+
+ @Override
+ public boolean putByte(int offset, byte b) {
+ if (!isInBounds(offset, 1))
+ return false;
+
+ buff[offset] = b;
+ return true;
+ }
+
+ @Override
+ public boolean putBytes(int offset, byte[] data, int len) {
+ len = len >= 0 ? len : data.length;
+ if (!isInBounds(offset, len))
+ return false;
+
+ System.arraycopy(data, 0, buff, offset, len);
+ return true;
+ }
+
+ @Override
+ public int getByte(int offset) {
+ return isInBounds(offset, 1) ? buff[offset] : ITag.FAIL;
+ }
+
+ @Override
+ public byte[] getBytes(int offset, int len) {
+ len = len >= 0 ? len : buff.length - offset;
+ if (!isInBounds(offset, len))
+ return null;
+
+ byte[] data = new byte[len];
+ System.arraycopy(buff, offset, data, 0, len);
+ return data;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java
new file mode 100644
index 0000000..57c29d8
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java
@@ -0,0 +1,103 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.dom.ast.tag;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger;
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.ITagReader;
+import org.eclipse.cdt.core.dom.ast.tag.ITagWriter;
+import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding;
+import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+
+public class TagManager {
+ private static TagManager INSTANCE;
+
+ private Map<String, TaggerDescriptor> taggers;
+
+ public static TagManager getInstance() {
+ if (INSTANCE == null)
+ INSTANCE = new TagManager();
+ return INSTANCE;
+ }
+
+ private TagManager() {
+ taggers = loadExtensions();
+ }
+
+ private static final String ExtensionPoint = "tagger"; //$NON-NLS-1$
+
+ private static Map<String, TaggerDescriptor> loadExtensions() {
+ Map<String, TaggerDescriptor> taggers = new HashMap<String, TaggerDescriptor>();
+
+ // load the extensions
+ IConfigurationElement[] elements = Platform.getExtensionRegistry()
+ .getConfigurationElementsFor(CCorePlugin.PLUGIN_ID, ExtensionPoint);
+ for (IConfigurationElement element : elements) {
+ TaggerDescriptor desc = new TaggerDescriptor(element);
+ taggers.put(desc.getId(), desc);
+ }
+
+ return taggers;
+ }
+
+ /**
+ * Provide an opportunity for the specified tagger to process the given values. The tagger will only run
+ * if its enablement expression returns true for the arguments.
+ */
+ public ITag process(String taggerId, ITagWriter tagWriter, IBinding binding, IASTName ast) {
+ TaggerDescriptor desc = taggers.get(taggerId);
+ if (desc == null)
+ return null;
+
+ IBindingTagger tagger = desc.getBindingTaggerFor(binding, ast);
+ return tagger == null ? null : tagger.process(tagWriter, binding, ast);
+ }
+
+ /** Provide an opportunity for all enabled taggers to process the given values. */
+ public Iterable<ITag> process(ITagWriter tagWriter, IBinding binding, IASTName ast) {
+ List<ITag> tags = new LinkedList<ITag>();
+ for (TaggerDescriptor desc : taggers.values()) {
+ IBindingTagger tagger = desc.getBindingTaggerFor(binding, ast);
+ if (tagger != null) {
+ ITag tag = tagger.process(tagWriter, binding, ast);
+ if (tag != null)
+ tags.add(tag);
+ }
+ }
+
+ return tags;
+ }
+
+ /** Add or remove tags from the destination to ensure that it has the same tag information as the source. */
+ public void syncTags(IPDOMBinding dst, IBinding src) {
+ // don't try to copy any tags when there are no contributors to this extension point
+ if (dst == null || taggers.isEmpty())
+ return;
+
+ ITagReader tagReader = CCorePlugin.getTagService().findTagReader(src);
+ if (tagReader == null)
+ return;
+
+ ITagWriter tagWriter = new PDOMTaggable(dst.getPDOM(), dst.getRecord());
+ tagWriter.setTags(tagReader.getTags());
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java
new file mode 100644
index 0000000..ca22dc9
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java
@@ -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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.dom.ast.tag;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.tag.ITagReader;
+import org.eclipse.cdt.core.dom.ast.tag.ITagService;
+
+public class TagService implements ITagService {
+ /**
+ * First gives the IBinding instance a chance to convert itself, by calling IAdaptable#getAdapter(
+ * ITagReader.class ) on the binding. If the binding doesn't provide an implementation then a simple,
+ * in-memory, non-cached implementation is created and returned.
+ */
+ @Override
+ public ITagReader findTagReader(IBinding binding) {
+ if (binding == null)
+ return null;
+
+ // let the binding adapt to its own tag reader
+ ITagReader tagReader = (ITagReader) binding.getAdapter(ITagReader.class);
+ if (tagReader != null)
+ return tagReader;
+
+ return new NonCachedTaggable(binding);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java
new file mode 100644
index 0000000..f408e88
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java
@@ -0,0 +1,196 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.dom.ast.tag;
+
+import java.util.Arrays;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger;
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.ITagWriter;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.ExpressionTagNames;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * Internal container for extensions of org.eclipse.cdt.core.tagger. The implementation of the tagger is
+ * instantiated only after checking the enablement expression (if present) for the specified binding. This
+ * avoids activating the contributing plugin until it is actually needed.
+ */
+public class TaggerDescriptor {
+ private static final String Attr_LocalId = "local-id"; //$NON-NLS-1$
+ private static final String Attr_Class = "class"; //$NON-NLS-1$
+
+ private final IConfigurationElement element;
+ private final Expression enablementExpression;
+ private Boolean fStatus = null;
+
+ private String id;
+ private IBindingTagger tagger;
+
+ private static final String VAR_PROJECTNATURES = "projectNatures"; //$NON-NLS-1$
+ private static final String VAR_LANGUAGEID = "languageId"; //$NON-NLS-1$
+
+ /**
+ * An empty implementation of the tagger used as a placeholder in descriptors that are unable to load the
+ * contributed class.
+ */
+ private static final IBindingTagger NullTagger = new IBindingTagger() {
+ @Override
+ public ITag process(ITagWriter tagWriter, IBinding binding, IASTName ast) {
+ return null;
+ }
+ };
+
+ public TaggerDescriptor(IConfigurationElement element) {
+ this.element = element;
+
+ Expression expr = null;
+ IConfigurationElement[] children = element.getChildren(ExpressionTagNames.ENABLEMENT);
+ switch (children.length) {
+ case 0:
+ fStatus = Boolean.TRUE;
+ break;
+ case 1:
+ try {
+ ExpressionConverter parser = ExpressionConverter.getDefault();
+ expr = parser.perform(children[0]);
+ } catch (CoreException e) {
+ CCorePlugin.log("Error in enablement expression of " + id, e); //$NON-NLS-1$
+ }
+ break;
+ default:
+ CCorePlugin.log("Too many enablement expressions for " + id); //$NON-NLS-1$
+ fStatus = Boolean.FALSE;
+ break;
+ }
+ enablementExpression = expr;
+ }
+
+ public String getId() {
+ if (id != null)
+ return id;
+
+ String globalId = element.getContributor().getName();
+ String localId = element.getAttribute(Attr_LocalId);
+
+ // there must be a valid local id
+ if (localId == null) {
+ String extId = element.getDeclaringExtension().getSimpleIdentifier();
+ CCorePlugin
+ .log("Invalid extension " + globalId + '.' + extId + " must provide tagger's local-id"); //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ // the extension should not include the plugin id, but return immediately if it does
+ if (localId.startsWith(globalId) && localId.length() > globalId.length())
+ return localId;
+
+ // make sure the local id has real content
+ if (localId.isEmpty()) {
+ String extId = element.getDeclaringExtension().getSimpleIdentifier();
+ CCorePlugin
+ .log("Invalid extension " + globalId + '.' + extId + " must provide value for tagger's local-id"); //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ // otherwise prepend with the globalId, and ensure a dot between them
+ if (localId.charAt(0) == '.')
+ return globalId + localId;
+ return globalId + '.' + localId;
+ }
+
+ private boolean matches(ITranslationUnit tu) {
+ // if the enablement expression is missing or structurally invalid, then return immediately
+ if (fStatus != null)
+ return fStatus.booleanValue();
+
+ // if there is no tu, then the enablement expression cannot be evaluated, assume that all taggers
+ // are needed
+ if (tu == null)
+ return true;
+
+ if (enablementExpression != null)
+ try {
+ IProject project = null;
+ ICProject cProject = tu.getCProject();
+ if (cProject != null)
+ project = cProject.getProject();
+
+ EvaluationContext evalContext = new EvaluationContext(null, project);
+
+ // if the project is not accessible, then only taggers that don't care about it will
+ // get a chance to run
+ if (project != null) {
+ String[] natures = project.getDescription().getNatureIds();
+ evalContext.addVariable(VAR_PROJECTNATURES, Arrays.asList(natures));
+ }
+
+ ILanguage language = tu.getLanguage();
+ if (language != null)
+ evalContext.addVariable(VAR_LANGUAGEID, language.getId());
+
+ return enablementExpression.evaluate(evalContext) == EvaluationResult.TRUE;
+ } catch (CoreException e) {
+ CCorePlugin.log("Error while evaluating enablement expression for " + id, e); //$NON-NLS-1$
+ }
+
+ fStatus = Boolean.FALSE;
+ return false;
+ }
+
+ private IBindingTagger getTagger() {
+ if (tagger == null)
+ synchronized (this) {
+ if (tagger == null) {
+ try {
+ tagger = (IBindingTagger) element.createExecutableExtension(Attr_Class);
+ } catch (CoreException e) {
+ String id = element.getDeclaringExtension().getNamespaceIdentifier() + '.'
+ + element.getDeclaringExtension().getSimpleIdentifier();
+ CCorePlugin.log("Error in class attribute of " + id, e); //$NON-NLS-1$
+
+ // mark the tagger with an empty implementation to prevent future load attempts
+ tagger = NullTagger;
+ }
+ }
+ }
+
+ return tagger;
+ }
+
+ // Activates the plugin if needed.
+ public IBindingTagger getBindingTaggerFor(IBinding binding, IASTName ast) {
+ // If there isn't an ast with an AST-TU accessible, then there is no way to defer processing,
+ // just return the tagger and let it try to sort things out. E.g., this happens for built-in
+ // things.
+ if (ast == null)
+ return getTagger();
+ IASTTranslationUnit astTU = ast.getTranslationUnit();
+ if (astTU == null)
+ return getTagger();
+
+ // Otherwise evaluate the enablement expression for this TU
+ return matches(astTU.getOriginatingTranslationUnit()) ? getTagger() : null;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index d306479..403516e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -340,10 +340,10 @@ public class CPPVisitor extends ASTQueries {
return false;
}
}
-
+
if (inScope == null)
return false;
-
+
IBinding pb= names[names.length-2].resolvePreBinding();
if (pb instanceof IProblemBinding)
return false;
@@ -357,7 +357,7 @@ public class CPPVisitor extends ASTQueries {
} else if (pb instanceof ICPPNamespace) {
scope= ((ICPPNamespace)pb).getNamespaceScope();
}
-
+
return scope == inScope;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java
index cf628db..df41726 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java
@@ -41,6 +41,7 @@ import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IndexLocationFactory;
import org.eclipse.cdt.core.model.AbstractLanguage;
import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.FileContent;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IScannerInfo;
@@ -48,6 +49,7 @@ import org.eclipse.cdt.core.parser.ISignificantMacros;
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
import org.eclipse.cdt.core.parser.ParserUtil;
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
+import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.index.FileContentKey;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
@@ -1004,6 +1006,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
IASTTranslationUnit ast= createAST(lang, codeReader, scanInfo, isSource, fASTOptions, ctx, pm);
fStatistics.fParsingTime += System.currentTimeMillis() - start;
if (ast != null) {
+ // Give the new AST-TU a chance to recognize its translation unit before it is written
+ // to the index.
+ ( (ASTTranslationUnit)ast ).setOriginatingTranslationUnit( (ITranslationUnit)tu );
writeToIndex(lang.getLinkageID(), ast, codeReader, ctx, pm);
}
} catch (CoreException e) {
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 8b8d709..5c59fbc 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
@@ -89,6 +89,7 @@ import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacroReferenceName;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNamedNode;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
+import org.eclipse.cdt.internal.core.pdom.tag.PDOMTagIndex;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
@@ -208,7 +209,7 @@ public class PDOM extends PlatformObject implements IPDOM {
* 113.0 - Changed marshaling of values, bug 327878
* #114.0# - Partial specializations for class template specializations, bug 332884.
* - Corrected signatures for function templates, bug 335062. <<CDT 8.0>>
- *
+ *
* CDT 8.1 development (versions not supported on the 8.0.x branch)
* 120.0 - Enumerators in global index, bug 356235
* 120.1 - Specializations of using declarations, bug 357293.
@@ -217,7 +218,7 @@ public class PDOM extends PlatformObject implements IPDOM {
* 123.0 - Combined file size and encoding hash code.
* 124.0 - GCC attributes and NO_RETURN flag for functions.
* #125.0# - Indexes for unresolved includes and files indexed with I/O errors. <<CDT 8.1>>
- *
+ *
* CDT 8.2 development (versions not supported on the 8.1.x branch)
* 130.0 - Dependent expressions, bug 299911.
* 131.0 - Dependent expressions part 2, bug 299911.
@@ -230,6 +231,7 @@ public class PDOM extends PlatformObject implements IPDOM {
* 138.0 - Constexpr functions, bug 395238.
* 139.0 - More efficient and robust storage of types and template arguments, bug 395243.
* 140.0 - Enumerators with dependent values, bug 389009.
+ * 140.1 - Mechanism for tagging nodes with extended data, bug 400020
* 141.0 - Storing enclosing template bindings for evaluations, bug 399829
*/
private static final int MIN_SUPPORTED_VERSION= version(141, 0);
@@ -270,7 +272,8 @@ public class PDOM extends PlatformObject implements IPDOM {
public static final int INDEX_OF_DEFECTIVE_FILES = Database.DATA_AREA + 8;
public static final int INDEX_OF_FILES_WITH_UNRESOLVED_INCLUDES = Database.DATA_AREA + 12;
public static final int PROPERTIES = Database.DATA_AREA + 16;
- public static final int END= Database.DATA_AREA + 20;
+ public static final int TAG_INDEX = Database.DATA_AREA + 20;
+ public static final int END= Database.DATA_AREA + 24;
static {
assert END <= Database.CHUNK_SIZE;
}
@@ -332,6 +335,7 @@ public class PDOM extends PlatformObject implements IPDOM {
// Local caches
protected Database db;
private BTree fileIndex;
+ private PDOMTagIndex tagIndex;
private BTree indexOfDefectiveFiles;
private BTree indexOfFiledWithUnresolvedIncludes;
private final Map<Integer, PDOMLinkage> fLinkageIDCache = new HashMap<Integer, PDOMLinkage>();
@@ -460,6 +464,15 @@ public class PDOM extends PlatformObject implements IPDOM {
return fileIndex;
}
+ public PDOMTagIndex getTagIndex() throws CoreException {
+ if (tagIndex == null)
+ {
+ // tag index can only be stored in database versions 139.1 or greater
+ tagIndex = new PDOMTagIndex( db.getVersion() >= version( 139, 1 ) ? db : null, TAG_INDEX );
+ }
+ return tagIndex;
+ }
+
/**
* Returns the index of files that were read with I/O errors.
*/
@@ -549,7 +562,7 @@ public class PDOM extends PlatformObject implements IPDOM {
});
return files.toArray(new IIndexFragmentFile[files.size()]);
}
-
+
protected IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location,
ISignificantMacros sigMacros) throws CoreException {
PDOMLinkage linkage= createLinkage(linkageID);
@@ -1358,6 +1371,7 @@ public class PDOM extends PlatformObject implements IPDOM {
private void clearCaches() {
fileIndex= null;
+ tagIndex = null;
indexOfDefectiveFiles= null;
indexOfFiledWithUnresolvedIncludes= null;
fLinkageIDCache.clear();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java
new file mode 100644
index 0000000..3c2774c
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java
@@ -0,0 +1,190 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.db;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * A container for storing a set of strings in the Database. The container allows only one instance of each
+ * string to be stored.
+ * <p>
+ * This implementation should only be used when the set is expected to be small. It uses a singly linked list
+ * for storing strings in Database. Which means that a linear lookup is needed to find strings in the list. An
+ * in-memory, lazily-loaded, cache is provided so the list will only be fully retrieved once in the lifetime
+ * of this instance. A BTree will be more efficient for larger sets.
+ */
+public class PDOMStringSet {
+ private final Database db;
+
+ private long ptr;
+ private long head;
+ private long loaded;
+
+ // A lazily initialized, in-memory cache that maps a persisted string to its storage record.
+ private Map<String, Long> lazyCache;
+
+ public PDOMStringSet(Database db, long ptr) throws CoreException {
+ this.db = db;
+ this.ptr = ptr;
+
+ head = 0;
+ loaded = 0;
+ }
+
+ public void clearCaches() {
+ head = 0;
+ loaded = 0;
+
+ if (lazyCache != null)
+ lazyCache = null;
+ }
+
+ private long getHead() throws CoreException {
+ if (head == 0)
+ head = db.getRecPtr(ptr);
+ return head;
+ }
+
+ // A simple enum describing the type of the information that is stored in the Database. Each
+ // enumerator represents a single field in the persistent structure and is able to answer its
+ // offset in that structure.
+ private static enum NodeType {
+ Next, Item, _last;
+
+ // NOTE: All fields are pointers, if that changes then these initializations will need
+ // to be updated.
+ public final long offset = ordinal() * Database.PTR_SIZE;
+ public static final int sizeof = (int) _last.offset;
+
+ /** Return the value of the pointer stored in this field in the given instance. */
+ public long get(Database db, long instance) throws CoreException {
+ return db.getRecPtr(instance + offset);
+ }
+
+ /** Store the given pointer into this field in the given instance. */
+ public void put(Database db, long instance, long value) throws CoreException {
+ db.putRecPtr(instance + offset, value);
+ }
+ }
+
+ /**
+ * Adds the given string to the receiving set. May cause the entire list to be loaded from the Database
+ * while testing for uniqueness. Returns the record of the string that was inserted into the list.
+ */
+ public long add(String str) throws CoreException {
+ long record = find(str);
+ if (record != 0)
+ return record;
+
+ IString string = db.newString(str);
+ record = string.getRecord();
+
+ long new_node = db.malloc(NodeType.sizeof);
+ NodeType.Next.put(db, new_node, getHead());
+ NodeType.Item.put(db, new_node, record);
+
+ if (lazyCache == null)
+ lazyCache = new HashMap<String, Long>();
+ lazyCache.put(str, record);
+
+ // If the Database has already been partially searched, then the loaded pointer will be after the
+ // head. Since we've already put this new record into the lazy cache, there is no reason to try to
+ // load it again. We put the new node at the start of the list so that it will be before the loaded
+ // pointer.
+ head = new_node;
+ if (loaded == 0)
+ loaded = new_node;
+ db.putRecPtr(ptr, new_node);
+ return record;
+ }
+
+ /**
+ * Search for the given string in the receiver. This could cause the entire list to be loaded from the
+ * Database. The results are cached, so the list will only be loaded one time during the lifetime of this
+ * instance. Returns the record of the String.
+ */
+ public long find(String str) throws CoreException {
+ if (lazyCache != null) {
+ Long l = lazyCache.get(str);
+ if (l != null)
+ return l.longValue();
+ }
+
+ // if there is nothing in the Database, then there is nothing to load
+ if (getHead() == 0)
+ return 0;
+
+ // otherwise prepare the cache for the data that is about to be loaded
+ if (lazyCache == null)
+ lazyCache = new HashMap<String, Long>();
+
+ // if nothing has been loaded, then start loading with the head node, otherwise continue
+ // loading from whatever is after the last loaded node
+ long curr = loaded == 0 ? getHead() : NodeType.Next.get(db, loaded);
+ while (curr != 0) {
+ long next = NodeType.Next.get(db, curr);
+ long item = NodeType.Item.get(db, curr);
+
+ IString string = db.getString(item);
+
+ // put the value into the cache
+ lazyCache.put(string.getString(), Long.valueOf(item));
+
+ // return immediately if this is the target
+ if (string.compare(str, true) == 0)
+ return item;
+
+ // otherwise keep looking
+ loaded = curr;
+ curr = next;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Return a pointer to the record of the String that was removed.
+ */
+ public long remove(String str) throws CoreException {
+ if (lazyCache != null)
+ lazyCache.remove(str);
+
+ long prev = 0;
+ long curr = getHead();
+ while (curr != 0) {
+ long next = NodeType.Next.get(db, curr);
+ long item = NodeType.Item.get(db, curr);
+
+ IString string = db.getString(item);
+
+ if (string.compare(str, true) == 0) {
+ if (head != curr)
+ NodeType.Next.put(db, prev, next);
+ else {
+ db.putRecPtr(ptr, next);
+ head = next;
+ }
+
+ db.free(curr);
+ return item;
+ }
+
+ prev = curr;
+ curr = next;
+ }
+
+ return 0;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java
index 769d7a0..1ff1729 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java
@@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
+import org.eclipse.cdt.core.dom.ast.tag.ITagReader;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@@ -36,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.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IString;
+import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable;
import org.eclipse.core.runtime.CoreException;
/**
@@ -48,33 +50,41 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
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 LOCAL_TO_FILE = PDOMNamedNode.RECORD_SIZE + 12; // size 4
-
+
@SuppressWarnings("hiding")
protected static final int RECORD_SIZE = PDOMNamedNode.RECORD_SIZE + 16;
private byte hasDeclaration= -1;
-
+
protected PDOMBinding(PDOMLinkage linkage, PDOMNode parent, char[] name) throws CoreException {
super(linkage, parent, name);
}
-
+
public PDOMBinding(PDOMLinkage linkage, long record) {
super(linkage, record);
}
-
+
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(PDOMBinding.class))
return this;
+ // Any PDOMBinding can have a persistent tag. These tags should be deleted when the PDOMBinding
+ // is deleted. However, PDOMBinding's don't get deleted, so there is no way to trigger deleting
+ // of the tags. If the implementation is changed so that PDOMBindings do get deleted, then call:
+ // PDOMTagIndex.setTags( getPDOM(), pdomBinding.record, Collections.<ITag>emptyList() );
+ // to clear out all tags for the binding.
+ if (adapter.isAssignableFrom(ITagReader.class))
+ return new PDOMTaggable( getPDOM(), getRecord() );
+
return null;
}
-
+
/**
* Is the binding as the record orphaned, i.e., has no declarations
* or references.
* Watch out, a binding may also be used in a type (e.g. pointer to class)
- *
+ *
* @param pdom
* @param record
* @return <code>true</code> if the binding is orphaned.
@@ -86,7 +96,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
&& db.getRecPtr(record + FIRST_DEF_OFFSET) == 0
&& db.getRecPtr(record + FIRST_REF_OFFSET) == 0;
}
-
+
@Override
public final boolean hasDeclaration() throws CoreException {
if (hasDeclaration == -1) {
@@ -101,7 +111,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return hasDeclaration != 0;
}
-
+
public final void addDeclaration(PDOMName name) throws CoreException {
PDOMName first = getFirstDeclaration();
if (first != null) {
@@ -110,7 +120,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
setFirstDeclaration(name);
}
-
+
public final void addDefinition(PDOMName name) throws CoreException {
PDOMName first = getFirstDefinition();
if (first != null) {
@@ -119,7 +129,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
setFirstDefinition(name);
}
-
+
public final void addReference(PDOMName name) throws CoreException {
PDOMName first = getFirstReference();
if (first != null) {
@@ -128,37 +138,37 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
setFirstReference(name);
}
-
+
public PDOMName getFirstDeclaration() throws CoreException {
long namerec = getDB().getRecPtr(record + FIRST_DECL_OFFSET);
return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null;
}
-
+
public void setFirstDeclaration(PDOMName name) throws CoreException {
long namerec = name != null ? name.getRecord() : 0;
getDB().putRecPtr(record + FIRST_DECL_OFFSET, namerec);
}
-
+
public PDOMName getFirstDefinition() throws CoreException {
long namerec = getDB().getRecPtr(record + FIRST_DEF_OFFSET);
return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null;
}
-
+
public void setFirstDefinition(PDOMName name) throws CoreException {
long namerec = name != null ? name.getRecord() : 0;
getDB().putRecPtr(record + FIRST_DEF_OFFSET, namerec);
}
-
+
public PDOMName getFirstReference() throws CoreException {
long namerec = getDB().getRecPtr(record + FIRST_REF_OFFSET);
return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null;
}
-
+
public void setFirstReference(PDOMName name) throws CoreException {
long namerec = name != null ? name.getRecord() : 0;
getDB().putRecPtr(record + FIRST_REF_OFFSET, namerec);
}
-
+
@Override
public final PDOMFile getLocalToFile() throws CoreException {
final long filerec = getLocalToFileRec(getDB(), record);
@@ -196,7 +206,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return CharArrayUtils.EMPTY;
}
-
+
public IIndexScope getParent() {
try {
IBinding parent = getParentBinding();
@@ -208,12 +218,12 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return null;
}
-
+
@Override
public final IIndexScope getScope() {
- // The parent node in the binding hierarchy is the scope.
+ // The parent node in the binding hierarchy is the scope.
try {
- IBinding parent= getParentBinding();
+ IBinding parent= getParentBinding();
while (parent != null) {
if (parent instanceof ICPPClassType) {
return (IIndexScope) ((ICPPClassType) parent).getCompositeScope();
@@ -223,7 +233,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
final ICPPEnumeration enumeration = (ICPPEnumeration) parent;
if (enumeration.isScoped()) {
return (IIndexScope) enumeration.asScope();
- }
+ }
parent= ((PDOMNamedNode) parent).getParentBinding();
} else if (parent instanceof IIndexScope) {
return (IIndexScope) parent;
@@ -237,7 +247,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return null;
}
-
+
@Override
public IIndexFragment getFragment() {
return getPDOM();
@@ -245,7 +255,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
@Override
abstract protected int getRecordSize(); // superclass's implementation is no longer valid
-
+
/* For debug purposes only.
* @see java.lang.Object#toString()
*/
@@ -266,15 +276,15 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
} else {
return getName() + "()"; //$NON-NLS-1$
}
- }
+ }
return getName();
}
-
+
/**
* For debug purposes only.
* @param linkage
* @param value
- * @return String representation of <code>value</code>.
+ * @return String representation of <code>value</code>.
*/
protected static String getConstantNameForValue(PDOMLinkage linkage, int value) {
Class<? extends PDOMLinkage> c= linkage.getClass();
@@ -297,7 +307,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return Integer.toString(value);
}
-
+
public PDOMName getScopeName() {
try {
PDOMName name = getFirstDefinition();
@@ -314,7 +324,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
public String[] getQualifiedName() {
return new String[] { getName() };
}
-
+
@Override
final public boolean isFileLocal() throws CoreException {
return getDB().getRecPtr(record + LOCAL_TO_FILE) != 0;
@@ -327,11 +337,11 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
/**
* Compares two binding fully qualified names. If b0 has
- * less segments than b1 then -1 is returned, if b0 has
+ * less segments than b1 then -1 is returned, if b0 has
* more segments than b1 then 1 is returned. If the segment
* lengths are equal then comparison is lexicographical on each
* component name, beginning with the most nested name and working
- * outward.
+ * outward.
* If one of the bindings in the hierarchy is file-local it is treated as a different
* binding.
* The first non-zero comparison is returned as the result.
@@ -345,7 +355,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
*/
private static int comparePDOMBindingQNs(PDOMBinding b0, PDOMBinding b1) {
try {
- int cmp = 0;
+ int cmp = 0;
do {
IString s0 = b0.getDBName(), s1 = b1.getDBName();
cmp = s0.compare(s1, true);
@@ -370,7 +380,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
/**
- * Compares two PDOMBinding objects in accordance with
+ * Compares two PDOMBinding objects in accordance with
* {@link IIndexFragmentBindingComparator#compare(IIndexFragmentBinding, IIndexFragmentBinding)}
* @param other
* @return comparison result, -1, 0, or 1.
@@ -384,14 +394,14 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
}
return cmp;
}
-
+
/**
* Returns whether pdomCompareTo returns zero
*/
public final boolean pdomEquals(PDOMBinding other) {
return pdomCompareTo(other)==0;
}
-
+
@Override
public final int getBindingConstant() {
return getNodeType();
@@ -399,11 +409,11 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
/**
* The binding is reused by a declaration or definition, we may need to update modifiers.
- * @throws CoreException
+ * @throws CoreException
*/
public void update(PDOMLinkage linkage, IBinding newBinding) throws CoreException {
}
-
+
@Override
final public void delete(PDOMLinkage linkage) throws CoreException {
assert false;
@@ -417,7 +427,7 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
public int getAdditionalNameFlags(int standardFlags, IASTName name) {
return 0;
}
-
+
public final IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, null);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java
index dd7be43..77608c1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java
@@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.index.IIndexBinding;
+import org.eclipse.cdt.internal.core.dom.ast.tag.TagManager;
import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
@@ -97,6 +98,11 @@ class PDOMCLinkage extends PDOMLinkage implements IIndexCBindingConstants {
if (pdomBinding != null) {
getPDOM().putCachedResult(inputBinding, pdomBinding);
}
+
+ // Synchronize the tags associated with the persistent binding to match the set that is
+ // associated with the input binding.
+ TagManager.getInstance().syncTags( pdomBinding, inputBinding );
+
return pdomBinding;
}
@@ -104,7 +110,13 @@ class PDOMCLinkage extends PDOMLinkage implements IIndexCBindingConstants {
}
if (shouldUpdate(pdomBinding, fromName)) {
- pdomBinding.update(this, fromName.getBinding());
+ IBinding fromBinding = fromName.getBinding();
+
+ pdomBinding.update(this, fromBinding);
+
+ // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but
+ // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation.
+ TagManager.getInstance().syncTags( pdomBinding, fromBinding );
}
return pdomBinding;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
index 656dfb0..3d85ab4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
@@ -75,6 +75,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.Util;
+import org.eclipse.cdt.internal.core.dom.ast.tag.TagManager;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
@@ -358,6 +359,10 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
if (inputBinding instanceof CPPClosureType) {
addImplicitMethods(pdomBinding, (ICPPClassType) binding, fromName);
}
+
+ // Synchronize the tags associated with the persistent binding to match the set that is
+ // associated with the input binding.
+ TagManager.getInstance().syncTags( pdomBinding, inputBinding );
}
} catch (DOMException e) {
throw new CoreException(Util.createStatus(e));
@@ -367,8 +372,15 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
}
if (shouldUpdate(pdomBinding, fromName)) {
- pdomBinding.update(this, fromName.getBinding());
+ IBinding fromBinding = fromName.getBinding();
+
+ pdomBinding.update(this, fromBinding);
+
+ // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but
+ // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation.
+ TagManager.getInstance().syncTags( pdomBinding, fromBinding );
}
+
return pdomBinding;
}
@@ -408,7 +420,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
// template parameters are created directly by their owners.
if (binding instanceof ICPPTemplateParameter)
return null;
- if (binding instanceof ICPPUnknownBinding)
+ if (binding instanceof ICPPUnknownBinding)
return null;
if (binding instanceof ICPPSpecialization) {
@@ -561,6 +573,10 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
} else if (!getPDOM().hasLastingDefinition(pdomBinding)) {
pdomBinding.update(this, method);
old.remove(pdomBinding);
+
+ // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but
+ // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation.
+ TagManager.getInstance().syncTags( pdomBinding, method );
}
}
}
@@ -691,7 +707,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
if (result != null) {
return result;
}
-
+
// Assign names to anonymous types.
IBinding binding= PDOMASTAdapter.getAdapterForAnonymousASTBinding(inputBinding);
if (binding == null) {
@@ -1111,7 +1127,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return CPPPointerToMemberType.unmarshal(firstByte, buffer);
case ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE:
return TypeOfDependentExpression.unmarshal(firstByte, buffer);
- case ITypeMarshalBuffer.UNKNOWN_MEMBER:
+ case ITypeMarshalBuffer.UNKNOWN_MEMBER:
IBinding binding= CPPUnknownMember.unmarshal(getPDOM(), firstByte, buffer);
if (binding instanceof IType)
return (IType) binding;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java
new file mode 100644
index 0000000..53740f1
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java
@@ -0,0 +1,87 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.tag;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.internal.core.pdom.db.BTree;
+import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+public class BTreeIterable<T> implements Iterable<T> {
+ public static interface Descriptor<T> {
+ public int compare(long record) throws CoreException;
+
+ public T create(long record);
+ }
+
+ private final BTree btree;
+ private final Descriptor<T> descriptor;
+
+ public BTreeIterable(BTree btree, Descriptor<T> descriptor) {
+ this.btree = btree;
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ Visitor v = new Visitor();
+ try {
+ btree.accept(v);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return Collections.<T> emptyList().iterator();
+ }
+ return new BTreeIterator(v.records);
+ }
+
+ private class Visitor implements IBTreeVisitor {
+ public final List<Long> records = new LinkedList<Long>();
+
+ @Override
+ public int compare(long record) throws CoreException {
+ return BTreeIterable.this.descriptor.compare(record);
+ }
+
+ @Override
+ public boolean visit(long record) throws CoreException {
+ records.add(Long.valueOf(record));
+ return true;
+ }
+ }
+
+ private class BTreeIterator implements Iterator<T> {
+ private final Iterator<Long> records;
+
+ public BTreeIterator(Iterable<Long> records) {
+ this.records = records.iterator();
+ }
+
+ @Override
+ public void remove() {
+ }
+
+ @Override
+ public boolean hasNext() {
+ return records.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return BTreeIterable.this.descriptor.create(records.next());
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java
new file mode 100644
index 0000000..c332fcc
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java
@@ -0,0 +1,323 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.tag;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.tag.IWritableTag;
+import org.eclipse.cdt.internal.core.pdom.db.Database;
+import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
+import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * A container for storing tags in the PDOM. The storage format is as follows:
+ *
+ * <pre>
+ * PDOMTag
+ * {
+ * u4 node_record; # pointer to the node that is being tagged
+ * u4 tagger_id; # pointer to the string that identifies the tagger that
+ * # created this tag
+ * u4 data_len; # number of bytes stored in this tag's payload
+ * u1[]; # a buffer for storing the tag's payload
+ * };
+ * </pre>
+ *
+ * Each tag points to the contributing tagger id, the record that is being tagged. Finally, it stores a buffer
+ * for the tag's payload. The buffer is read and written by the contributor of the tag.
+ */
+public class PDOMTag implements IWritableTag {
+ private final Database db;
+ private final long record;
+
+ private String taggerId;
+ private int dataLen = -1;
+
+ private static enum Fields {
+ Node, TaggerId, DataLen, Data;
+
+ public final long offset = ordinal() * Database.PTR_SIZE;
+
+ public static int sizeof(int datalen) {
+ return (int) Data.offset + datalen;
+ }
+
+ public long getRecPtr(Database db, long instance, long data_offset) throws CoreException {
+ return db.getRecPtr(instance + offset + data_offset);
+ }
+
+ public void putRecPtr(Database db, long instance, long data_offset, long value)
+ throws CoreException {
+ db.putRecPtr(instance + offset + data_offset, value);
+ }
+
+ public void put(Database db, long instance, long data_offset, byte value)
+ throws CoreException {
+ db.putByte(instance + offset + data_offset, value);
+ }
+
+ public void put(Database db, long instance, byte[] data, long data_offset, int len)
+ throws CoreException {
+ db.putBytes(instance + offset + data_offset, data, len);
+ }
+
+ public byte getByte(Database db, long instance, long data_offset) throws CoreException {
+ return db.getByte(instance + offset + data_offset);
+ }
+
+ public byte[] getBytes(Database db, long instance, long data_offset, int len)
+ throws CoreException {
+ byte[] data = new byte[len];
+ db.getBytes(instance + offset + data_offset, data);
+ return data;
+ }
+
+ public void put(Database db, long instance, long data_offset, int value)
+ throws CoreException {
+ db.putInt(instance + offset + data_offset, value);
+ }
+
+ public int getInt(Database db, long instance, long data_offset) throws CoreException {
+ return db.getInt(instance + offset + data_offset);
+ }
+ }
+
+ public PDOMTag(Database db, long record) {
+ this.db = db;
+ this.record = record;
+ }
+
+ public PDOMTag(Database db, int dataLen) throws CoreException {
+ this.db = db;
+ this.record = db.malloc(Fields.sizeof(dataLen));
+ this.dataLen = dataLen;
+ Fields.DataLen.put(db, record, 0, dataLen);
+ }
+
+ public long getNode() throws CoreException {
+ return Fields.Node.getRecPtr(db, record, 0);
+ }
+
+ @Override
+ public String getTaggerId() {
+ if (taggerId == null)
+ try {
+ long taggerIdRecord = Fields.TaggerId.getRecPtr(db, record, 0);
+ taggerId = taggerIdRecord == 0L ? new String() : db.getString(taggerIdRecord)
+ .getString();
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+
+ return taggerId;
+ }
+
+ @Override
+ public int getDataLen() {
+ if (dataLen < 0)
+ try {
+ dataLen = Fields.DataLen.getInt(db, record, 0);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return 0;
+ }
+
+ return dataLen;
+ }
+
+ public long getRecord() {
+ return record;
+ }
+
+ /**
+ * Create and return a new PDOMTag that has the same node/taggerId as the receiver but with the specified
+ * data. Return null on failure.
+ */
+ public PDOMTag cloneWith(byte[] data) throws CoreException {
+ PDOMTag partialTag = null;
+ try {
+ long existing_node = Fields.Node.getRecPtr(db, record, 0);
+ long existing_id = Fields.TaggerId.getRecPtr(db, record, 0);
+
+ partialTag = new PDOMTag(db, data.length);
+ Fields.Node.putRecPtr(db, partialTag.record, 0, existing_node);
+ Fields.TaggerId.putRecPtr(db, partialTag.record, 0, existing_id);
+ if (partialTag.putBytes(0, data, data.length)) {
+ PDOMTag tag = partialTag;
+ partialTag = null;
+ return tag;
+ }
+ } finally {
+ if (partialTag != null)
+ partialTag.delete();
+ }
+
+ return null;
+ }
+
+ public void delete() {
+ if (db != null && record != 0)
+ try {
+ db.free(record);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+ }
+
+ public static class BTreeComparator implements IBTreeComparator {
+ private final Database db;
+
+ public BTreeComparator(Database db) {
+ this.db = db;
+ }
+
+ @Override
+ public int compare(long record1, long record2) throws CoreException {
+ if (record1 == record2)
+ return 0;
+
+ long node1 = Fields.Node.getRecPtr(db, record1, 0);
+ long node2 = Fields.Node.getRecPtr(db, record2, 0);
+ if (node1 < node2)
+ return -1;
+ if (node1 > node2)
+ return 1;
+
+ long tagger1 = Fields.TaggerId.getRecPtr(db, record1, 0);
+ long tagger2 = Fields.TaggerId.getRecPtr(db, record2, 0);
+ if (tagger1 < tagger2)
+ return -1;
+ if (tagger1 > tagger2)
+ return 1;
+
+ return 0;
+ }
+ }
+
+ public static class BTreeVisitor implements IBTreeVisitor {
+ private final Database db;
+ private final long node2;
+ private final long tagger2;
+
+ public boolean hasResult = false;
+ public long tagRecord = 0;
+
+ public BTreeVisitor(Database db, long node2, long tagger2) {
+ this.db = db;
+ this.node2 = node2;
+ this.tagger2 = tagger2;
+ }
+
+ @Override
+ public int compare(long record1) throws CoreException {
+ long node1 = Fields.Node.getRecPtr(db, record1, 0);
+ if (node1 < node2)
+ return -1;
+ if (node1 > node2)
+ return 1;
+
+ long tagger1 = Fields.TaggerId.getRecPtr(db, record1, 0);
+ if (tagger1 < tagger2)
+ return -1;
+ if (tagger1 > tagger2)
+ return 1;
+
+ return 0;
+ }
+
+ @Override
+ public boolean visit(long record) throws CoreException {
+ tagRecord = record;
+ hasResult = true;
+ return false;
+ }
+ }
+
+ public void setNode(long node) throws CoreException {
+ Fields.Node.putRecPtr(db, record, 0, node);
+ }
+
+ public void setTaggerId(long idRecord) throws CoreException {
+ Fields.TaggerId.putRecPtr(db, record, 0, idRecord);
+ }
+
+ private boolean isInBounds(int offset, int len) {
+ int data_len = getDataLen();
+ return offset >= 0 && offset < data_len && (offset + len) <= data_len;
+ }
+
+ @Override
+ public boolean putByte(int offset, byte data) {
+ if (!isInBounds(offset, 1))
+ return false;
+
+ try {
+ Fields.Data.put(db, record, offset, data);
+ return true;
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean putBytes(int offset, byte[] data, int len) {
+ boolean fullWrite = len < 0;
+ if (fullWrite)
+ len = data.length;
+ if (!isInBounds(offset, len))
+ return false;
+
+ try {
+ Fields.Data.put(db, record, data, offset, len);
+
+ // if the new buffer replaces all of the existing one, then modify the receiver's stored length
+ int currLen = getDataLen();
+ if (fullWrite && offset == 0 && currLen > len) {
+ Fields.DataLen.put(db, record, 0, len);
+ dataLen = len;
+ }
+
+ return true;
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return false;
+ }
+ }
+
+ @Override
+ public int getByte(int offset) {
+ if (!isInBounds(offset, 1))
+ return FAIL;
+
+ try {
+ return Fields.Data.getByte(db, record, offset);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return FAIL;
+ }
+ }
+
+ @Override
+ public byte[] getBytes(int offset, int len) {
+ len = len >= 0 ? len : getDataLen() - offset;
+ if (!isInBounds(offset, len))
+ return null;
+
+ try {
+ return Fields.Data.getBytes(db, record, offset, len);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return null;
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java
new file mode 100644
index 0000000..614ba8f
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java
@@ -0,0 +1,269 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.tag;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.IWritableTag;
+import org.eclipse.cdt.internal.core.pdom.PDOM;
+import org.eclipse.cdt.internal.core.pdom.db.BTree;
+import org.eclipse.cdt.internal.core.pdom.db.Database;
+import org.eclipse.cdt.internal.core.pdom.db.PDOMStringSet;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Not thread-safe.
+ */
+public class PDOMTagIndex {
+ private final Database db;
+ private final long ptr;
+ private long rootRecord;
+
+ private static enum Fields {
+ TaggerIds, Tags, _last;
+
+ public final long offset = ordinal() * Database.PTR_SIZE;
+ public static int sizeof = _last.ordinal() * Database.PTR_SIZE;
+ }
+
+ private PDOMStringSet taggerIds;
+ private BTree tags;
+
+ public PDOMTagIndex(Database db, long ptr) throws CoreException {
+ this.db = db;
+ this.ptr = ptr;
+ this.rootRecord = 0;
+ }
+
+ private long getFieldAddress(Fields field) throws CoreException {
+ if (rootRecord == 0)
+ rootRecord = db.getRecPtr(ptr);
+
+ if (rootRecord == 0) {
+ rootRecord = db.malloc(Fields.sizeof);
+ db.putRecPtr(ptr, rootRecord);
+ }
+
+ return rootRecord + field.offset;
+ }
+
+ private PDOMStringSet getTaggerIds() throws CoreException {
+ if (taggerIds == null)
+ taggerIds = new PDOMStringSet(db, getFieldAddress(Fields.TaggerIds));
+ return taggerIds;
+ }
+
+ private BTree getTagsBTree() throws CoreException {
+ if (tags == null)
+ tags = new BTree(db, getFieldAddress(Fields.Tags), new PDOMTag.BTreeComparator(db));
+ return tags;
+ }
+
+ /**
+ * Return the record storing the specified tagger id. Create a new record if needed.
+ */
+ private long getIdRecord(String taggerId, boolean createIfNeeded) {
+ assert taggerId != null;
+ assert !taggerId.isEmpty();
+
+ if (db == null || taggerId == null || taggerId.isEmpty()
+ || (taggerIds == null && !createIfNeeded))
+ return 0L;
+
+ try {
+ long record = getTaggerIds().find(taggerId);
+ if (record == 0 && createIfNeeded)
+ record = getTaggerIds().add(taggerId);
+ return record;
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+
+ return 0L;
+ }
+
+ private IWritableTag createTag(long record, String id, int len) {
+ if (db == null)
+ return null;
+
+ long idRecord = getIdRecord(id, true);
+ if (idRecord == 0L)
+ return null;
+
+ try {
+ PDOMTag tag = new PDOMTag(db, len);
+ tag.setNode(record);
+ tag.setTaggerId(idRecord);
+
+ // return the tag if it was properly inserted
+ long inserted = getTagsBTree().insert(tag.getRecord());
+ if (inserted == tag.getRecord())
+ return tag;
+
+ // TODO check that the existing record has the same length
+
+ // otherwise destroy this provisional one and return the tag that was actually inserted
+ // TODO figure out what this case means
+ tag.delete();
+ return inserted == 0 ? null : new PDOMTag(db, inserted);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+
+ return null;
+ }
+
+ private ITag getTag(long record, String id) {
+ if (db == null)
+ return null;
+
+ long idRecord = getIdRecord(id, false);
+ if (idRecord == 0L)
+ return null;
+
+ PDOMTag.BTreeVisitor v = new PDOMTag.BTreeVisitor(db, record, idRecord);
+ try {
+ getTagsBTree().accept(v);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+
+ return v.hasResult ? new PDOMTag(db, v.tagRecord) : null;
+ }
+
+ private Iterable<ITag> getTags(long binding_record) {
+ BTree btree = null;
+ try {
+ btree = getTagsBTree();
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return Collections.emptyList();
+ }
+
+ final Long bindingRecord = Long.valueOf(binding_record);
+ return new BTreeIterable<ITag>(btree, new BTreeIterable.Descriptor<ITag>() {
+ @Override
+ public ITag create(long record) {
+ return new PDOMTag(db, record);
+ }
+
+ @Override
+ public int compare(long test_record) throws CoreException {
+ long test_node = new PDOMTag(db, test_record).getNode();
+
+ // -1 if record < key, 0 if record == key, 1 if record > key
+ return Long.valueOf(test_node).compareTo(bindingRecord);
+ }
+ });
+ }
+
+ private boolean setTags(long binding_record, Iterable<ITag> tags) {
+ // There could be several tags for the given record in the database, one for each taggerId. We need
+ // to delete all of those tags and replace them with given list. The incoming tags are first put
+ // into a map, indexed by their taggerId. Then we examine the btree of tags to find all tags for this
+ // record. In each case we decide whether to delete or update the tag. Tags of the same size can be
+ // updated in place, otherwise the tag needs to be deleted and recreated.
+
+ final Map<String, ITag> newTags = new HashMap<String, ITag>();
+ for (ITag tag : tags) {
+ ITag dupTag = newTags.put(tag.getTaggerId(), tag);
+ if (dupTag != null)
+ CCorePlugin
+ .log("Duplicate incoming tag for record " + binding_record + " from taggerId " + tag.getTaggerId()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ BTree btree = null;
+ try {
+ btree = getTagsBTree();
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return false;
+ }
+
+ PDOMTagSynchronizer sync = new PDOMTagSynchronizer(db, Long.valueOf(binding_record),
+ newTags);
+
+ // visit the full tree, then return true on success and false on failure
+ try {
+ btree.accept(sync);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ return false;
+ }
+
+ // Complete the synchronization (delete/insert the records that could not be modified in-place). This
+ // will only have something to do when a tag has changed length, which should be a rare.
+ sync.synchronize(btree);
+
+ // insert any new tags that are left in the incoming list
+ for (ITag newTag : newTags.values()) {
+ IWritableTag pdomTag = createTag(binding_record, newTag.getTaggerId(),
+ newTag.getDataLen());
+ pdomTag.putBytes(0, newTag.getBytes(0, -1), -1);
+ }
+
+ return true;
+ }
+
+ private static PDOMTagIndex getTagIndex(PDOM pdom) {
+ if (pdom == null)
+ return null;
+
+ try {
+ PDOMTagIndex index = pdom.getTagIndex();
+ return index.db == null ? null : index;
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+ return null;
+ }
+
+ // common implementations
+ public static IWritableTag createTag(PDOM pdom, long record, String id, int len) {
+ PDOMTagIndex index = getTagIndex(pdom);
+ if (index == null)
+ return null;
+
+ return index.createTag(record, id, len);
+ }
+
+ public static ITag getTag(PDOM pdom, long record, String id) {
+ PDOMTagIndex index = getTagIndex(pdom);
+ if (index == null)
+ return null;
+
+ return index.getTag(record, id);
+ }
+
+ public static Iterable<ITag> getTags(PDOM pdom, long record) {
+ PDOMTagIndex index = getTagIndex(pdom);
+ if (index == null)
+ return Collections.emptyList();
+
+ return index.getTags(record);
+ }
+
+ public static boolean setTags(PDOM pdom, long record, Iterable<ITag> tags) {
+ if (record == 0)
+ return true;
+
+ PDOMTagIndex index = getTagIndex(pdom);
+ if (index == null)
+ return false;
+
+ return index.setTags(record, tags);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java
new file mode 100644
index 0000000..4043e44
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java
@@ -0,0 +1,104 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.tag;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.internal.core.pdom.db.BTree;
+import org.eclipse.cdt.internal.core.pdom.db.Database;
+import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * An implementation utility for synchronizing the tags between source and destination nodes.
+ */
+public class PDOMTagSynchronizer implements IBTreeVisitor {
+ private final Database db;
+ private final Long searchRecord;
+ private final Map<String, ITag> newTags;
+
+ private final List<Long> toRemove = new LinkedList<Long>();
+ private final List<Long> toInsert = new LinkedList<Long>();
+
+ public PDOMTagSynchronizer(Database db, Long searchRecord, Map<String, ITag> newTags) {
+ this.db = db;
+ this.searchRecord = searchRecord;
+ this.newTags = newTags;
+ }
+
+ /**
+ * Complete the synchronization by deleting and inserting all required records. Return true if successful
+ * and false otherwise.
+ */
+ public boolean synchronize(BTree tree) {
+ for (Long rm : toRemove)
+ try {
+ long record = rm.longValue();
+ tree.delete(record);
+ db.free(record);
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ }
+ toRemove.clear();
+
+ for (Long insert : toInsert)
+ try {
+ tree.insert(insert.longValue());
+ } catch (CoreException e) {
+ CCorePlugin.log(e);
+ try {
+ db.free(insert.longValue());
+ } catch (CoreException e1) {
+ CCorePlugin.log(e1);
+ }
+ }
+ toInsert.clear();
+
+ return true;
+ }
+
+ @Override
+ public int compare(long test_record) throws CoreException {
+ // TODO this is the same as BTreeIterable.Descriptor.compare
+
+ long test_node = new PDOMTag(db, test_record).getNode();
+
+ // -1 if record < key, 0 if record == key, 1 if record > key
+ return Long.valueOf(test_node).compareTo(searchRecord);
+ }
+
+ @Override
+ public boolean visit(long existing_record) throws CoreException {
+ PDOMTag existingTag = new PDOMTag(db, existing_record);
+ String taggerId = existingTag.getTaggerId();
+
+ ITag newTag = newTags.remove(taggerId);
+ if (newTag == null) {
+ toRemove.add(Long.valueOf(existing_record));
+ } else if (newTag.getDataLen() > existingTag.getDataLen()) {
+ toRemove.add(Long.valueOf(existing_record));
+
+ PDOMTag pdomTag = existingTag.cloneWith(newTag.getBytes(0, -1));
+ if (pdomTag != null)
+ toInsert.add(Long.valueOf(pdomTag.getRecord()));
+ } else if (!existingTag.putBytes(0, newTag.getBytes(0, -1), -1))
+ CCorePlugin
+ .log("Unable to modify data of tag record " + existing_record + " from taggerId " + taggerId); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // try to visit the full tree
+ return true;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java
new file mode 100644
index 0000000..5714ee6
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java
@@ -0,0 +1,51 @@
+/*
+ * 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
+ *
+ * Contributors:
+ * Andrew Eidsness - Initial implementation
+ */
+
+package org.eclipse.cdt.internal.core.pdom.tag;
+
+import org.eclipse.cdt.core.dom.ast.tag.ITag;
+import org.eclipse.cdt.core.dom.ast.tag.ITagReader;
+import org.eclipse.cdt.core.dom.ast.tag.ITagWriter;
+import org.eclipse.cdt.core.dom.ast.tag.IWritableTag;
+import org.eclipse.cdt.internal.core.pdom.PDOM;
+
+/**
+ * A container for things that can be tagged and then stored in the index database.
+ */
+public class PDOMTaggable implements ITagReader, ITagWriter {
+ private final PDOM pdom;
+ private final long record;
+
+ public PDOMTaggable(PDOM pdom, long record) {
+ this.pdom = pdom;
+ this.record = record;
+ }
+
+ @Override
+ public IWritableTag createTag(String id, int len) {
+ return PDOMTagIndex.createTag(pdom, record, id, len);
+ }
+
+ @Override
+ public ITag getTag(String id) {
+ return PDOMTagIndex.getTag(pdom, record, id);
+ }
+
+ @Override
+ public Iterable<ITag> getTags() {
+ return PDOMTagIndex.getTags(pdom, record);
+ }
+
+ @Override
+ public boolean setTags(Iterable<ITag> tags) {
+ return PDOMTagIndex.setTags(pdom, record, tags);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/plugin.properties b/core/org.eclipse.cdt.core/plugin.properties
index 46e1547..287ee25 100644
--- a/core/org.eclipse.cdt.core/plugin.properties
+++ b/core/org.eclipse.cdt.core/plugin.properties
@@ -121,6 +121,7 @@ CConfigurationDataProvider.name = CConfigurationData provider
projectConverter.name = project converter
CIndex.name = CIndex
externalSettingsProvider.name = External Settings provider
+tagger.name = Parser Node Tagger Extension Point
GeneratePDOMApplication.name = GeneratePDOM
defaultProvider.name = Default Provider
templatesExtensionPoint.name = Templates Extension point
diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml
index bb1125c..4b2e257 100644
--- a/core/org.eclipse.cdt.core/plugin.xml
+++ b/core/org.eclipse.cdt.core/plugin.xml
@@ -42,6 +42,7 @@
<extension-point id="projectConverter" name="%projectConverter.name" schema="schema/projectConverter.exsd"/>
<extension-point id="CIndex" name="%CIndex.name" schema="schema/CIndex.exsd"/>
<extension-point id="externalSettingsProvider" name="%externalSettingsProvider.name" schema="schema/externalSettingsProvider.exsd"/>
+ <extension-point id="tagger" name="%tagger.name" schema="schema/tagger.exsd"/>
<!-- =================================================================================== -->
<!-- CProjectDescriptionStorage provides addition types of project description storage -->
<!-- =================================================================================== -->
diff --git a/core/org.eclipse.cdt.core/schema/tagger.exsd b/core/org.eclipse.cdt.core/schema/tagger.exsd
new file mode 100644
index 0000000..98d3768
--- /dev/null
+++ b/core/org.eclipse.cdt.core/schema/tagger.exsd
@@ -0,0 +1,139 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.cdt.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.cdt.core" id="tagger" name="Node Tagger"/>
+ </appInfo>
+ <documentation>
+ This extension point allows extensions to contribute to the parsed nodes. When PDOM nodes are tagged, the content of the tag is stored in to the Database. The information for other nodes, e.g., the AST, is stored in memory.
+ </documentation>
+ </annotation>
+
+ <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
+
+ <element name="extension">
+ <annotation>
+ <appInfo>
+ <meta.element />
+ </appInfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="bindingTagger" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ a fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ an optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ an optional name of the extension instance
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="bindingTagger">
+ <complexType>
+ <sequence>
+ </sequence>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.cdt.core.dom.ast.tag.IBindingTagger"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ <attribute name="local-id" type="string" use="required">
+ <annotation>
+ <documentation>
+ A unique identifier for this tagger&apos;s contributions.
+
+The local id will be appended to the contributing plugin&apos;s id (separated with a dot &apos;.&apos;) to form the globally unique identifier for this tagger. This id is used to uniquely associate the tag with this plugin.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ 8.2
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ The following is an example of a Tagger contribution:
+&lt;p&gt;
+&lt;pre&gt;
+&lt;extension
+ point=&quot;org.eclipse.cdt.core.tagger&quot;
+ id=&quot;example&quot;
+ name=&quot;Example Tagger Extension&quot;&gt;
+ &lt;bindingTagger
+ local-id=&quot;my-tagger&quot;
+ class=&quot;com.example.internal.ExampleTagger&quot;&gt;
+ &lt;enablement&gt;
+ &lt;with variable=&quot;projectNatures&quot;&gt;
+ &lt;iterate operator=&quot;or&quot;&gt;
+ &lt;equals value=&quot;com.example.my-nature&quot;/&gt;
+ &lt;/iterate&gt;
+ &lt;/with&gt;
+ &lt;/enablement&gt;
+ &lt;/bindingTagger&gt;
+&lt;/extension&gt;
+&lt;/pre&gt;
+&lt;/p&gt;
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ The contributed class must implement &lt;code&gt;org.eclipse.cdt.core.dom.ast.tag.IBindingTagger&lt;/code&gt;
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ 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
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
index 22a2290..b5fc7a7 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java
@@ -26,6 +26,7 @@ import java.util.ResourceBundle;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.cdtvariables.IUserVarSupplier;
import org.eclipse.cdt.core.dom.IPDOMManager;
+import org.eclipse.cdt.core.dom.ast.tag.ITagService;
import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
@@ -50,6 +51,7 @@ import org.eclipse.cdt.internal.core.ICConsole;
import org.eclipse.cdt.internal.core.PositionTrackerManager;
import org.eclipse.cdt.internal.core.cdtvariables.CdtVariableManager;
import org.eclipse.cdt.internal.core.cdtvariables.UserVarSupplier;
+import org.eclipse.cdt.internal.core.dom.ast.tag.TagService;
import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager;
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsScannerInfoProvider;
import org.eclipse.cdt.internal.core.model.CModelManager;
@@ -214,6 +216,8 @@ public class CCorePlugin extends Plugin {
private PDOMManager pdomManager;
+ private ITagService tagService = new TagService();
+
private CdtVarPathEntryVariableManager fPathEntryVariableManager;
private final class NullConsole implements IConsole {
@@ -713,6 +717,13 @@ public class CCorePlugin extends Plugin {
return getDefault().pdomManager;
}
+ /**
+ * @since 5.5
+ */
+ public static ITagService getTagService() {
+ return getDefault().tagService;
+ }
+
public IPathEntryVariableManager getPathEntryVariableManager() {
return fPathEntryVariableManager;
}
diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java
index 733e088..63d22a4 100644
--- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java
+++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java
@@ -156,7 +156,7 @@ public class QtCompletionProposalComputer extends ParsingBasedProposalComputer
return false;
int result = tag.getByte( 0 );
- return result != ITag.Fail
+ return result != ITag.FAIL
&& ( ( result & QtPlugin.SignalSlot_Mask_signal ) == QtPlugin.SignalSlot_Mask_signal );
}
};
@@ -175,7 +175,7 @@ public class QtCompletionProposalComputer extends ParsingBasedProposalComputer
return false;
int result = tag.getByte( 0 );
- return result != ITag.Fail
+ return result != ITag.FAIL
&& ( ( result & QtPlugin.SignalSlot_Mask_slot ) == QtPlugin.SignalSlot_Mask_slot );
}
};