From c6c1ef94fc37b4a3cab7f2ef1b66e82ceaddc03d Mon Sep 17 00:00:00 2001 From: Andrew Eidsness Date: Thu, 12 Dec 2013 07:40:51 -0500 Subject: Fix Qt plugin's project structure The Qt plugins have been naming internal packages using two different prefixes: cdt.qt.internal cdt.internal.qt This renames all packages to cdt.internal.qt, which seems to be the convention for other projects. I've increased the Qt plugin versions because alot of new API has been added, especially to the qt.core plugin. I increased the version in the MANIFEST.MF and pom.xml files. I've also fixed the MANIFEST.MF files to take CDT out of the plugin names. I've also replaced a call to CCorePlugin.log(Exception) with a call to QtUIPlugin.log (and added the logging functions to QtUIPlugin. Change-Id: I1e3e7b2a42c2eb79fe33608c14a1abcf013a9f2c Signed-off-by: Andrew Eidsness Reviewed-on: https://git.eclipse.org/r/19698 Tested-by: Hudson CI Reviewed-by: Doug Schaefer IP-Clean: Doug Schaefer --- qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF | 6 +- qt/org.eclipse.cdt.qt.core/plugin.properties | 5 +- qt/org.eclipse.cdt.qt.core/plugin.xml | 6 +- qt/org.eclipse.cdt.qt.core/pom.xml | 2 +- .../cdt/internal/qt/core/QtIncludePaths.java | 282 +++++++++++++ .../internal/qt/core/QtIncludePathsProvider.java | 133 ++++++ .../eclipse/cdt/internal/qt/core/QtMethodUtil.java | 345 ++++++++++++++++ .../cdt/internal/qt/core/index/AbstractQField.java | 38 ++ .../cdt/internal/qt/core/index/CDTIndex.java | 62 +++ .../eclipse/cdt/internal/qt/core/index/QEnum.java | 69 ++++ .../cdt/internal/qt/core/index/QMethod.java | 99 +++++ .../cdt/internal/qt/core/index/QObject.java | 146 +++++++ .../cdt/internal/qt/core/index/QObjectMembers.java | 86 ++++ .../cdt/internal/qt/core/index/QProperty.java | 106 +++++ .../cdt/internal/qt/core/index/QtFactory.java | 122 ++++++ .../cdt/internal/qt/core/index/QtIndexImpl.java | 66 +++ .../internal/qt/core/pdom/ASTDelegatedName.java | 230 +++++++++++ .../internal/qt/core/pdom/ASTNameReference.java | 109 +++++ .../qt/core/pdom/AbstractQObjectMemberName.java | 123 ++++++ .../cdt/internal/qt/core/pdom/IQtASTName.java | 21 + .../cdt/internal/qt/core/pdom/IQtPDOMCodec.java | 39 ++ .../qt/core/pdom/PDOMQtLinkageFactory.java | 33 ++ .../cdt/internal/qt/core/pdom/QMethodName.java | 31 ++ .../cdt/internal/qt/core/pdom/QObjectName.java | 121 ++++++ .../cdt/internal/qt/core/pdom/QtASTClass.java | 380 +++++++++++++++++ .../internal/qt/core/pdom/QtASTImageLocation.java | 88 ++++ .../cdt/internal/qt/core/pdom/QtASTVisitor.java | 454 +++++++++++++++++++++ .../cdt/internal/qt/core/pdom/QtEnumName.java | 32 ++ .../internal/qt/core/pdom/QtPDOMASTProcessor.java | 24 ++ .../cdt/internal/qt/core/pdom/QtPDOMArray.java | 127 ++++++ .../cdt/internal/qt/core/pdom/QtPDOMBinding.java | 81 ++++ .../cdt/internal/qt/core/pdom/QtPDOMLinkage.java | 221 ++++++++++ .../cdt/internal/qt/core/pdom/QtPDOMNodeType.java | 61 +++ .../cdt/internal/qt/core/pdom/QtPDOMProperty.java | 174 ++++++++ .../cdt/internal/qt/core/pdom/QtPDOMQEnum.java | 113 +++++ .../cdt/internal/qt/core/pdom/QtPDOMQMethod.java | 115 ++++++ .../cdt/internal/qt/core/pdom/QtPDOMQObject.java | 254 ++++++++++++ .../cdt/internal/qt/core/pdom/QtPDOMVisitor.java | 109 +++++ .../qt/core/pdom/QtPropertyAttributeName.java | 32 ++ .../cdt/internal/qt/core/pdom/QtPropertyName.java | 61 +++ .../src/org/eclipse/cdt/qt/core/index/QtIndex.java | 2 +- .../cdt/qt/internal/core/QtIncludePaths.java | 282 ------------- .../qt/internal/core/QtIncludePathsProvider.java | 133 ------ .../eclipse/cdt/qt/internal/core/QtMethodUtil.java | 345 ---------------- .../cdt/qt/internal/core/index/AbstractQField.java | 38 -- .../cdt/qt/internal/core/index/CDTIndex.java | 62 --- .../eclipse/cdt/qt/internal/core/index/QEnum.java | 69 ---- .../cdt/qt/internal/core/index/QMethod.java | 99 ----- .../cdt/qt/internal/core/index/QObject.java | 146 ------- .../cdt/qt/internal/core/index/QObjectMembers.java | 86 ---- .../cdt/qt/internal/core/index/QProperty.java | 106 ----- .../cdt/qt/internal/core/index/QtFactory.java | 122 ------ .../cdt/qt/internal/core/index/QtIndexImpl.java | 66 --- .../qt/internal/core/pdom/ASTDelegatedName.java | 230 ----------- .../qt/internal/core/pdom/ASTNameReference.java | 109 ----- .../core/pdom/AbstractQObjectMemberName.java | 123 ------ .../cdt/qt/internal/core/pdom/IQtASTName.java | 21 - .../cdt/qt/internal/core/pdom/IQtPDOMCodec.java | 39 -- .../internal/core/pdom/PDOMQtLinkageFactory.java | 33 -- .../cdt/qt/internal/core/pdom/QMethodName.java | 31 -- .../cdt/qt/internal/core/pdom/QObjectName.java | 121 ------ .../cdt/qt/internal/core/pdom/QtASTClass.java | 380 ----------------- .../qt/internal/core/pdom/QtASTImageLocation.java | 88 ---- .../cdt/qt/internal/core/pdom/QtASTVisitor.java | 454 --------------------- .../cdt/qt/internal/core/pdom/QtEnumName.java | 32 -- .../qt/internal/core/pdom/QtPDOMASTProcessor.java | 24 -- .../cdt/qt/internal/core/pdom/QtPDOMArray.java | 127 ------ .../cdt/qt/internal/core/pdom/QtPDOMBinding.java | 81 ---- .../cdt/qt/internal/core/pdom/QtPDOMLinkage.java | 221 ---------- .../cdt/qt/internal/core/pdom/QtPDOMNodeType.java | 61 --- .../cdt/qt/internal/core/pdom/QtPDOMProperty.java | 174 -------- .../cdt/qt/internal/core/pdom/QtPDOMQEnum.java | 113 ----- .../cdt/qt/internal/core/pdom/QtPDOMQMethod.java | 115 ------ .../cdt/qt/internal/core/pdom/QtPDOMQObject.java | 254 ------------ .../cdt/qt/internal/core/pdom/QtPDOMVisitor.java | 109 ----- .../core/pdom/QtPropertyAttributeName.java | 32 -- .../cdt/qt/internal/core/pdom/QtPropertyName.java | 61 --- qt/org.eclipse.cdt.qt.tests/META-INF/MANIFEST.MF | 5 +- qt/org.eclipse.cdt.qt.tests/plugin.properties | 8 + qt/org.eclipse.cdt.qt.tests/pom.xml | 2 +- qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF | 8 +- qt/org.eclipse.cdt.qt.ui/plugin.properties | 3 + qt/org.eclipse.cdt.qt.ui/plugin.xml | 2 +- qt/org.eclipse.cdt.qt.ui/pom.xml | 2 +- .../qt/ui/QtCompletionProposalComputer.java | 391 ++++++++++++++++++ .../internal/ui/QtCompletionProposalComputer.java | 390 ------------------ .../src/org/eclipse/cdt/qt/ui/QtUIPlugin.java | 45 ++ 87 files changed, 5056 insertions(+), 4995 deletions(-) create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePaths.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePathsProvider.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtMethodUtil.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/AbstractQField.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/CDTIndex.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QEnum.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QMethod.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObject.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObjectMembers.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QProperty.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtFactory.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtIndexImpl.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTDelegatedName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTNameReference.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQObjectMemberName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtASTName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtPDOMCodec.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/PDOMQtLinkageFactory.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QMethodName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QObjectName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTClass.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTImageLocation.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTVisitor.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtEnumName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMASTProcessor.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMArray.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMBinding.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMLinkage.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMNodeType.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMProperty.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQEnum.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQMethod.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQObject.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMVisitor.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyAttributeName.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePaths.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePathsProvider.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtMethodUtil.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/AbstractQField.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/CDTIndex.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QEnum.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QMethod.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObject.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObjectMembers.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QProperty.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtFactory.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtIndexImpl.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTDelegatedName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTNameReference.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/AbstractQObjectMemberName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtASTName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtPDOMCodec.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/PDOMQtLinkageFactory.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QMethodName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QObjectName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTClass.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTImageLocation.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTVisitor.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtEnumName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMASTProcessor.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMArray.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMBinding.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMLinkage.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMNodeType.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMProperty.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQEnum.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQMethod.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQObject.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMVisitor.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyAttributeName.java delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyName.java create mode 100644 qt/org.eclipse.cdt.qt.tests/plugin.properties create mode 100644 qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QtCompletionProposalComputer.java delete mode 100644 qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java (limited to 'qt') diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 0d10edde6e4..e11a2c6eb58 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -1,10 +1,10 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: CDT Qt Support Core +Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.qt.core;singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.1.0.qualifier Bundle-Activator: org.eclipse.cdt.qt.core.QtPlugin -Bundle-Vendor: Eclipse CDT +Bundle-Vendor: %providerName Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources, org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)", diff --git a/qt/org.eclipse.cdt.qt.core/plugin.properties b/qt/org.eclipse.cdt.qt.core/plugin.properties index 322b6ca7011..b66c9d0ff85 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.properties +++ b/qt/org.eclipse.cdt.qt.core/plugin.properties @@ -4,7 +4,10 @@ # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html +pluginName=C/C++ Qt Support Core +providerName=Eclipse CDT + qtProjectFile.name = Qt Project File qmlFile.name = QML File qmakeEnvProvider.name = QMake Environment Provider -QtInstallHeaders.pathProvider.name = Qt Installed Headers \ No newline at end of file +QtInstallHeaders.pathProvider.name = Qt Installed Headers diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml index e1e3cc1de54..aa0f7908f27 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.xml +++ b/qt/org.eclipse.cdt.qt.core/plugin.xml @@ -67,7 +67,7 @@ id="qt.PDOMASTProcessor" name="Qt PDOM AST Processor"> + class="org.eclipse.cdt.internal.qt.core.pdom.QtPDOMASTProcessor"> @@ -80,11 +80,11 @@ + class="org.eclipse.cdt.internal.qt.core.pdom.PDOMQtLinkageFactory"/> diff --git a/qt/org.eclipse.cdt.qt.core/pom.xml b/qt/org.eclipse.cdt.qt.core/pom.xml index 8862e5515a0..b7ed0d0bfd6 100644 --- a/qt/org.eclipse.cdt.qt.core/pom.xml +++ b/qt/org.eclipse.cdt.qt.core/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT org.eclipse.cdt.qt.core eclipse-plugin diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePaths.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePaths.java new file mode 100644 index 00000000000..3ab4504e18e --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePaths.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider; +import org.eclipse.cdt.core.settings.model.CIncludePathEntry; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.cdt.core.settings.model.ICSettingEntry; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.resources.IResource; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Discovers and persists the list of Qt include paths for a particular installation of + * Qt. The Qt installation is described by the path to qmake. + *

+ * Qt uses a tool called qmake to generate makefiles for Qt projects. The tool has a + * query mode that can be used to discover information about the Qt installation. Here + * qmake is used to build a list of all installed Qt include paths. + *

+ * These paths are persisted into a file called language-settings.xml in the workspace + * metadata area. + * + * @see QtIncludePathsProvider + */ +public class QtIncludePaths extends LanguageSettingsSerializableProvider { + + /** + * The path to the qmake executable uniquely identifies this installation. + */ + private final String qmakePath; + + /** + * The cached data is reloaded when the qmake executable is modified. + */ + private long qmakeModTime; + + /** + * The cached data is reloaded when the folder holding the include paths + * is removed. + */ + private String qtInstallHeadersPath; + + /** + * The cached data is reloaded when the folder containing the include folders is + * modified. + */ + private long qtInstallHeadersModTime; + + private static final String ATTR_QMAKE = "qmake"; + private static final String ATTR_QMAKE_MOD = "qmakeModification"; + private static final String ATTR_QT_INSTALL_HEADERS = "QT_INSTALL_HEADERS"; + private static final String ATTR_QT_INSTALL_HEADERS_MOD = "qtInstallHeadersModification"; + + /** + * Create a new instance of the include path wrapper for the Qt installation for + * the given qmake binary. + */ + public QtIncludePaths(String qmakePath) { + this.qmakePath = qmakePath; + } + + /** + * Create and load an instance of QtIncludePaths from data that was serialized into the + * given XML element. Return null if an instance cannot be loaded or if the installation + * is no longer valid. + */ + public static QtIncludePaths loadFrom(Node node) { + if (node.getNodeType() != Node.ELEMENT_NODE) + return null; + + Element element = (Element) node; + String qmakePath = element.getAttribute(ATTR_QMAKE); + if (qmakePath == null + || qmakePath.isEmpty()) + return null; + + QtIncludePaths qtIncludePaths = new QtIncludePaths(qmakePath); + qtIncludePaths.load(element); + return qtIncludePaths; + } + + public String getQMakePath() { + return qmakePath; + } + + /** + * Return true if the receiver points to a valid Qt installation and false otherwise. + * The installation is considered valid if an executable qmake binary exists at the + * expected location. + */ + public boolean isValid() { + if (qmakePath == null + || qmakePath.isEmpty()) + return false; + + File qmake = new File(qmakePath); + return qmake.exists() + && qmake.canExecute(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof QtIncludePaths)) + return super.equals(obj); + + // Include paths are equivalent when they point to the same qmake binary. All other + // values are reloaded from that binary and do not need to be directly compared. + QtIncludePaths other = (QtIncludePaths) obj; + return qmakePath == null ? other.qmakePath == null : qmakePath.equals(other.qmakePath); + } + + @Override + public int hashCode() { + return qmakePath == null ? 0 : qmakePath.hashCode(); + } + + /** + * Return a current list of the include paths for this Qt installation. Return null if + * no such paths can be found. + *

+ * Updates the cached results if needed. If the settings are updated then the new list + * will be serialized into the workspace metadata area. + */ + @Override + public List getSettingEntries(ICConfigurationDescription configDesc, IResource rc, String languageId) { + List entries = null; + + File qmake = new File(qmakePath); + if (!qmake.exists() + || qmakeModTime != qmake.lastModified()) + entries = reload(); + else { + File qtInstallHeadersDir = new File(qtInstallHeadersPath); + if (!qtInstallHeadersDir.exists() + || qtInstallHeadersModTime != qtInstallHeadersDir.lastModified()) + entries = reload(); + } + + // If the cache was not reloaded, then return the previously discovered entries. + if (entries == null) + return super.getSettingEntries(configDesc, rc, languageId); + + // Otherwise store, persist, and return the newly discovered values. + setSettingEntries(configDesc, rc, languageId, entries); + serializeLanguageSettingsInBackground(null); + return entries; + } + + @Override + public Element serializeAttributes(Element parentElement) { + parentElement.setAttribute(ATTR_QMAKE, qmakePath); + parentElement.setAttribute(ATTR_QMAKE_MOD, Long.toString(qmakeModTime)); + parentElement.setAttribute(ATTR_QT_INSTALL_HEADERS, qtInstallHeadersPath); + parentElement.setAttribute(ATTR_QT_INSTALL_HEADERS_MOD, Long.toString(qtInstallHeadersModTime)); + + // The parent implementation tries to create a new child node (provider) that is used + // as the part for later entries. This isn't needed in this case, we just want to + // use the part that serializes the languages. + return parentElement; + } + + @Override + public void loadAttributes(Element element) { + qmakeModTime = getLongAttribute(element, ATTR_QMAKE_MOD); + qtInstallHeadersPath = element.getAttribute(ATTR_QT_INSTALL_HEADERS); + qtInstallHeadersModTime = getLongAttribute(element, ATTR_QT_INSTALL_HEADERS_MOD); + + // The parent implementation tries to create a new child node (provider) that is used + // as the part for later entries. This isn't needed in this case, we just want to + // use the part that serializes the languages. + } + + /** + * Parse and return the given attribute as a long. Return 0 if the attribute does + * not have a valid value. + */ + private static long getLongAttribute(Element element, String attr) { + String value = element.getAttribute(attr); + if (value == null + || value.isEmpty()) + return 0; + + try { + return Long.parseLong(value); + } catch(NumberFormatException e) { + QtPlugin.log("attribute name:" + attr + " value:" + value, e); + return 0; + } + } + + /** + * Reload and return the entries if possible, return null otherwise. + */ + private List reload() { + // All keys are reset and then updated as their values are discovered. This allows partial + // success to skip over previously calculated values. + qmakeModTime = 0; + qtInstallHeadersPath = null; + qtInstallHeadersModTime = 0; + + File qmake = new File(qmakePath); + if (!qmake.exists() + || !qmake.canExecute()) + return Collections.emptyList(); + + qmakeModTime = qmake.lastModified(); + + // Run `qmake -query QT_INSTALL_HEADERS` to get output like "/opt/qt-5.0.0/include". + BufferedReader reader = null; + Process process = null; + try { + process = ProcessFactory.getFactory().exec(new String[]{ qmakePath, "-query", "QT_INSTALL_HEADERS" }); + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + qtInstallHeadersPath = reader.readLine(); + } catch(IOException e) { + QtPlugin.log(e); + } finally { + try { + if (reader != null) + reader.close(); + } catch(IOException e) { + /* ignore */ + } finally { + if (process != null) + process.destroy(); + } + } + + if (qtInstallHeadersPath == null) + return Collections.emptyList(); + + File qtInstallHeadersDir = new File(qtInstallHeadersPath); + + qtInstallHeadersModTime = qtInstallHeadersDir.lastModified(); + if (!qtInstallHeadersDir.exists() + || !qtInstallHeadersDir.canRead() + || !qtInstallHeadersDir.isDirectory()) + return Collections.emptyList(); + + // Create an include path entry for all sub-folders in the QT_INSTALL_HEADERS location, including + // the QT_INSTALL_HEADERS folder itself. + File[] files = qtInstallHeadersDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.exists() && pathname.isDirectory(); + } + }); + + List entries = new ArrayList(files.length + 1); + safeAdd(entries, qtInstallHeadersDir); + for(File file : files) + safeAdd(entries, file); + + return entries; + } + + private static void safeAdd(List entries, File file) { + try { + entries.add(new CIncludePathEntry(file.getCanonicalPath(), ICSettingEntry.READONLY | ICSettingEntry.RESOLVED)); + } catch(IOException e) { + QtPlugin.log(e); + } + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePathsProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePathsProvider.java new file mode 100644 index 00000000000..fa832c66d79 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtIncludePathsProvider.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.envvar.IEnvironmentVariable; +import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider; +import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; +import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; +import org.eclipse.core.resources.IResource; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This provider uses persistent cache to store the include paths for different + * Qt installations. A Qt installation is uniquely identified by the path to + * the qmake binary within the installation. + *

+ * This result is shared among all Build Configurations that use the provider + * with the same value for the QMAKE environment variable. + */ +public class QtIncludePathsProvider extends LanguageSettingsSerializableProvider { + + /** + * The provider identifies Qt installations by the absolute path to the qmake binary. The + * include paths relevant to the installations are computed and persisted in {@link QtIncludePaths}. + */ + private final Map qtInstallHeaders = new HashMap(); + + /** + * The build configuration stores the path to the qmake binary as an environment variable. + */ + private static final String ENVVAR_QMAKE = "QMAKE"; + + private static final String ELEMENT_QMAKE = "qmake"; + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof QtIncludePathsProvider)) + return super.equals(obj); + + /** + * Providers are equal when they have the same cached values. + */ + QtIncludePathsProvider other = (QtIncludePathsProvider) obj; + if (qtInstallHeaders == null) + return other.qtInstallHeaders == null; + return qtInstallHeaders.equals(other.qtInstallHeaders); + } + + @Override + public int hashCode() { + return qtInstallHeaders == null ? 0 : qtInstallHeaders.hashCode(); + } + + @Override + public void loadEntries(Element providerNode) { + super.loadEntries(providerNode); + + // Find and load all qmake child nodes. There will be one node for each Qt + // installation that has been used. Qt installations that are no longer valid + // are not loaded. This means they will be removed from the file the next time + // that the language setting providers are serialized. + NodeList children = providerNode.getChildNodes(); + for (int i = 0; i < children.getLength(); ++i) { + Node child = children.item(i); + if (ELEMENT_QMAKE.equals(child.getNodeName())) { + QtIncludePaths qtIncludePaths = QtIncludePaths.loadFrom(child); + if (qtIncludePaths != null + && qtIncludePaths.isValid()) + qtInstallHeaders.put(qtIncludePaths.getQMakePath(), qtIncludePaths); + } + } + } + + @Override + public void serializeEntries(Element parent) { + // NOTE: This creates its own XML structure where children of the provider node are qmake nodes. + // Within each qmake node is a list of include paths for that installation. Calling the + // base #serializeEntries here would try to write this instance's (empty) list of settings + // to the file. + + // Each value is serialized into a new element in the XML document. + Document document = parent instanceof Document ? (Document)parent : parent.getOwnerDocument(); + for(QtIncludePaths qtIncludePaths : qtInstallHeaders.values()) { + Element child = document.createElement(ELEMENT_QMAKE); + qtIncludePaths.serialize(child); + parent.appendChild(child); + } + } + + /** + * The given build configuration's QMAKE environment variable is used to identify the appropriate + * Qt installation. The language settings are then either returned from the previously persisted + * data or loaded, serialized, and returned. + */ + @Override + public synchronized List getSettingEntries(ICConfigurationDescription configDesc, IResource rc, String languageId) { + // Make sure the requested language is in scope for this provider. + if (!getLanguageScope().contains(languageId)) + return null; + + // The value of the build configuration's QMAKE environment variable is used to select the + // right version of qmake. + IEnvironmentVariable qmake_var = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENVVAR_QMAKE, configDesc, true); + if (qmake_var == null) + return null; + + String qmake = qmake_var.getValue(); + if (qmake == null) + return null; + + // The path to qmake is used as the key into the in-memory cache of header paths. + QtIncludePaths paths = qtInstallHeaders.get(qmake); + if (paths == null) { + paths = new QtIncludePaths(qmake); + qtInstallHeaders.put(qmake, paths); + } + + return paths.getSettingEntries(configDesc, null, languageId); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtMethodUtil.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtMethodUtil.java new file mode 100644 index 00000000000..bb38d44b43e --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/QtMethodUtil.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.DatatypeConverter; + +import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTPointer; +import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; +import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; +import org.eclipse.cdt.internal.qt.core.parser.QtParser; + +/** + * A collection of utility functions for dealing with Qt methods. A Qt method is a normal + * C++ method that has been annotated with empty macro expansions. + */ +@SuppressWarnings("restriction") +public class QtMethodUtil { + + /** + * The Qt implementation uses specific rules for generating a signature that is used + * to map between invokable function declarations and their use. This function has + * be implemented by comparing the output of moc to the various test cases in the + * qt test suite. + */ + public static String getQtNormalizedMethodSignature(String signature) { + + ICPPASTFunctionDeclarator function = QtParser.parseQtMethodReference(signature); + if (function == null) + return null; + + // NOTE: This implementation (both here and in methods that are invoked) used call #getRawSignature + // to get the original tokens. This has been changed to use #toString instead. They seem to + // provide the same value, so this should be OK. The problem with #getRawSignature is that it + // looks for the characters in the file (using offset and length). There isn't a file backing + // the StringScanner, so the result is the empty String. If we find cases where #toString + // returns the wrong value, then this can be changed back to #getRawSignature. Implement the + // AST and LocationResolver to work with ASTNode#getRawSignatureChars: + // protected char[] getRawSignatureChars() { + // final IASTFileLocation floc= getFileLocation(); + // final IASTTranslationUnit ast = getTranslationUnit(); + // if (floc != null && ast != null) { + // ILocationResolver lr= (ILocationResolver) ast.getAdapter(ILocationResolver.class); + // if (lr != null) { + // return lr.getUnpreprocessedSignature(getFileLocation()); + // } + // } + + StringBuilder result = new StringBuilder(); + + // raw sig tries to find the file + String fnName = function.getName().getLastName().toString(); + result.append(stripWS(fnName)); + result.append('('); + + boolean first = true; + for(ICPPASTParameterDeclaration param : function.getParameters()) { + if (first) + first = false; + else + result.append(','); + + IASTDeclSpecifier spec = param.getDeclSpecifier(); + ICPPASTDeclarator declarator = param.getDeclarator(); + + // The parameters are encoded so that we can rely on , being used to separate + // parameters. All other commas (e.g., to separate template arguments within + // the parameter type) will be encoded. + StringBuilder paramSig = new StringBuilder(); + append(paramSig, spec, declarator, true); + + result.append(stripWS(paramSig.toString())); + } + + result.append(')'); + + // Whitespace around operators is not needed, remove it to normalize the signature. + return result.toString(); + } + + public static Collection getDecodedQtMethodSignatures(String qtEncSignatures) { + if (qtEncSignatures == null) + return null; + + StringBuilder signature = new StringBuilder(); + int i = qtEncSignatures.indexOf('('); + String name = qtEncSignatures.substring(0, i); + + signature.append(name); + signature.append('('); + + boolean first = true; + List signatures = new ArrayList(); + qtEncSignatures = qtEncSignatures.substring(i + 1); + Pattern p = Pattern.compile("^([a-zA-Z0-9+/=]*)(@?).*$"); + while(!qtEncSignatures.isEmpty()) { + Matcher m = p.matcher(qtEncSignatures); + if (!m.matches()) + break; + + int next = m.end(2) + 1; + qtEncSignatures = qtEncSignatures.substring(next); + + String param = new String(DatatypeConverter.parseBase64Binary(m.group(1))); + + // If this parameter has a default value, then add a signature for the method up + // to this point. + if (!m.group(2).isEmpty()) + signatures.add(signature.toString() + ')'); + + if (first) + first = false; + else + signature.append(','); + signature.append(param); + } + + signature.append(')'); + signatures.add(signature.toString()); + return signatures; + } + + /** + * The Qt implementation has specific rules for generating a signature that is used + * to map between invokable function declarations and their use. This function has + * been implemented by comparing the output of moc to the various test cases in the + * Qt test suite. + */ + public static String getEncodedQtMethodSignatures(ICPPASTFunctionDeclarator function) { + StringBuilder result = new StringBuilder(); + + String fnName = function.getName().getLastName().toString(); + result.append(stripWS(fnName)); + result.append('('); + + boolean first = true; + for(ICPPASTParameterDeclaration param : function.getParameters()) { + if (first) + first = false; + else + result.append(','); + + IASTDeclSpecifier spec = param.getDeclSpecifier(); + ICPPASTDeclarator declarator = param.getDeclarator(); + + // The parameters are encoded so that we can rely on , being used to separate + // parameters. All other commas (e.g., to separate template arguments within + // the parameter type) will be encoded. + StringBuilder paramSig = new StringBuilder(); + append(paramSig, spec, declarator, true); + + String paramStr = stripWS(paramSig.toString()); + result.append(DatatypeConverter.printBase64Binary(paramStr.getBytes())); + + // A special character is used as a suffix on parameters that have a default value. + // A previous version of this implementation used '=' within the Base64 encoded + // payload. Now that the initializer flag is outside of the payload, '=' is a bad + // choice because it is also a valid Base64 encoded character. + // Like all the other parts of this encoder, the @ must match the value that is used + // in the decoder. + if (declarator.getInitializer() != null) + result.append('@'); + } + + result.append(')'); + + // Whitespace around operators is not needed, remove it to normalize the signature. + return result.toString(); + } + + private static String stripWS(String str) { + return str + .trim() + .replaceAll("\\s+", " ") + .replaceAll(" ([\\*&,()<>]+)", "$1") + .replaceAll("([\\*&,()<>]+) ", "$1"); + } + + private static String asString(IASTPointerOperator ptr) { + if (ptr instanceof ICPPASTReferenceOperator) + return "&"; + if (ptr instanceof IASTPointer) { + StringBuilder str = new StringBuilder(); + IASTPointer astPtr = (IASTPointer) ptr; + str.append('*'); + if (astPtr.isConst()) + str.append(" const"); + if (astPtr.isVolatile()) + str.append(" volatile"); + return str.toString(); + } + + return ptr.toString(); + } + + private static void append(StringBuilder result, IASTDeclSpecifier spec, IASTDeclarator declarator, boolean pruneConst) { + IASTPointerOperator[] ptrs = declarator.getPointerOperators(); + if (ptrs == null) + ptrs = new IASTPointerOperator[0]; + + if (!(spec instanceof ICPPASTDeclSpecifier)) { + result.append(spec.toString()); + return; + } + + ICPPASTDeclSpecifier cppSpec = (ICPPASTDeclSpecifier) spec; + + // Qt considers the type const if it is marked as const, or if it is a reference + // and the previous pointer is const. I.e., we need this: + // const T& -> T + // const T* const & -> T* + boolean isConst = cppSpec.isConst(); + boolean stripLastPtrConst + = pruneConst + && !isConst + && (ptrs.length >= 2 + && ptrs[ptrs.length - 1] instanceof ICPPASTReferenceOperator + && ptrs[ptrs.length - 2] instanceof IASTPointer + && ((IASTPointer) ptrs[ptrs.length - 2]).isConst()); + + if (isConst || stripLastPtrConst) { + if (!pruneConst) + result.append("const "); + else { + // Qt signature generation converts const value and const reference types + // into simple value types. E.g., + // const T => T + // const T & => T + // From observation, they also convert const pointer to const to const + // pointers although I think that is a bug, because simple pointer to + // const are not converted to simple pointers. E.g., + // const T * => const T * + // const T * const => T * const + if (ptrs.length > 0) { + IASTPointerOperator lastPtr = ptrs[ptrs.length - 1]; + if (lastPtr instanceof ICPPASTReferenceOperator) + ptrs = Arrays.copyOf(ptrs, ptrs.length - 1); + else if (!(lastPtr instanceof IASTPointer) + || !((IASTPointer) lastPtr).isConst()) + result.append("const "); + } + } + } + + // Qt does no special handling for volatile. This is likely an oversight. + if (cppSpec.isVolatile()) + result.append("volatile "); + + IASTNode[] children = cppSpec.getChildren(); + if (children == null || children.length <= 0) { + // We use the raw signature to get the text that was used to reference the + // type (without following typedefs, etc.), and then strip out all const + // which has already been handled. + String raw = cppSpec.toString(); + raw = raw.replaceAll("const\\s", ""); + raw = raw.replaceAll("\\sconst", ""); + result.append(raw); + } else { + for(IASTNode child : children) { + result.append( ' ' ); + if (child instanceof ICPPASTTemplateId) { + ICPPASTTemplateId templId = (ICPPASTTemplateId) child; + result.append(templId.getTemplateName()); + result.append('<'); + for(IASTNode templArg : templId.getTemplateArguments()) { + append(result, templArg); + } + result.append('>'); + } else + result.append(child.toString()); + } + } + + // exclude param name, use '=' to indicate an initial value + for(int i = 0; i < ptrs.length; ++i) { + if (!stripLastPtrConst + || i < ptrs.length - 1) + result.append(asString(ptrs[i])); + else + result.append(asString(ptrs[i]).replaceAll("const", "")); + } + } + + private static void append(StringBuilder result, IASTNode node) { + + // JI476551: When the code is parsed without full context, e.g., when parsing a Qt method ref, an + // ambiguous node could be created. Since we only need the original text, we can use + // any of the nodes that triggered the ambiguity. Arbitrarily choose the first one. + if (node instanceof ASTAmbiguousNode) { + IASTNode[] nodes = ((ASTAmbiguousNode) node).getNodes(); + if (nodes != null + && nodes.length > 0) { + append(result, nodes[0]); + return; + } + } + + if (node instanceof ICPPASTTypeId) { + ICPPASTTypeId typeId = (ICPPASTTypeId) node; + IASTDeclSpecifier spec = typeId.getDeclSpecifier(); + IASTDeclarator declarator = typeId.getAbstractDeclarator(); + append(result, spec, declarator, false); + return; + } + + if (!(node instanceof ICPPASTTemplateId)) { + result.append(node.toString()); + return; + } + + ICPPASTTemplateId templId = (ICPPASTTemplateId) node; + result.append(templId.getTemplateName()); + result.append('<'); + boolean first = true; + for (IASTNode child : templId.getTemplateArguments()) { + if (first) + first = false; + else + result.append(", "); + append(result, child); + } + result.append('>'); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/AbstractQField.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/AbstractQField.java new file mode 100644 index 00000000000..a9f77cb2417 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/AbstractQField.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import org.eclipse.cdt.qt.core.index.IQObject; +import org.eclipse.cdt.qt.core.index.IQObject.IMember; + +public abstract class AbstractQField implements IQObject.IMember { + + private final IQObject owner; + protected String name; + + protected AbstractQField(IQObject owner) { + this.owner = owner; + } + + @Override + public IQObject getOwner() { + return owner; + } + + @Override + public boolean isOverride(IMember member) { + if (!AbstractQField.class.isAssignableFrom(member.getClass())) + return false; + + // I haven't been able to find Qt documentation describing how things like + // Q_PROPERY are overridden, but the docs suggest it is just by name. + + AbstractQField other = (AbstractQField) member; + return name == null ? other.name == null : name.equals(other.name); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/CDTIndex.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/CDTIndex.java new file mode 100644 index 00000000000..8886eb6d7e7 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/CDTIndex.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.core.runtime.CoreException; + +/** + * A wrapper around the CDT index that manages the read lock. + */ +public class CDTIndex { + + private final IIndex index; + + public CDTIndex(IIndex index) { + this.index = index; + } + + /** + * An object used for reading from the CDT index. The {@link #access(IIndex)} method + * will only be invoked when the index's read lock has been properly acquired. + */ + public static interface Accessor { + /** + * A method that performs the lookup within the CDT index. The read-lock will + * be acquired before invoking this method. + *

+ * The implementation of access must not make calls to {@link CDTIndex#get(Accessor)}. + * If other objects are needed, then have the accessor return a qualified name and + * lookup the object after the implementation of #access completes. + */ + public T access(IIndex index) throws CoreException; + } + + /** + * Use the given accessor to find and return a value from the index. This method ensures + * that the read-lock has been acquired. + */ + public T get(Accessor accessor) { + try { + index.acquireReadLock(); + } catch(InterruptedException e) { + return null; + } + + try { + return accessor.access(index); + } catch(CoreException e) { + QtPlugin.log( e ); + } finally { + index.releaseReadLock(); + } + + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QEnum.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QEnum.java new file mode 100644 index 00000000000..255a41efb88 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QEnum.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.cdt.core.dom.ast.IEnumerator; +import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.qt.core.index.IQEnum; + +public class QEnum implements IQEnum { + + private final String name; + private final boolean isFlag; + private final List enumerators; + + public QEnum(String name, boolean isFlag, List enumerators) { + this.name = name; + this.isFlag = isFlag; + this.enumerators = new ArrayList(enumerators.size()); + for (IEnumerator enumerator : enumerators) + this.enumerators.add(new Enumerator(enumerator)); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isFlag() { + return isFlag; + } + + @Override + public Collection getEnumerators() { + return enumerators; + } + + private static class Enumerator implements IQEnum.Enumerator { + + private final String name; + private final Long ordinal; + + public Enumerator(IEnumerator enumerator) { + this.name = enumerator.getName(); + + IValue val = enumerator.getValue(); + this.ordinal = val == null ? null : val.numericalValue(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Long getOrdinal() { + return ordinal; + } + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QMethod.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QMethod.java new file mode 100644 index 00000000000..7bf8e3188cd --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QMethod.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.internal.qt.core.QtMethodUtil; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQMethod; +import org.eclipse.cdt.qt.core.index.IQMethod; +import org.eclipse.cdt.qt.core.index.IQObject; +import org.eclipse.cdt.qt.core.index.IQObject.IMember; +import org.eclipse.core.runtime.CoreException; + +public class QMethod implements IQMethod { + + private final IQObject owner; + private final String name; + private final IQMethod.Kind kind; + private final Collection signatures; + private final Long revision; + + public QMethod(IQObject owner, QtPDOMQMethod pdom) throws CoreException { + this.owner = owner; + this.name = pdom.getName(); + this.kind = pdom.getKind(); + this.signatures = QtMethodUtil.getDecodedQtMethodSignatures(pdom.getQtEncodedSignatures()); + this.revision = pdom.getRevision(); + } + + @Override + public boolean isOverride(IMember member) { + if (!IQMethod.class.isAssignableFrom(member.getClass())) + return false; + + // Methods override when they have the same name and type. + + IQMethod other = (IQMethod) member; + + if (name == null) { + if (other.getName() != null) + return false; + } else if (!name.equals(other.getName())) + return false; + + IBinding otherBinding = other.getBinding(); + if (otherBinding == null) + return getBinding() == null; + + return false ;// TODO +// if (!ICPPMethod.class.isAssignableFrom(otherBinding.getClass())) +// return false; +// +// IType thisType = method.getType(); +// IType otherType = ((ICPPMethod) otherBinding).getType(); +// return thisType == null ? otherType == null : thisType.isSameType(otherType); + } + + @Override + public IBinding getBinding() { + return null; // TODO method; + } + + @Override + public IQObject getOwner() { + return owner; + } + + @Override + public Kind getKind() { + return kind; + } + + @Override + public String getName() { + return name; + } + + @Override + public Collection getSignatures() { + return signatures == null ? Collections.emptyList() : signatures; + } + + @Override + public Long getRevision() { + return revision; + } + + @Override + public String toString() { + return kind.toString() + ' ' + signatures; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObject.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObject.java new file mode 100644 index 00000000000..60157b7409a --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObject.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMProperty; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQEnum; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQMethod; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQObject; +import org.eclipse.cdt.qt.core.index.IQEnum; +import org.eclipse.cdt.qt.core.index.IQMethod; +import org.eclipse.cdt.qt.core.index.IQObject; +import org.eclipse.cdt.qt.core.index.IQProperty; +import org.eclipse.core.runtime.CoreException; + +public class QObject implements IQObject { + + private final String name; + private final QtPDOMQObject pdomQObject; + private final List bases; + private final IQObject.IMembers slots; + private final IQObject.IMembers signals; + private final IQObject.IMembers invokables; + private final IQObject.IMembers properties; + private final List enums; + private final Map classInfos; + + public QObject(QtIndexImpl qtIndex, CDTIndex cdtIndex, QtPDOMQObject pdomQObject) throws CoreException { + this.name = pdomQObject.getName(); + this.pdomQObject = pdomQObject; + + List baseSlots = new ArrayList(); + List baseSignals = new ArrayList(); + List baseInvokables = new ArrayList(); + List baseProps = new ArrayList(); + + this.bases = new ArrayList(); + for(QtPDOMQObject base : pdomQObject.findBases()) { + QObject baseQObj = new QObject(qtIndex, cdtIndex, base); + this.bases.add(baseQObj); + baseProps.addAll(baseQObj.getProperties().all()); + } + + this.classInfos = pdomQObject.getClassInfos(); + + List slots = new ArrayList(); + List signals = new ArrayList(); + List invokables = new ArrayList(); + for(QtPDOMQMethod pdom : pdomQObject.getChildren(QtPDOMQMethod.class)) + switch(pdom.getKind()) { + case Slot: + slots.add(new QMethod(this, pdom)); + break; + case Signal: + signals.add(new QMethod(this, pdom)); + break; + case Invokable: + invokables.add(new QMethod(this, pdom)); + break; + case Unspecified: + break; + } + + this.slots = QObjectMembers.create(slots, baseSlots); + this.signals = QObjectMembers.create(signals, baseSignals); + this.invokables = QObjectMembers.create(invokables, baseInvokables); + + this.enums = new ArrayList(); + for(QtPDOMQEnum pdom : pdomQObject.getChildren(QtPDOMQEnum.class)) + this.enums.add(new QEnum(pdom.getName(), pdom.isFlag(), pdom.getEnumerators())); + + List props = new ArrayList(); + for(QtPDOMProperty pdom : pdomQObject.getChildren(QtPDOMProperty.class)) { + QProperty qProp = new QProperty(this, pdom.getType(), pdom.getName()); + for(QtPDOMProperty.Attribute attr : pdom.getAttributes()) + qProp.setAttribute(attr.attr, attr.value); + props.add(qProp); + } + this.properties = QObjectMembers.create(props, baseProps); + } + + @Override + public IBinding getBinding() { + return pdomQObject; + } + + @Override + public String getName() { + return name; + } + + @Override + public List getBases() { + return bases; + } + + @Override + public IMembers getSlots() { + return slots; + } + + @Override + public IMembers getSignals() { + return signals; + } + + @Override + public IMembers getInvokables() { + return invokables; + } + + @Override + public IQObject.IMembers getProperties() { + return properties; + } + + @Override + public String getClassInfo(String key) { + String value = classInfos.get(key); + if (value != null) + return value; + + for(IQObject base : bases) { + value = base.getClassInfo(key); + if (value != null) + return value; + } + + return null; + } + + @Override + public Collection getEnums() { + return enums; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObjectMembers.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObjectMembers.java new file mode 100644 index 00000000000..faf09377a6a --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QObjectMembers.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.cdt.qt.core.index.IQObject; + +public class QObjectMembers implements IQObject.IMembers { + + private final List all; + private final Collection locals; + private Collection withoutOverrides; + + public static QObjectMembers create(Collection locals, Collection inherited) { + // NOTE: All must be ordered with the locals before the inherited members. This ensures that + // the algorithm for computing #withoutOverrides will filter out the parent members and + // not the local ones. + // @see withoutOverrides() + ArrayList all = new ArrayList(locals.size() + inherited.size()); + all.addAll(locals); + all.addAll(inherited); + return new QObjectMembers(all, locals); + } + + private QObjectMembers(List all, Collection locals) { + this.all = Collections.unmodifiableList(all); + this.locals = Collections.unmodifiableCollection(locals); + } + + @Override + public Collection all() { + return all; + } + + @Override + public Collection locals() { + return locals; + } + + @Override + public Collection withoutOverrides() { + + if (withoutOverrides == null) + synchronized (all) { + if (withoutOverrides == null) { + + // Naively tests each existing element for override before inserting the new + // element. Most member lists have less than 3 elements, and the largest that + // I've found (in the Qt impl) is about 20; so performance may not be as bad + // as it seems. + // + // An earlier approach tried to use a SortedSet with the #isOverride result in + // the Comparator. The problem with the approach is finding a stable sort order + // when the members don't override each other. + // E.g., if o1 and o2 override each other and m is unrelated, we could get a + // tree like: + // m + // / \ + // o1 o2 + + ArrayList filtered = new ArrayList(all.size()); + for(T member : all) { + boolean isOverridden = false; + for(Iterator i = filtered.iterator(); !isOverridden && i.hasNext(); ) + isOverridden = member.isOverride(i.next()); + if (!isOverridden) + filtered.add(member); + } + + withoutOverrides = Collections.unmodifiableCollection(filtered); + } + } + + return withoutOverrides; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QProperty.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QProperty.java new file mode 100644 index 00000000000..9e8b2c14b20 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QProperty.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import org.eclipse.cdt.qt.core.index.IQObject; +import org.eclipse.cdt.qt.core.index.IQProperty; + +public class QProperty extends AbstractQField implements IQProperty { + + private String type; + private final String[] values = new String[Attribute.values().length]; + + public QProperty(IQObject owner, String type, String name) { + super(owner); + this.type = type; + this.name = name; + } + + public void setAttribute(IQProperty.Attribute attr, String value) { + values[attr.ordinal()] = ( value == null ? "" : value ); + } + + @Override + public String getType() { + return type; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue(Attribute attr) { + return values[attr.ordinal()]; + } + + @Override + public String getReadMethodName() { + return Attribute.READ.valueIn(this); + } + + @Override + public String getWriteMethodName() { + return Attribute.WRITE.valueIn(this); + } + + @Override + public String getResetMethodName() { + return Attribute.RESET.valueIn(this); + } + + @Override + public String getNotifyMethodName() { + return Attribute.NOTIFY.valueIn(this); + } + + @Override + public Long getRevision() { + String revision = Attribute.REVISION.valueIn(this); + if (revision != null) + try { + return Long.valueOf(revision); + } catch(NumberFormatException e) { + // This is a problem with the user's C++ code, there is no need to log this exception, + // just ignore the value. + } + + return null; + } + + @Override + public String getDesignable() { + return Attribute.DESIGNABLE.valueIn(this); + } + + @Override + public String getScriptable() { + return Attribute.SCRIPTABLE.valueIn(this); + } + + @Override + public String getStored() { + return Attribute.STORED.valueIn(this); + } + + @Override + public String getUser() { + return Attribute.USER.valueIn(this); + } + + @Override + public boolean isConstant() { + return Attribute.CONSTANT.valueIn(this) != null; + } + + @Override + public boolean isFinal() { + return Attribute.FINAL.valueIn(this) != null; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtFactory.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtFactory.java new file mode 100644 index 00000000000..4b6e9576e92 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtFactory.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.index.IIndexMacro; +import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.qt.core.index.QtIndex; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; + +public class QtFactory { + + private static final char[] QT_VERSION = "QT_VERSION".toCharArray(); + + public static QtIndex create(IProject project) { + CDTIndex cdtIndex = getCDTIndex(project); + if (cdtIndex == null) { + QtPlugin.log("could not get CDT index from project " + project.getName()); + return null; + } + + QtVersion qtVersion = cdtIndex.get(QtVersionAccessor); + if (qtVersion == null) { + QtPlugin.log("could not find Qt version in CDT index from project " + project.getName()); + return null; + } + + if (qtVersion.major == 4 && qtVersion.minor == 8) + return new QtIndexImpl(cdtIndex); + + // Qt 4.8 is the default implementation, 5.0 support will need to come soon + return new QtIndexImpl(cdtIndex); + } + + private static CDTIndex getCDTIndex(IProject project) { + if (project == null) + return null; + + ICProject cProject = CoreModel.getDefault().create(project); + if (cProject == null) + return null; + + IIndex index = null; + try { + index = CCorePlugin.getIndexManager().getIndex(cProject); + } catch( CoreException e ) { + QtPlugin.log(e); + return null; + } + + return index == null ? null : new CDTIndex(index); + } + + /** + * A small wrapper to hold the result of index lookups for the Qt version. + */ + private static class QtVersion { + public final int major; + public final int minor; + @SuppressWarnings("unused") + public final int patch; + + // QT_VERSION looks like 0x040805 + private static final Pattern Version_regex = Pattern.compile( "0x([a-fA-F\\d]{1,2})([a-fA-F\\d]{2})([a-fA-F\\d]{2})" ); + + public static QtVersion create(String version) { + Matcher m = Version_regex.matcher(version); + if (!m.matches()) + return null; + + try { + int major = Integer.parseInt(m.group(1), 16); + int minor = Integer.parseInt(m.group(2), 16); + int patch = Integer.parseInt(m.group(3), 16); + return new QtVersion(major, minor, patch); + } catch(NumberFormatException e) { + QtPlugin.log(e); + } + return null; + } + + private QtVersion(int major, int minor, int patch) { + this.major = major; + this.minor = minor; + this.patch = patch; + } + } + + private static final CDTIndex.Accessor QtVersionAccessor = new CDTIndex.Accessor() { + @Override + public QtVersion access(IIndex index) throws CoreException { + // Multiple macros might be found, sort the values and choose the highest version. + SortedSet versions = new TreeSet(); + try { + for(IIndexMacro macro : index.findMacros(QT_VERSION, IndexFilter.ALL, null)) + versions.add(new String(macro.getExpansion()).toLowerCase()); + } catch( CoreException e ) { } + + // don't create the Qt index if there is no Qt information in the CDT index + if (versions.size() <= 0) + return null; + + // the highest version has been sorted to the last position + return QtVersion.create(versions.last()); + } + }; +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtIndexImpl.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtIndexImpl.java new file mode 100644 index 00000000000..7390f91d368 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QtIndexImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.index; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.index.IIndexBinding; +import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQObject; +import org.eclipse.cdt.qt.core.index.IQObject; +import org.eclipse.cdt.qt.core.index.QtIndex; +import org.eclipse.core.runtime.CoreException; + +public class QtIndexImpl extends QtIndex { + + private final CDTIndex cdtIndex; + + private static final IndexFilter QtLinkageFilter = new IndexFilter() { + @Override + public boolean acceptLinkage(ILinkage linkage) { + return linkage.getLinkageID() == ILinkage.QT_LINKAGE_ID; + } + + @Override + public boolean acceptBinding(IBinding binding) throws CoreException { + return true; + } + }; + + public QtIndexImpl(CDTIndex cdtIndex) { + this.cdtIndex = cdtIndex; + } + + @Override + public IQObject findQObject(String[] name) { + return name == null ? null : cdtIndex.get(new QObjectImplAccessor(name)); + } + + private class QObjectImplAccessor implements CDTIndex.Accessor { + + private final char[][] name; + + public QObjectImplAccessor(String[] qualName) { + name = new char[qualName.length][]; + for(int i = 0; i < name.length; ++i) + name[i] = qualName[i].toCharArray(); + } + + @Override + public IQObject access(IIndex index) throws CoreException { + + // TODO can there be more than one result? + for(IIndexBinding binding : index.findBindings(name, QtLinkageFilter, null)) + if (binding instanceof QtPDOMQObject) + return new QObject(QtIndexImpl.this, cdtIndex, (QtPDOMQObject) binding); + + return null; + } + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTDelegatedName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTDelegatedName.java new file mode 100644 index 00000000000..271c3f5d3d5 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTDelegatedName.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTImageLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.parser.IToken; + +/** + * The Qt linkage introduces several names that are based on names from the C++ linkage. This + * utility class is used to delegate operations to that base C++ name. Methods can be overridden + * by implementing in a subclass. + * + * @see QObjectName + */ +public abstract class ASTDelegatedName implements IASTName { + + protected final IASTName delegate; + + protected IBinding binding; + + protected ASTDelegatedName(IASTName delegate) { + this.delegate = delegate; + } + + @Override + public IASTTranslationUnit getTranslationUnit() { + return delegate.getTranslationUnit(); + } + + @Override + public IASTNodeLocation[] getNodeLocations() { + return delegate.getNodeLocations(); + } + + @Override + public IASTFileLocation getFileLocation() { + return delegate.getFileLocation(); + } + + @Override + public String getContainingFilename() { + return delegate.getContainingFilename(); + } + + @Override + public boolean isPartOfTranslationUnitFile() { + return delegate.isPartOfTranslationUnitFile(); + } + + @Override + public IASTNode getParent() { + return delegate.getParent(); + } + + @Override + public IASTNode[] getChildren() { + return delegate.getChildren(); + } + + @Override + public void setParent(IASTNode node) { + delegate.setParent(node); + } + + @Override + public ASTNodeProperty getPropertyInParent() { + return delegate.getPropertyInParent(); + } + + @Override + public void setPropertyInParent(ASTNodeProperty property) { + delegate.setPropertyInParent(property); + } + + @Override + public boolean accept(ASTVisitor visitor) { + return delegate.accept(visitor); + } + + @Override + public String getRawSignature() { + return delegate.getRawSignature(); + } + + @Override + public boolean contains(IASTNode node) { + return delegate.contains(node); + } + + @Override + public IToken getLeadingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException { + return delegate.getLeadingSyntax(); + } + + @Override + public IToken getTrailingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException { + return delegate.getTrailingSyntax(); + } + + @Override + public IToken getSyntax() throws ExpansionOverlapsBoundaryException { + return delegate.getSyntax(); + } + + @Override + public boolean isFrozen() { + return delegate.isFrozen(); + } + + @Override + public boolean isActive() { + return delegate.isActive(); + } + + @Override + public IASTNode getOriginalNode() { + return delegate.getOriginalNode(); + } + + @Override + public char[] getSimpleID() { + return delegate.getSimpleID(); + } + + @Override + public boolean isDeclaration() { + return delegate.isDeclaration(); + } + + @Override + public boolean isReference() { + return delegate.isReference(); + } + + @Override + public boolean isDefinition() { + return delegate.isDefinition(); + } + + @Override + public char[] toCharArray() { + return delegate.toCharArray(); + } + + @Override + public IBinding getBinding() { + return null; + } + + @Override + public IBinding resolveBinding() { + return null; + } + + @Override + public int getRoleOfName(boolean allowResolution) { + return delegate.getRoleOfName(allowResolution); + } + + @Override + public IASTCompletionContext getCompletionContext() { + return delegate.getCompletionContext(); + } + + @Override + public ILinkage getLinkage() { + return delegate.getLinkage(); + } + + @Override + public IASTImageLocation getImageLocation() { + return delegate.getImageLocation(); + } + + @Override + public IASTName getLastName() { + return delegate.getLastName(); + } + + @Override + public IASTName copy() { + return delegate.copy(); + } + + @Override + public IASTName copy(CopyStyle style) { + return delegate.copy(style); + } + + @Override + public void setBinding(IBinding binding) { + this.binding = binding; + } + + @Override + public char[] getLookupKey() { + return delegate.getLookupKey(); + } + + @Override + public IBinding getPreBinding() { + return binding; + } + + @Override + public IBinding resolvePreBinding() { + return resolveBinding(); + } + + @Override + public boolean isQualified() { + return delegate.isQualified(); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTNameReference.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTNameReference.java new file mode 100644 index 00000000000..52d511a8337 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/ASTNameReference.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.index.IIndexName; +import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; +import org.eclipse.cdt.internal.core.index.IIndexFragmentName; +import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; +import org.eclipse.core.runtime.CoreException; + +/** + * Some Qt elements are introduced with empty macro expansions. The Qt linkage handles this + * by creating a new name and then adding it as a reference to the C++ language element. + * This utility helps by containing that C++ name and the location of the Qt name. + */ +@SuppressWarnings("restriction") +public class ASTNameReference extends ASTDelegatedName { + + private final IASTFileLocation location; + + /** + * Create and return a name that will reference the given name. + */ + public ASTNameReference(IASTName name) { + super(name); + this.location = name.getFileLocation(); + } + + /** + * Create and return a name that will reference the given name from the given location. + */ + public ASTNameReference(IASTName name, IASTFileLocation location) { + super(name); + this.location = location; + } + + /** + * Find and return the Qt binding that annotates the given PDOMBinding. E.g., if the input binding + * is an instance of PDOMCPPClassType, then this method will return the QtPDOMQObject that was created + * from that class (or null if there is no such Qt element). + *

+ * This is implemented by creating an ASTNameReference within the Qt element binding's definition. That + * name is added as reference from the C++ PDOM binding. + */ + public static T findFromBinding(Class cls, PDOMBinding binding) throws CoreException { + if (binding == null) + return null; + + // Look for external references to the binding. + IPDOMIterator pdomIterator = binding.getExternalReferences(); + while(pdomIterator.hasNext()) { + PDOMName extRef = pdomIterator.next(); + IIndexName caller = extRef.getEnclosingDefinition(); + if (caller instanceof IIndexFragmentName) { + IIndexFragmentBinding extRefBinding = ((IIndexFragmentName) caller).getBinding(); + if (cls.isAssignableFrom(extRefBinding.getClass())) + return cls.cast(extRefBinding); + } + } + + return null; + } + + @Override + public IBinding resolveBinding() { + return delegate.resolveBinding(); + } + + @Override + public IBinding getBinding() { + return delegate.getBinding(); + } + + @Override + public IASTFileLocation getFileLocation() { + return location; + } + + @Override + public boolean isReference() { + return true; + } + + @Override + public boolean isDefinition() { + return false; + } + + @Override + public boolean isDeclaration() { + return false; + } + + @Override + public int getRoleOfName(boolean allowResolution) { + return IASTNameOwner.r_reference; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQObjectMemberName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQObjectMemberName.java new file mode 100644 index 00000000000..edc404fa52c --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQObjectMemberName.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTImageLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.internal.core.dom.Linkage; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public abstract class AbstractQObjectMemberName extends ASTDelegatedName { + + private final QObjectName owner; + private final String name; + private final IASTImageLocation location; + private ASTNodeProperty propertyInParent; + + protected AbstractQObjectMemberName(QObjectName owner, IASTName ast, String name, IASTImageLocation location) { + super(ast); + this.owner = owner; + this.name = name; + this.location = location; + } + + protected PDOMBinding getOwner(QtPDOMLinkage linkage) throws CoreException { + return linkage.getBinding(owner); + } + + public String getFieldName() { + return name; + } + + @Override + public IASTFileLocation getFileLocation() { + return location; + } + + @Override + public IASTNode getParent() { + return owner; + } + + @Override + public IASTNode[] getChildren() { + return IASTNode.EMPTY_NODE_ARRAY; + } + + @Override + public void setParent(IASTNode node) { + throw new IllegalStateException("attempt to modify parent of QObject field"); //$NON-NLS-1$ + } + + @Override + public ASTNodeProperty getPropertyInParent() { + return propertyInParent; + } + + @Override + public void setPropertyInParent(ASTNodeProperty property) { + propertyInParent = property; + } + + @Override + public char[] getSimpleID() { + return name.toCharArray(); + } + + @Override + public String getRawSignature() { + return name; + } + + @Override + public boolean isDeclaration() { + return false; + } + + @Override + public boolean isReference() { + return false; + } + + @Override + public boolean isDefinition() { + return true; + } + + @Override + public int getRoleOfName(boolean allowResolution) { + return IASTNameOwner.r_definition; + } + + @Override + public ILinkage getLinkage() { + return Linkage.QT_LINKAGE; + } + + @Override + public IASTImageLocation getImageLocation() { + return location; + } + + @Override + public IASTName copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public IASTName copy(CopyStyle style) { + throw new UnsupportedOperationException("attempt to copy QObject field"); //$NON-NLS-1$ + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtASTName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtASTName.java new file mode 100644 index 00000000000..0d13bb8ef4d --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtASTName.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.core.runtime.CoreException; + +public interface IQtASTName extends IASTName { + /** + * Create and return a new instance of PDOMBinding for the receiver. The implementation + * is allowed to return null if there is no possibility of creating a PDOMBinding. + * The value that is returned must be consistent -- if null is returned one time then + * it must be returned every time. + */ + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException; +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtPDOMCodec.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtPDOMCodec.java new file mode 100644 index 00000000000..8cc4b08a7c1 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/IQtPDOMCodec.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 + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.core.runtime.CoreException; + +/** + * A utility interface for encoding and decoding fixed-sized elements to and + * from the Database. + */ +public interface IQtPDOMCodec { + /** + * Return the number of bytes needed to store a single element. + */ + public int getElementSize(); + + /** + * Allocate and return a new array to hold the specified number of elements. + */ + public T[] allocArray(int count); + + /** + * Examine the database at the specified record to decode an element instance. + */ + public T decode(QtPDOMLinkage linkage, long record) throws CoreException; + + /** + * Encode the given element into the database at the specified record. The codec is + * responsible for releasing storage that is about to be overwritten (if needed). + * The element will be null when the implementation should delete all memory used + * for storage at record. + */ + public void encode(QtPDOMLinkage linkage, long record, T element) throws CoreException; +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/PDOMQtLinkageFactory.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/PDOMQtLinkageFactory.java new file mode 100644 index 00000000000..79d3fad1836 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/PDOMQtLinkageFactory.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 + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.internal.core.pdom.PDOM; +import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class PDOMQtLinkageFactory implements IPDOMLinkageFactory { + + @Override + public PDOMLinkage getLinkage(PDOM pdom, long record) { + try { + return new QtPDOMLinkage(pdom, record); + } catch(CoreException e) { + QtPlugin.log(e); + } + return null; + } + + @Override + public PDOMLinkage createLinkage(PDOM pdom) throws CoreException { + return new QtPDOMLinkage(pdom); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QMethodName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QMethodName.java new file mode 100644 index 00000000000..b0da79542d2 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QMethodName.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.qt.core.index.IQMethod; +import org.eclipse.core.runtime.CoreException; + +public class QMethodName extends AbstractQObjectMemberName implements IQtASTName { + + private final IQMethod.Kind kind; + private final String qtEncSignatures; + private final Long revision; + + public QMethodName(QObjectName qobjName, IASTName cppName, IQMethod.Kind kind, String qtEncSignatures, Long revision) { + super(qobjName, cppName, cppName.getLastName().toString(), cppName.getImageLocation()); + this.kind = kind; + this.qtEncSignatures = qtEncSignatures; + this.revision = revision; + } + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + return new QtPDOMQMethod(linkage, getOwner(linkage), this, delegate, kind, qtEncSignatures, revision); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QObjectName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QObjectName.java new file mode 100644 index 00000000000..06544b49b38 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QObjectName.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.internal.core.dom.Linkage; +import org.eclipse.core.runtime.CoreException; + +/** + * QObjects are C++ classes that have been annotated with Qt marker macros. This class is + * used to introduce the QObject to the Qt linkage. + */ +@SuppressWarnings("restriction") +public class QObjectName extends ASTDelegatedName implements IQtASTName { + + private final ICPPASTCompositeTypeSpecifier spec; + private final List properties = new ArrayList(); + private final Map classInfos = new LinkedHashMap(); + + private IASTNode parent; + private ASTNodeProperty propertyInParent; + + public QObjectName(ICPPASTCompositeTypeSpecifier spec) { + super(spec.getName()); + this.spec = spec; + this.parent = delegate.getParent(); + this.propertyInParent = delegate.getPropertyInParent(); + } + + public List getProperties() { + return properties; + } + + public void addProperty(QtPropertyName property) { + properties.add(property); + } + + public Map getClassInfos() { + return classInfos; + } + + public String addClassInfo(String key, String value) { + return classInfos.put(key, value); + } + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + return new QtPDOMQObject(linkage, this, spec.getName()); + } + + @Override + public IASTTranslationUnit getTranslationUnit() { + return spec.getTranslationUnit(); + } + + @Override + public IASTNode[] getChildren() { + return IASTNode.EMPTY_NODE_ARRAY; + } + + @Override + public IASTNode getParent() { + return parent; + } + + @Override + public void setParent(IASTNode node) { + parent = node; + } + + @Override + public ASTNodeProperty getPropertyInParent() { + return propertyInParent; + } + + @Override + public void setPropertyInParent(ASTNodeProperty property) { + propertyInParent = property; + } + + @Override + public boolean accept(ASTVisitor visitor) { + return false; + } + + @Override + public boolean contains(IASTNode node) { + return false; + } + + @Override + public ILinkage getLinkage() { + return Linkage.QT_LINKAGE; + } + + @Override + public IASTName copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public IASTName copy(CopyStyle style) { + return new QObjectName(spec); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTClass.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTClass.java new file mode 100644 index 00000000000..6fb7a19ae1f --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTClass.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.index.IQMethod; + +/** + * The AST for a QObject is separated into regions based on macro expansions. These + * regions determine the Qt kind for methods that are declared within them. + *

+ * This utility class makes one pass over the C++ class specification to identify + * all such regions. It also provides an iterator that can be used while examining + * the class spec's members. + */ +public class QtASTClass { + + private final Iterator regions; + private final Iterator tags; + private final Iterator revisions; + private Region region; + private Tag tag; + private Revision revision; + + /** + * Must only be called with increasing offset. Internal pointers may be advanced on + * each call. + */ + public IQMethod.Kind getKindFor(int offset) { + + // There are 3 steps: + // 1) The tags counter must always be advanced. Tags only apply to the next declaration + // and therefore the internal counter must always be advanced. Multiple tags are + // collapsed to find the highest precedence value. + // 2) The region counter is advanced to find a region that either contains the offset + // or is the first region after the offset. Regions override tags, so we use the + // region kind if one is found. + // 3) The final result is based on tags (if they were present). + // + // This precedence is based on experimentation with the moc (ver 63). It + // ignores macros tagging a single method when that method is declared within + // a signal/slot region. E.g., the following example has two signals and one slot: + // + // class Q : public QObject + // { + // Q_OBJECT + // signals: void signal1(); + // Q_SLOT void signal2(); /* Tagged with Q_SLOT, but the declaration is within the + // * signals region, so the moc considers it a signal. */ + // public: + // Q_SLOT void slot1(); + // }; + + + // Consume all tags since the last declaration to find the highest precedence tag. + IQMethod.Kind kind = IQMethod.Kind.Unspecified; + while(tag != null && tag.offset < offset) { + kind = getHigherPrecedence(kind, tag.kind); + tag = tags.hasNext() ? tags.next() : null; + } + + // Advance regions to find one that does not end before this offset. + while(region != null && region.end < offset) + region = regions.hasNext() ? regions.next() : null; + + // If the offset is within this region, then use its kind. + if (region != null && region.contains(offset)) + kind = region.kind; + + return kind; + } + + /** + * Must only be called with increasing offset. Internal pointers may be advanced on + * each call. + */ + public Long getRevisionFor(int offset) { + + // Consume all revisions since the last declaration to find one (if any) that applies + // to this declaration. + Long rev = null; + while(revision != null && revision.offset < offset) { + rev = revision.revision; + revision = revisions.hasNext() ? revisions.next() : null; + } + + return rev; + } + + private static IQMethod.Kind getHigherPrecedence(IQMethod.Kind kind1, IQMethod.Kind kind2) { + switch(kind1) { + case Unspecified: + return kind2; + case Invokable: + switch(kind2) { + case Slot: + case Signal: + return kind2; + default: + return kind1; + } + case Signal: + if (kind2 == IQMethod.Kind.Slot) + return kind2; + return kind2; + case Slot: + return kind1; + } + return IQMethod.Kind.Unspecified; + } + + public static QtASTClass create(ICPPASTCompositeTypeSpecifier spec) { + + // There is more detail in Bug 401696 describing why this needs to look at all + // the node locations. Briefly, the CDT parser does not associate empty macros + // with the function when they are the first thing in the declaration. E.g., + // + // #define X + // void func1() {} + // X void func2() {} + // + // Could also look like: + // void func1() {} X + // void func2() {} + // + // The nodes are processed in three stages which are described in detail below. Only + // the first stage looks at the nodes, the later stages just cleanup results from the + // first walk over all node locations. + + // 1) Examine the locations to find all macro expansions. This finds a beginning and + // highest possible end for the regions. It also locates the offset for single-method + // tags (including resolving precedence). + // This allows single-method tags to overlap regions because regions may be shortened + // by a later step. + ArrayList tags = new ArrayList(); + ArrayList revisions = new ArrayList(); + ArrayList regions = new ArrayList(); + Region currRegion = null; + for(IASTNodeLocation location : spec.getNodeLocations()) { + + Tag tag = Tag.create(location); + if (tag != null) + tags.add(tag); + + Revision revision = Revision.create(location); + if (revision != null) + revisions.add(revision); + + Region region = Region.create(location); + if (region != null) { + if (currRegion != null) + currRegion.end = region.begin; + + currRegion = region; + regions.add(region); + } + } + + // 2) Make the regions smaller where visibility labels are introduced. + if (!regions.isEmpty()) { + Iterator iterator = regions.iterator(); + Region region = iterator.next(); + for (IASTDeclaration decl : spec.getMembers()) { + + // Ignore everything other than visibility labels. + if (!(decl instanceof ICPPASTVisibilityLabel)) + continue; + + int offset = decl.getFileLocation().getNodeOffset(); + + // Otherwise terminate all regions that start before this label and advance + // to the first one that follows. + while(region != null && region.begin < offset) { + region.end = offset; + region = iterator.hasNext() ? iterator.next() : null; + } + + // Stop searching for visibility labels after the last region has been terminated. + if (region == null) + break; + } + } + + // 3) Eliminate tags that are within regions. + if (!tags.isEmpty()) { + Iterator iterator = tags.iterator(); + Tag tag = iterator.next(); + for(Region region : regions) { + + // Keep all tags that are before the start of this region. + while(tag != null && tag.offset < region.begin) + tag = iterator.hasNext() ? iterator.next() : null; + + // Delete all tags that are within this region. + while(tag != null && region.contains(tag.offset)) { + iterator.remove(); + tag = iterator.hasNext() ? iterator.next() : null; + } + + // Stop searching when there are no more tags to be examined. + if (tag == null) + break; + } + } + + return new QtASTClass(regions, tags, revisions); + } + + private QtASTClass(List regions, List tags, List revisions) { + this.regions = regions.iterator(); + this.tags = tags.iterator(); + this.revisions = revisions.iterator(); + + this.region = this.regions.hasNext() ? this.regions.next() : null; + this.tag = this.tags.hasNext() ? this.tags.next() : null; + this.revision = this.revisions.hasNext() ? this.revisions.next() : null; + } + + private static class Region { + public final int begin; + public int end = Integer.MAX_VALUE; + public final IQMethod.Kind kind; + + public Region(int begin, IQMethod.Kind kind) { + this.begin = begin; + this.kind = kind; + } + + public boolean contains(int offset) { + return offset >= begin + && offset < end; + } + + /** + * Return a region for the given location or null if the location does not + * introduce a region. + */ + public static Region create(IASTNodeLocation location) { + if (!(location instanceof IASTMacroExpansionLocation)) + return null; + + IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; + IASTFileLocation fileLocation = macroLocation.asFileLocation(); + if (fileLocation == null) + return null; + + int offset = fileLocation.getNodeOffset(); + IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); + String macroName = getMacroName(expansion); + if (QtKeywords.Q_SLOTS.equals(macroName) + || QtKeywords.SLOTS.equals(macroName)) + return new Region(offset, IQMethod.Kind.Slot); + if (QtKeywords.Q_SIGNALS.equals(macroName) + || QtKeywords.SIGNALS.equals(macroName)) + return new Region(offset, IQMethod.Kind.Signal); + return null; + } + } + + private static class Tag { + public final int offset; + public IQMethod.Kind kind; + + private Tag(int begin, IQMethod.Kind kind) { + this.offset = begin; + this.kind = kind; + } + + /** + * Return a tag for the given location or null if the location does not + * introduce a tag. + */ + public static Tag create(IASTNodeLocation location) { + if (!(location instanceof IASTMacroExpansionLocation)) + return null; + + IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; + IASTFileLocation fileLocation = macroLocation.asFileLocation(); + if (fileLocation == null) + return null; + + int offset = fileLocation.getNodeOffset(); + IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); + String macroName = getMacroName(expansion); + if (QtKeywords.Q_SLOT.equals(macroName)) + return new Tag(offset, IQMethod.Kind.Slot); + if (QtKeywords.Q_SIGNAL.equals(macroName)) + return new Tag(offset, IQMethod.Kind.Signal); + if (QtKeywords.Q_INVOKABLE.equals(macroName)) + return new Tag(offset, IQMethod.Kind.Invokable); + return null; + } + } + + private static class Revision { + private final int offset; + private final Long revision; + + // This regular expression matches Q_REVISION macro expansions. It allows C++ integer + // literals as the expansion parameter. The integer literal is provided in capture + // group 1. Hexadecimal and octal prefixes are included in the capture group. Unsigned + // and long suffixes are allowed but are excluded from the capture group. The matcher's + // input string should be trimmed and have all newlines replaced. + private static final Pattern QREVISION_REGEX = Pattern.compile("^Q_REVISION\\s*\\(\\s*((?:0x)?[\\da-fA-F]+)[ulUL]*\\s*\\)$"); + + public Revision(int offset, Long revision) { + this.offset = offset; + this.revision = revision; + } + + /** + * Return a tag for the given location or null if the location does not + * introduce a tag. + */ + public static Revision create(IASTNodeLocation location) { + if (!(location instanceof IASTMacroExpansionLocation)) + return null; + + IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; + IASTFileLocation fileLocation = macroLocation.asFileLocation(); + if (fileLocation == null) + return null; + + int offset = fileLocation.getNodeOffset(); + IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); + String macroName = getMacroName(expansion); + if (!QtKeywords.Q_REVISION.equals(macroName)) + return null; + + String raw = expansion.getRawSignature(); + if (raw == null) + return null; + + // Trim leading and trailing whitespace and remove all newlines. + Matcher m = QREVISION_REGEX.matcher(raw.trim().replaceAll("\\s+", "")); + if (m.matches()) { + try { + return new Revision(offset, Long.parseLong(m.group(1))); + } catch(NumberFormatException e) { + // The number will be parsed incorrectly when the C++ client code does not + // contain a valid integer. We can't do anything about that, so the exception + // is ignored. A codan checker could notify the user of this problem. + } + } + + return null; + } + } + + /** + * Find and return the simple name of the macro that is being expanded or null if the name + * cannot be found. + */ + private static String getMacroName(IASTPreprocessorMacroExpansion expansion) { + if (expansion == null) + return null; + + IASTName name = expansion.getMacroReference(); + return name == null ? null : name.toString(); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTImageLocation.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTImageLocation.java new file mode 100644 index 00000000000..bfc7858e9e9 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTImageLocation.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTImageLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; + +/** + * The location of the signal/slot reference is stored as the location of the parent + * macro expansion + an offset, which is the number of characters between the start + * of the expansion and the start of the argument (including whitespace). E.g. in, + * + *

+ * MACRO( expansionParameter )
+ * ^      ^                ^ c: end of reference name
+ * |      +----------------- b: start of reference name
+ * +------------------------ a: start of macro expansion
+ * 
+ * + * The offset is b - a and length is c - b. This means that the result of 'Find + * References' will highlight just "parameter". + */ +public class QtASTImageLocation implements IASTImageLocation { + + private final IASTFileLocation refLocation; + private final int offset; + private final int length; + + public QtASTImageLocation(IASTFileLocation refLocation, int offset, int length) { + this.refLocation = refLocation; + this.offset = offset; + this.length = length; + } + + public int getOffset() { + return offset; + } + + public int getLength() { + return length; + } + + @Override + public IASTFileLocation asFileLocation() { + return this; + } + + @Override + public String getFileName() { + return refLocation.getFileName(); + } + + @Override + public int getNodeOffset() { + return refLocation.getNodeOffset() + offset; + } + + @Override + public int getNodeLength() { + return length; + } + + @Override + public int getStartingLineNumber() { + return refLocation.getStartingLineNumber(); + } + + @Override + public int getEndingLineNumber() { + return refLocation.getEndingLineNumber(); + } + + @Override + public IASTPreprocessorIncludeStatement getContextInclusionStatement() { + return refLocation.getContextInclusionStatement(); + } + + @Override + public int getLocationKind() { + return REGULAR_CODE; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTVisitor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTVisitor.java new file mode 100644 index 00000000000..4273ef4d6b8 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtASTVisitor.java @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.index.IIndexSymbols; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; +import org.eclipse.cdt.internal.qt.core.QtMethodUtil; +import org.eclipse.cdt.internal.qt.core.index.QProperty; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.index.IQMethod; +import org.eclipse.cdt.qt.core.index.IQProperty; + +@SuppressWarnings("restriction") +public class QtASTVisitor extends ASTVisitor { + + private final IIndexSymbols symbols; + private final LocationMap locationMap; + + private static final Pattern expansionParamRegex = Pattern.compile("^(?:Q_ENUMS|Q_FLAGS)\\s*\\((.*)\\)$", Pattern.DOTALL); + private static final Pattern qualNameRegex = Pattern.compile("\\s*((?:[^\\s:]+\\s*::\\s*)*[^\\s:]+).*"); + + private static final Pattern declareFlagsRegex = Pattern.compile("^Q_DECLARE_FLAGS\\s*\\(\\s*([^\\s]+),\\s*([^\\s]+)\\s*\\)$", Pattern.DOTALL); + + /** + * A regular expression for scanning the Q_CLASSINFO expansion and extracting the + * expansion parameter key and value. It provides the following capture groups: + *
1 - the key + *
2 - the value + *

+ * The key must not have embedded quotes. + */ + private static final Pattern classInfoRegex = Pattern.compile("^Q_CLASSINFO\\s*\\(\\s*\"([^\"]+)\"\\s*,\\s*\"(.*)\"\\s*\\)$", Pattern.DOTALL); + + private static final Pattern leadingWhitespaceRegex = Pattern.compile("^\\s*([^\\s].*)$"); + + private static final Pattern qPropertyRegex = Pattern.compile("^Q_PROPERTY\\s*\\(\\s*(.+?)\\s*([a-zA-Z_][\\w]*+)(?:(?:\\s+(READ\\s+.*))|\\s*)\\s*\\)$", Pattern.DOTALL); + + /** + * A regular expression for scanning Q_PROPERTY attributes. The regular expression is built + * from the values defined in IQProperty#Attribute. It looks like: + *

+	 * (:?READ)|(?:WRITE)|(:?RESET)|...
+	 * 
+ * This regular expression is used to recognize valid attributes while scanning the + * Q_PROPERTY macro expansion. + * + * @see QProperty#scanAttributes(String) + */ + private static final Pattern qPropertyAttributeRegex; + static { + StringBuilder regexBuilder = new StringBuilder(); + for(IQProperty.Attribute attr : IQProperty.Attribute.values()) { + if (attr.ordinal() > 0) + regexBuilder.append('|'); + regexBuilder.append("(:?"); + regexBuilder.append(attr.identifier); + regexBuilder.append(")"); + } + qPropertyAttributeRegex = Pattern.compile(regexBuilder.toString()); + } + + public QtASTVisitor(IIndexSymbols symbols, LocationMap locationMap) { + shouldVisitDeclSpecifiers = true; + + this.symbols = symbols; + this.locationMap = locationMap; + } + + @Override + public int visit(IASTDeclSpecifier declSpec) { + if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { + ICPPASTCompositeTypeSpecifier spec = (ICPPASTCompositeTypeSpecifier) declSpec; + + IASTFileLocation loc = spec.getFileLocation(); + IASTPreprocessorIncludeStatement owner = loc == null ? null : loc.getContextInclusionStatement(); + + IASTPreprocessorMacroExpansion[] expansions = locationMap.getMacroExpansions(loc); + + if (isQObject(spec, expansions)) + handleQObject(owner, spec, expansions); + } + + return super.visit(declSpec); + } + + private boolean isQObject(ICPPASTCompositeTypeSpecifier spec, IASTPreprocessorMacroExpansion[] expansions) { + + // The class definition must contain a Q_OBJECT expansion. + for (IASTPreprocessorMacroExpansion expansion : expansions) { + IASTPreprocessorMacroDefinition macro = expansion.getMacroDefinition(); + if (QtKeywords.Q_OBJECT.equals(String.valueOf(macro.getName()))) + return true; + } + + return false; + } + + private class EnumDecl { + private final String name; + private final boolean isFlag; + private final IASTName refName; + private final QtASTImageLocation location; + + public EnumDecl(String name, boolean isFlag, IASTName refName, int offset, int length) { + this.name = name; + this.isFlag = isFlag; + this.refName = refName; + this.location = new QtASTImageLocation(refName.getFileLocation(), offset, length); + } + + public void handle(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, QObjectName qobjName, Map aliases) { + + String alias = aliases.get(name); + + IBinding[] bindings = CPPSemantics.findBindingsForQualifiedName(spec.getScope(), alias == null ? name : alias); + for(IBinding binding : bindings) { + // Create a reference from this Qt name to the target enum's definition. + IASTName cppName = findASTName(binding); + QtEnumName astName = new QtEnumName(qobjName, refName, name, cppName, location, isFlag); + symbols.add(owner, astName, qobjName); + + if (cppName != null) + symbols.add(owner, new ASTNameReference(cppName, location), astName); + } + } + } + + private void handleQObject(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, IASTPreprocessorMacroExpansion[] expansions) { + + // Put the QObject into the symbol map. + QObjectName qobjName = new QObjectName(spec); + symbols.add(owner, qobjName, null); + + // The QObject contains a reference to the C++ class that it annotates. + symbols.add(owner, new ASTNameReference(spec.getName()), qobjName); + + // There are three macros that are significant to QEnums, Q_ENUMS, Q_FLAGS, and Q_DECLARE_FLAGS. + // All macro expansions in the QObject class definition are examined to find instances of these + // three. Two lists are created during this processing. Then those lists are uses to create + // the QEnum instances. + + List enumDecls = new ArrayList(); + Map flagAliases = new HashMap(); + + for (IASTPreprocessorMacroExpansion expansion : expansions) { + + IASTName name = expansion.getMacroReference(); + String macroName = name == null ? null : name.toString(); + if (QtKeywords.Q_OBJECT.equals(macroName)) + continue; + + if (QtKeywords.Q_ENUMS.equals(macroName)) + extractEnumDecls(expansion, false, enumDecls); + else if (QtKeywords.Q_FLAGS.equals(macroName)) + extractEnumDecls(expansion, true, enumDecls); + else if (QtKeywords.Q_DECLARE_FLAGS.equals(macroName)) { + Matcher m = declareFlagsRegex.matcher(expansion.getRawSignature()); + if (m.matches()) { + String flagName = m.group(1); + String enumName = m.group(2); + flagAliases.put(flagName, enumName); + } + } else if(QtKeywords.Q_CLASSINFO.equals(macroName)) { + Matcher m = classInfoRegex.matcher(expansion.getRawSignature()); + if (m.matches()) { + String key = m.group(1); + String value = m.group(2); + qobjName.addClassInfo(key, value); + } + } else if(QtKeywords.Q_PROPERTY.equals(macroName)) + handleQPropertyDefn(owner, qobjName, expansion); + } + + // Process the slot, signal, and invokable method declarations. + extractQMethods(owner, spec, qobjName); + + for(EnumDecl decl : enumDecls) + decl.handle(owner, spec, qobjName, flagAliases); + } + + private void extractEnumDecls(IASTPreprocessorMacroExpansion expansion, boolean isFlag, List decls) { + String signature = expansion.getRawSignature(); + Matcher m = expansionParamRegex.matcher(signature); + if (!m.matches()) + return; + + IASTName refName = expansion.getMacroReference(); + String param = m.group(1); + for(int offset = m.start(1), end = param.length(); !param.isEmpty(); offset += end, param = param.substring(end)) { + m = qualNameRegex.matcher(param); + if (!m.matches()) + break; + + int start = m.start(1); + end = m.end(1); + + String enumName = m.group(1); + decls.add(new EnumDecl(enumName, isFlag, refName, offset + start, end - start)); + } + } + + private void handleQPropertyDefn(IASTPreprocessorIncludeStatement owner, QObjectName qobjName, IASTPreprocessorMacroExpansion expansion) { + Matcher m = qPropertyRegex.matcher(expansion.getRawSignature()); + if (!m.matches()) + return; + + String type = m.group(1); + String name = m.group(2); + + int nameStart = m.start(2); + int nameEnd = m.end(2); + + IASTName refName = expansion.getMacroReference(); + QtASTImageLocation location = new QtASTImageLocation(refName.getFileLocation(), nameStart, nameEnd - nameStart); + + QtPropertyName propertyName = new QtPropertyName(qobjName, refName, name, location); + propertyName.setType(type); + qobjName.addProperty(propertyName); + symbols.add(owner, propertyName, qobjName); + + // Create nodes for all the attributes. + AttrValue[] values = new AttrValue[IQProperty.Attribute.values().length]; + String attributes = m.group(3); + if (attributes == null) + return; + + int attrOffset = m.start(3); + + int lastEnd = 0; + IQProperty.Attribute lastAttr = null; + for(Matcher attributeMatcher = qPropertyAttributeRegex.matcher(attributes); attributeMatcher.find(); lastEnd = attributeMatcher.end()) { + // set the value of attribute found in the previous iteration to the substring between + // the end of that attribute and the start of this one + if (lastAttr != null) { + String value = attributes.substring(lastEnd, attributeMatcher.start()); + int wsOffset = 0; + Matcher ws = leadingWhitespaceRegex.matcher(value); + if (ws.matches()) { + value = ws.group(1); + wsOffset = ws.start(1); + } + + values[lastAttr.ordinal()] = new AttrValue(attrOffset + lastEnd + wsOffset, value.trim()); + } + + // the regex is built from the definition of the enum, so none of the strings that it + // finds will throw an exception + lastAttr = IQProperty.Attribute.valueOf(IQProperty.Attribute.class, attributeMatcher.group(0)); + + // if this attribute doesn't have a value, then put it into the value map immediately + // and make sure it is not used later in this scan + if (!lastAttr.hasValue) { + values[lastAttr.ordinal()] = AttrValue.None; + lastAttr = null; + } + } + + // the value of the last attribute in the expansion is the substring between the end of + // the attribute identifier and the end of the string + if (lastAttr != null) { + String value = attributes.substring(lastEnd); + int wsOffset = 0; + Matcher ws = leadingWhitespaceRegex.matcher(value); + if (ws.matches()) { + value = ws.group(1); + wsOffset = ws.start(1); + } + + values[lastAttr.ordinal()] = new AttrValue(attrOffset + lastEnd + wsOffset, value.trim()); + } + + // Put all values into the property name. + for(int i = 0; i < values.length; ++i) { + IQProperty.Attribute attr = IQProperty.Attribute.values()[i]; + AttrValue value = values[i]; + if (value == null) + continue; + + // If the attribute is not expected to have a C++ binding as the value, then it can + // be immediately added to the Q_PROPERTY. + if (!couldHaveBinding(attr)) { + propertyName.addAttribute(attr, value.value); + continue; + } + + // Otherwise see if one or more bindings can be found for the value of the attribute. + // TODO Check whether the Qt moc allows for inherited methods. + IBinding[] bindings = null; + IASTNode specNode = qobjName.getParent(); + if (specNode instanceof IASTCompositeTypeSpecifier) { + IScope scope = ((IASTCompositeTypeSpecifier) specNode).getScope(); + bindings = CPPSemantics.findBindings(scope, value.value, false); + } + + // If no bindings are found, then the attribute can be immediately added to the Q_PROPERTY. + if (bindings == null || bindings.length <= 0) { + propertyName.addAttribute(attr, value.value); + continue; + } + + // Otherwise create a new attribute for each binding. + for(IBinding foundBinding : bindings) { + propertyName.addAttribute(attr, value.value, foundBinding); + + IASTName cppName = findASTName(foundBinding); + if (cppName != null) { + QtASTImageLocation attrLoc = new QtASTImageLocation(refName.getFileLocation(), value.offset, value.value.length()); + symbols.add(owner, new ASTNameReference(cppName, attrLoc), propertyName); + } + } + } + } + + private static boolean couldHaveBinding(IQProperty.Attribute attr) { + switch(attr) { + case READ: + case WRITE: + case RESET: + case NOTIFY: + case DESIGNABLE: + case SCRIPTABLE: + return true; + + case REVISION: + case STORED: + case USER: + case CONSTANT: + case FINAL: + default: + return false; + } + } + + private static IASTName findASTName(IBinding binding) { + IASTNode node = null; + if (binding instanceof ICPPInternalBinding) { + node = ((ICPPInternalBinding) binding).getDefinition(); + if (node == null) + node = ((ICPPInternalBinding) binding).getDeclarations()[0]; + } + + if (node == null) + return null; + + IASTName astName = node instanceof IASTName ? (IASTName) node : null; + if (astName != null) + return astName; + + if (node instanceof IASTDeclarator) + return ((IASTDeclarator) node).getName(); + + return null; + } + + private static class AttrValue { + public final int offset; + public final String value; + public AttrValue(int offset, String value) { + this.offset = offset; + this.value = value; + } + public static final AttrValue None = new AttrValue(0, null); + } + + private void extractQMethods(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, QObjectName qobjName) { + QtASTClass qtASTClass = QtASTClass.create(spec); + for (IASTDeclaration decl : spec.getMembers()) { + + // We only care about this node if it is within a signal/slot region or if it + // has been tagged with a Qt annotating tag. + int offset = decl.getFileLocation().getNodeOffset(); + IQMethod.Kind kind = qtASTClass.getKindFor(offset); + Long revision = qtASTClass.getRevisionFor(offset); + if (kind == IQMethod.Kind.Unspecified) + continue; + + // Only named methods are processed, so skip this node if it is not a function or + // if it does not have a name. + IASTSimpleDeclaration simpleDecl = getSimpleDecl(decl); + if (simpleDecl == null) + continue; + + ICPPASTFunctionDeclarator decltor = null; + for(IASTDeclarator d : simpleDecl.getDeclarators()) + if (d instanceof ICPPASTFunctionDeclarator) { + decltor = (ICPPASTFunctionDeclarator) d; + break; + } + if (decltor == null) + continue; + + IASTName cppName = decltor.getName(); + if (cppName == null) + continue; + + String qtEncSignatures = QtMethodUtil.getEncodedQtMethodSignatures(decltor); + symbols.add(owner, new QMethodName(qobjName, cppName, kind, qtEncSignatures, revision), qobjName); + } + } + + private static IASTSimpleDeclaration getSimpleDecl(IASTNode node) { + while (node != null && !(node instanceof IASTSimpleDeclaration)) + node = node.getParent(); + return node instanceof IASTSimpleDeclaration ? (IASTSimpleDeclaration) node : null; + } + + /** + * Return the node's IASTName if it is a function and null otherwise. + */ + private static IASTName getFunctionName(IASTDeclaration decl) { + IASTSimpleDeclaration simpleDecl = getSimpleDecl(decl); + if (simpleDecl == null) + return null; + + // Only functions can be signals or slots. Return the name of the first declarator + // that is a function. + for( IASTDeclarator decltor : simpleDecl.getDeclarators()) + if (decltor instanceof IASTFunctionDeclarator) + return decltor.getName(); + + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtEnumName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtEnumName.java new file mode 100644 index 00000000000..77a98b2f217 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtEnumName.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.core.runtime.CoreException; + +public class QtEnumName extends AbstractQObjectMemberName implements IQtASTName { + + private final IASTName cppEnumName; + private final boolean isFlag; + + public QtEnumName(QObjectName qobjName, IASTName ast, String qtEnumName, IASTName cppEnumName, QtASTImageLocation location, boolean isFlag) { + super(qobjName, ast, qtEnumName, location); + this.cppEnumName = cppEnumName; + this.isFlag = isFlag; + } + + public boolean isFlag() { + return isFlag; + } + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + return new QtPDOMQEnum(linkage, getOwner(linkage), this, cppEnumName); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMASTProcessor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMASTProcessor.java new file mode 100644 index 00000000000..02518e25b9b --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMASTProcessor.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.index.IIndexSymbols; +import org.eclipse.cdt.core.index.IPDOMASTProcessor; +import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPDOMASTProcessor extends IPDOMASTProcessor.Abstract { + @Override + public int process(IASTTranslationUnit ast, IIndexSymbols symbols) throws CoreException { + ast.accept(new QtASTVisitor(symbols, (LocationMap) ast.getAdapter(LocationMap.class))); + return ILinkage.QT_LINKAGE_ID; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMArray.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMArray.java new file mode 100644 index 00000000000..7ddb88336e9 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMArray.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.core.runtime.CoreException; + +/** + * A utility class for storing a fixed-size list of fixed-size elements into the Database. + */ +@SuppressWarnings("restriction") +public class QtPDOMArray { + + private static int offsetInitializer = 0; + protected static enum Field { + Count(Database.INT_SIZE), + Data(0); // The size of the block is provided at runtime. + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + private final QtPDOMLinkage linkage; + private final IQtPDOMCodec codec; + private long record; + + public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec codec, long record) { + this.linkage = linkage; + this.codec = codec; + this.record = record; + } + + public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec codec, T[] array) throws CoreException { + this.linkage = linkage; + this.codec = codec; + this.record = 0; + set(array); + } + + public long getRecord() { + return record; + } + + /** + * Return array that is stored in the database. Return null if the receiver is not initialized. + */ + public T[] get() throws CoreException { + if (record == 0) + return null; + + int count = linkage.getDB().getInt(Field.Count.getRecord(record)); + + long elementRec = Field.Data.getRecord(record); + T[] array = codec.allocArray(count); + for(int i = 0; i < count; ++i, elementRec += codec.getElementSize()) + array[i] = codec.decode(linkage, elementRec); + + return array; + } + + /** + * Store the given array into the database. This may change the storage location of the + * receiver. + * @param array The array of elements that should be stored. Setting the value to null is + * equivalent to calling {@link #delete()}, which clears all storage. + */ + public long set(T[] array) throws CoreException { + if (array == null) + return delete(); + + // Initialize the receiver if needed. + if (record == 0) { + record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize())); + linkage.getDB().putInt(Field.Count.getRecord(record), array.length); + } else { + // Check if the storage block needs to be resized. + int count = linkage.getDB().getInt(Field.Count.getRecord(record)); + if (count != array.length) { + linkage.getDB().free(record); + record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize())); + linkage.getDB().putInt(Field.Count.getRecord(record), array.length); + } + } + + // Write the new content into the database. + long elementRec = Field.Data.getRecord(record); + for(int i = 0; i < array.length; ++i, elementRec += codec.getElementSize()) + codec.encode(linkage, elementRec, array[i]); + + return record; + } + + /** + * Release all storage used by the receiver and its elements. + */ + public long delete() throws CoreException { + // If the receiver is already empty, then there is nothing else to do. + if (record == 0) + return record; + + // Otherwise get the size of the stored array and delete each element. + int count = linkage.getDB().getInt(Field.Count.getRecord(record)); + if (count > 0) { + long elementRec = Field.Data.getRecord(record); + for(int i = 0; i < count; ++i, elementRec += codec.getElementSize()) + codec.encode(linkage, elementRec, null); + } + + // Finally, release the entire record. + linkage.getDB().free(record); + record = 0; + return record; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMBinding.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMBinding.java new file mode 100644 index 00000000000..d2a772926c5 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMBinding.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public abstract class QtPDOMBinding extends PDOMBinding { + + // The offsetInitializer is initialized with the size of the parent. It is incremented + // during loading of the Fields enum. This value does not reliably store the size of + // the QtPDOMBinding record because the enum will not be initialized until it is needed. + // The record size is retrieved as the offset of the special terminal enumerator Last. + private static int offsetInitializer = RECORD_SIZE; + protected static enum Field { + Last(0); + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + protected QtPDOMBinding(QtPDOMLinkage linkage, long record) { + super(linkage, record); + } + + protected QtPDOMBinding(QtPDOMLinkage linkage, PDOMNode parent, IASTName qtName) throws CoreException { + super(linkage, parent, qtName.getSimpleID()); + } + + @Override + protected int getRecordSize() { + return Field.Last.offset; + } + + protected QtPDOMLinkage getQtLinkage() { + PDOMLinkage pdomLinkage = getLinkage(); + return pdomLinkage instanceof QtPDOMLinkage ? (QtPDOMLinkage) pdomLinkage : null; + } + + // Access to the base class is restricted in the cdt.core plugin. Other classes in the qt.core + // plugin that need the qualified name get an access warning. This forwarding function moves + // those warnings to a single place (this method). + @Override + public String[] getQualifiedName() { + return super.getQualifiedName(); + } + + // Access to the base class is restricted in the cdt.core plugin. Other classes in the qt.core + // plugin that need the name get an access warning. This forwarding function moves those warnings + // to a single place (this method). + @Override + public String getName() { + return super.getName(); + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Object getAdapter(Class adapter) { + if (adapter.isAssignableFrom(getClass())) + return this; + + return super.getAdapter(adapter); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMLinkage.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMLinkage.java new file mode 100644 index 00000000000..f6123b14878 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMLinkage.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; +import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; +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.IBTreeComparator; +import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; +import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPDOMLinkage extends PDOMLinkage { + + private static int offsetInitializer = PDOMLinkage.RECORD_SIZE; + private static enum Field { + Version(Database.INT_SIZE), + Last(0); + + private final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + // The version that has been read from/written to the persisted file. + private int version; + + private final Map cache = new HashMap(); + + public QtPDOMLinkage(PDOM pdom, long record) throws CoreException { + super(pdom, record); + + version = pdom.getDB().getInt(Field.Version.getRecord(record)); + } + + protected QtPDOMLinkage(PDOM pdom) throws CoreException { + super(pdom, ILinkage.QT_LINKAGE_NAME, ILinkage.QT_LINKAGE_NAME.toCharArray()); + + // Initialize the version with whatever is current. + version = QtPDOMNodeType.VERSION; + pdom.getDB().putInt(Field.Version.getRecord(record), version); + } + + public int getVersion() { + return version; + } + + @Override + public String getLinkageName() { + return ILinkage.QT_LINKAGE_NAME; + } + + @Override + public int getLinkageID() { + return ILinkage.QT_LINKAGE_ID; + } + + @Override + public PDOMNode getNode(long record, int nodeType) throws CoreException { + return QtPDOMNodeType.load(this, nodeType, record); + } + + @Override + public IBTreeComparator getIndexComparator() { + return new FindBinding.DefaultBindingBTreeComparator(this); + } + + // IBinding#getAdapter cannot create an instance of PDOMBinding because the Linkage is required. This + // utility method uses #getAdapter to see if an instance has already been create. If not then a new + // is created and stored in the AST binding. + @Override + public PDOMBinding adaptBinding(IBinding binding, boolean includeLocal) throws CoreException { + if (binding == null) + return null; + + // If a binding has already been persisted for this instance then return it now. + QtPDOMBinding pdomBinding = (QtPDOMBinding) binding.getAdapter(QtPDOMBinding.class); + if (pdomBinding != null + && pdomBinding.getLinkage() == this) + return pdomBinding; + + // If a PDOMBinding was created, then add it to the linkage before returning it. + if (pdomBinding != null) { + addChild(pdomBinding); + return pdomBinding; + } + + // Otherwise fall back to looking in the C++ linkage. + return getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID).adaptBinding(binding); + } + + public long getCPPRecord(IASTName cppName) throws CoreException { + + if (cppName == null) + return 0; + + IBinding binding = getPDOM().findBinding(cppName); + if (binding == null) + return 0; + + IPDOMBinding pdomBinding = (IPDOMBinding) binding.getAdapter(IPDOMBinding.class); + if (pdomBinding == null) + return 0; + + if (pdomBinding.getLinkage() == null + || pdomBinding.getLinkage().getLinkageID() != ILinkage.CPP_LINKAGE_ID) + return 0; + + return pdomBinding.getRecord(); + } + + /** + * Return the PDOMBinding for the given Qt name creating a new binding if needed. The + * implementation caches the result using the name instance as the key. This ensures + * one-to-one uniqueness between AST names and PDOMBindings. + *

+ * This method is not thread-safe. + */ + public PDOMBinding getBinding(IQtASTName qtAstName) throws CoreException { + // The Qt implementation ensures uniqueness by creating only a single instance of + // the IASTName for each thing that should create a single instance in the PDOM. + // This will work as long as all Qt elements are updated at once, which is currently + // the case. + // + // I don't think this needs to be thread-safe, because things are only added from + // the single indexer task. + PDOMBinding pdomBinding = null; + pdomBinding = cache.get(qtAstName); + if (pdomBinding != null) + return pdomBinding; + + // The result is cached even when null is returned. + pdomBinding = qtAstName.createPDOMBinding(this); + cache.put(qtAstName, pdomBinding); + + // Only add children that are actually created. + if (pdomBinding != null) + addChild(pdomBinding); + + return pdomBinding; + } + + @Override + public PDOMBinding addBinding(IASTName name) throws CoreException { + + // The Qt linkage is able to reference elements in other linkages. This implementation + // needs to decide if the binding associated with this name is from the Qt linkage or + // from one of those external references. + + if (name == null) + return null; + + if (name instanceof IQtASTName) + return getBinding((IQtASTName) name); + + IBinding binding = name.getBinding(); + if (binding == null) + return null; + + // Use the receiving linkage by default, and override only if the binding is found to + // have a linkage with a different id. + PDOMLinkage pdomLinkage = this; + ILinkage linkage = binding.getLinkage(); + if (linkage != null + && linkage.getLinkageID() != getLinkageID()) + pdomLinkage = getPDOM().getLinkage(linkage.getLinkageID()); + + // Handle bindings in unknown linkages as though the name is to be added to this linkage. + return (pdomLinkage == null ? this : pdomLinkage).adaptBinding(binding); + } + + @Override + public int getBindingType(IBinding binding) { + return binding instanceof QtPDOMBinding ? ((QtPDOMBinding) binding).getNodeType() : 0; + } + + @Override + public PDOMBinding addTypeBinding(IBinding binding) throws CoreException { + throw new CoreException(QtPlugin.error("Qt Linkage does not manage types")); //$NON-NLS-1$ + } + + @Override + public IType unmarshalType(ITypeMarshalBuffer buffer) throws CoreException { + throw new CoreException(QtPlugin.error("Qt Linkage does not marshal types")); //$NON-NLS-1$ + } + + @Override + public IBinding unmarshalBinding(ITypeMarshalBuffer buffer) throws CoreException { + throw new CoreException(QtPlugin.error("Qt Linkage does not marshal bindings")); //$NON-NLS-1$ + } + + @Override + public ISerializableEvaluation unmarshalEvaluation(ITypeMarshalBuffer typeMarshalBuffer) throws CoreException { + throw new CoreException(QtPlugin.error("Qt Linkage does not marshal evaluations")); //$NON-NLS-1$ + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMNodeType.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMNodeType.java new file mode 100644 index 00000000000..f79c65749d4 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMNodeType.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.internal.core.index.IIndexBindingConstants; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public enum QtPDOMNodeType { + + QObject, + QEnum, + QProperty, + QMethod; + + public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal(); + + /** + * The current version of the QtPDOMLinkage. This can be used to make sure the persisted + * data matches what is expected by the implementation. Care should be taken to make changes + * backward compatible when possible. + *

+ * The version is needed because ordinals for these enumerators are written to the file. + */ + public static final int VERSION = 4; + + public static QtPDOMNodeType forType(int version, int type) { + // Nothing has been deleted or replaced yet, so the version is ignored. + + for(QtPDOMNodeType node : values()) + if (node.Type == type) + return node; + return null; + } + + // This needs to return PDOMNode so that it can be either QtPDOMNode or QtPDOMBinding. + public static PDOMNode load(QtPDOMLinkage linkage, int nodeType, long record) throws CoreException { + QtPDOMNodeType node = QtPDOMNodeType.forType(linkage.getVersion(), nodeType); + if (node == null) + return null; + + switch(node) { + case QObject: + return new QtPDOMQObject(linkage, record); + case QEnum: + return new QtPDOMQEnum(linkage, record); + case QProperty: + return new QtPDOMProperty(linkage, record); + case QMethod: + return new QtPDOMQMethod(linkage, record); + } + + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMProperty.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMProperty.java new file mode 100644 index 00000000000..91123a91301 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMProperty.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.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.dom.PDOMBinding; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.qt.core.index.IQProperty; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPDOMProperty extends QtPDOMBinding { + + private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + protected static enum Field { + Type(Database.PTR_SIZE), + Attributes(Database.PTR_SIZE), + Last(0); + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + public QtPDOMProperty(QtPDOMLinkage linkage, long record) { + super(linkage, record); + } + + public QtPDOMProperty(QtPDOMLinkage linkage, PDOMBinding parent, QtPropertyName qtName) throws CoreException { + super(linkage, parent, qtName); + + setType(qtName.getType()); + + if (parent instanceof QtPDOMQObject) + ((QtPDOMQObject) parent).addChild(this); + } + + @Override + protected int getRecordSize() { + return Field.Last.offset; + } + + @Override + public int getNodeType() { + return QtPDOMNodeType.QProperty.Type; + } + + public void delete() throws CoreException { + long fieldRec = getDB().getRecPtr(Field.Type.getRecord(record)); + if (fieldRec != 0) + getDB().getString(fieldRec).delete(); + getDB().putRecPtr(Field.Type.getRecord(record), 0); + } + + public void setType(String type) throws CoreException { + long rec = getDB().getRecPtr(Field.Type.getRecord(record)); + if (rec != 0) { + IString typeStr = getDB().getString(rec); + if (type == null) { + typeStr.delete(); + return; + } + + // There is nothing to do if the database already stores the same name. + if (type.equals(typeStr.getString())) + return; + } + + getDB().putRecPtr(Field.Type.getRecord(record), getDB().newString(type).getRecord()); + } + + // IType? + public String getType() throws CoreException { + long rec = getDB().getRecPtr(Field.Type.getRecord(record)); + if (rec == 0) + return null; + + return getDB().getString(rec).getString(); + } + + public void setAttributes(Attribute[] attributes) throws CoreException { + long rec = getDB().getRecPtr(Field.Attributes.getRecord(record)); + QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), Attribute.Codec, rec); + rec = pdomArray.set(attributes); + getDB().putRecPtr(Field.Attributes.getRecord(record), rec); + } + + public Attribute[] getAttributes() throws CoreException { + long rec = getDB().getRecPtr(Field.Attributes.getRecord(record)); + QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), Attribute.Codec, rec); + return pdomArray.get(); + } + + public static class Attribute { + public final IQProperty.Attribute attr; + public final String value; + public final long cppRecord; + + public Attribute(IQProperty.Attribute attr, String value) { + this.attr = attr; + this.value = value; + this.cppRecord = 0; + } + + public Attribute(IQProperty.Attribute attr, String value, PDOMBinding cppBinding) { + this.attr = attr; + this.value = value; + this.cppRecord = cppBinding == null ? 0 : cppBinding.getRecord(); + } + + private Attribute(IQProperty.Attribute attr, String value, long cppRecord) { + this.attr = attr; + this.value = value; + this.cppRecord = cppRecord; + } + + private static final IQtPDOMCodec Codec = new IQtPDOMCodec() { + @Override + public int getElementSize() { + return 1 + Database.PTR_SIZE + Database.PTR_SIZE; + } + + @Override + public Attribute[] allocArray(int count) { + return new Attribute[count]; + } + + @Override + public Attribute decode(QtPDOMLinkage linkage, long record) throws CoreException { + byte attrId = linkage.getDB().getByte(record); + long valRec = linkage.getDB().getRecPtr(record + 1); + long cppRec = linkage.getDB().getRecPtr(record + 1 + Database.PTR_SIZE); + + if (attrId < 0 || attrId >= IQProperty.Attribute.values().length) + throw QtPlugin.coreException("invalid QProperty attribute id read from datbase, was " + attrId); + + IQProperty.Attribute attr = IQProperty.Attribute.values()[attrId]; + + String val = valRec == 0 ? "" : linkage.getDB().getString(valRec).getString(); + return new Attribute(attr, val, cppRec); + } + + @Override + public void encode(QtPDOMLinkage linkage, long record, Attribute element) throws CoreException { + linkage.getDB().putByte(record, (byte) element.attr.ordinal()); + + // Delete the existing strings then create and store new ones. + long rec = linkage.getDB().getRecPtr(record + 1); + if (rec != 0) + linkage.getDB().getString(rec).delete(); + + if (element == null || element.value == null) + linkage.getDB().putRecPtr(record + 1, 0); + else + linkage.getDB().putRecPtr(record + 1, linkage.getDB().newString(element.value).getRecord()); + + linkage.getDB().putRecPtr(record + 1 + Database.PTR_SIZE, element.cppRecord); + } + }; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQEnum.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQEnum.java new file mode 100644 index 00000000000..e17a61b36db --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQEnum.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IEnumeration; +import org.eclipse.cdt.core.dom.ast.IEnumerator; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPDOMQEnum extends QtPDOMBinding { + + private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + protected static enum Field { + Flags(1), + CppRecord(Database.PTR_SIZE), + Last(0); + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + private static final int IS_FLAG_MASK = 1; + + private QtPDOMQObject qobj; + + protected QtPDOMQEnum(QtPDOMLinkage linkage, long record) throws CoreException { + super(linkage, record); + } + + public QtPDOMQEnum(QtPDOMLinkage linkage, PDOMBinding parent, IASTName qtName, IASTName cppName) throws CoreException { + super(linkage, parent, qtName); + + getDB().putRecPtr(Field.CppRecord.getRecord(record), linkage.getCPPRecord(cppName)); + + // The flags are set in several sections, and then written to the Database in one operation. + byte flags = 0; + + if (qtName instanceof QtEnumName + && ((QtEnumName) qtName).isFlag()) + flags |= IS_FLAG_MASK; + + // Write the flags to the database. + getDB().putByte(Field.Flags.getRecord(record), flags); + + if (!(parent instanceof QtPDOMQObject)) + this.qobj = null; + else { + this.qobj = (QtPDOMQObject) parent; + this.qobj.addChild(this); + } + } + + @Override + public int getRecordSize() { + return Field.Last.offset; + } + + public IEnumeration getCppEnumeration() throws CoreException { + long cppRec = getDB().getRecPtr(Field.CppRecord.getRecord(record)); + if (cppRec == 0) + return null; + + PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID); + if (cppLinkage == null) + return null; + + PDOMBinding cppBinding = cppLinkage.getBinding(cppRec); + + // TODO + if (cppBinding == null) + return null; + cppBinding.getAdapter(IEnumeration.class); + + return cppBinding instanceof IEnumeration ? (IEnumeration) cppBinding : null; + } + + public boolean isFlag() throws CoreException { + byte flags = getDB().getByte(Field.Flags.getRecord(record)); + return (flags & IS_FLAG_MASK) == IS_FLAG_MASK; + } + + @Override + public int getNodeType() { + return QtPDOMNodeType.QEnum.Type; + } + + public List getEnumerators() throws CoreException { + IEnumeration cppEnum = getCppEnumeration(); + return cppEnum == null ? Collections.emptyList() : Arrays.asList(cppEnum.getEnumerators()); + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQMethod.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQMethod.java new file mode 100644 index 00000000000..0cd317e5782 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQMethod.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.qt.core.index.IQMethod; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPDOMQMethod extends QtPDOMBinding { + + private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + protected static enum Field { + Signature(Database.PTR_SIZE), + Revision(8), + Flags(1), + Last(0); + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + private static final int KIND_IS_INVOKABLE = 1; + private static final int KIND_IS_SIGNAL = 2; + private static final int KIND_IS_SLOT = 3; + private static final int KIND_MASK = 3; + private static final int HAS_REVISION = 4; + + public QtPDOMQMethod(QtPDOMLinkage linkage, long record) throws CoreException { + super(linkage, record); + } + + public QtPDOMQMethod(QtPDOMLinkage linkage, PDOMBinding parent, IASTName qtName, IASTName cppName, IQMethod.Kind kind, String qtEncSignatures, Long revision) throws CoreException { + super(linkage, parent, qtName); + + byte flag = 0; + switch(kind) { + case Invokable: + flag |= KIND_IS_INVOKABLE; + break; + case Signal: + flag |= KIND_IS_SIGNAL; + break; + case Slot: + flag |= KIND_IS_SLOT; + break; + case Unspecified: + break; + } + + if (revision != null) { + flag |= HAS_REVISION; + getDB().putLong(Field.Revision.getRecord(record), revision.longValue()); + } + + getDB().putByte(Field.Flags.getRecord(record), flag); + + long rec = qtEncSignatures == null ? 0 : getDB().newString(qtEncSignatures).getRecord(); + getDB().putRecPtr(Field.Signature.getRecord(record), rec); + + if (parent instanceof QtPDOMQObject) + ((QtPDOMQObject) parent).addChild(this); + } + + @Override + protected int getRecordSize() { + return Field.Last.offset; + } + + public IQMethod.Kind getKind() throws CoreException { + switch(getDB().getByte(Field.Flags.getRecord(record)) & KIND_MASK) { + case KIND_IS_INVOKABLE: + return IQMethod.Kind.Invokable; + case KIND_IS_SIGNAL: + return IQMethod.Kind.Signal; + case KIND_IS_SLOT: + return IQMethod.Kind.Slot; + default: + return IQMethod.Kind.Unspecified; + } + } + + public String getQtEncodedSignatures() throws CoreException { + long rec = getDB().getRecPtr(Field.Signature.getRecord(record)); + return rec == 0 ? null : getDB().getString(rec).getString(); + } + + public Long getRevision() throws CoreException { + byte flag = getDB().getByte(Field.Flags.getRecord(record)); + if ((flag & HAS_REVISION) == 0) + return null; + + return Long.valueOf(getDB().getLong(Field.Revision.getRecord(record))); + } + + @Override + public int getNodeType() { + return QtPDOMNodeType.QMethod.Type; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQObject.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQObject.java new file mode 100644 index 00000000000..ce599868cfd --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQObject.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.PDOMNodeLinkedList; +import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.core.runtime.CoreException; + +/** + * The persisted form of QObjects. + */ +@SuppressWarnings("restriction") +public class QtPDOMQObject extends QtPDOMBinding { + + private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + protected static enum Field { + CppRecord(Database.PTR_SIZE, 3), + Children(4 /* From PDOMNodeLinkedList.RECORD_SIZE, which is protected */, 0), + ClassInfos(Database.PTR_SIZE, 2), + Last(0, 0); + + private final int offset; + private final int version; + + private Field(int sizeof, int version) { + this.offset = offsetInitializer; + this.version = version; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + + /** + * Return true if this linkage in supported in the given instance of the linkage. + */ + public boolean isSupportedIn(QtPDOMLinkage linkage) { + return linkage.getVersion() >= version; + } + } + + private final PDOMNodeLinkedList children; + + protected QtPDOMQObject(QtPDOMLinkage linkage, long record) throws CoreException { + super(linkage, record); + children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record)); + } + + public QtPDOMQObject(QtPDOMLinkage linkage, IASTName qtName, IASTName cppName) throws CoreException { + super(linkage, null, qtName); + + IBinding cppBinding = getPDOM().findBinding(cppName); + if (cppBinding != null) { + IPDOMBinding cppPDOMBinding = (IPDOMBinding) cppBinding.getAdapter(IPDOMBinding.class); + if (cppPDOMBinding != null) { + if (cppPDOMBinding.getLinkage() != null + && cppPDOMBinding.getLinkage().getLinkageID() == ILinkage.CPP_LINKAGE_ID) + getDB().putRecPtr(Field.CppRecord.getRecord(record), cppPDOMBinding.getRecord()); + } + } + + children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record)); + + if (qtName instanceof QObjectName) { + QObjectName qobjName = (QObjectName) qtName; + setClassInfos(qobjName.getClassInfos()); + } + } + + public void delete() throws CoreException { + long fieldRec = Field.ClassInfos.getRecord(record); + new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, fieldRec).delete(); + getDB().putRecPtr(Field.ClassInfos.getRecord(record), 0); + } + + public ICPPClassType getCppClassType() throws CoreException { + long cppRec = getDB().getRecPtr(Field.CppRecord.getRecord(record)); + if (cppRec == 0) + return null; + + PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID); + if (cppLinkage == null) + return null; + + PDOMBinding cppBinding = cppLinkage.getBinding(cppRec); + return cppBinding instanceof ICPPClassType ? (ICPPClassType) cppBinding : null; + } + + public void setClassInfos(Map classInfos) throws CoreException { + + // Make sure the version of the linkage contains this field. + if (!Field.ClassInfos.isSupportedIn(getQtLinkage())) + return; + + // Create an array to be stored to the PDOM. + ClassInfo[] array = new ClassInfo[classInfos.size()]; + Iterator> iterator = classInfos.entrySet().iterator(); + for(int i = 0; i < array.length && iterator.hasNext(); ++i) { + Map.Entry entry = iterator.next(); + array[i] = new ClassInfo(entry.getKey(), entry.getValue()); + } + + // Store the array into the Database. + long arrayRec = getDB().getRecPtr(Field.ClassInfos.getRecord(record)); + QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, arrayRec); + arrayRec = pdomArray.set(array); + + // Update the record that is stored in the receiver's field. + getDB().putRecPtr(Field.ClassInfos.getRecord(record), arrayRec); + } + + public Map getClassInfos() throws CoreException { + Map classInfos = new LinkedHashMap(); + + // Make sure the version of the linkage contains this field. + if (!Field.ClassInfos.isSupportedIn(getQtLinkage())) + return classInfos; + + // Read the array from the Database and insert the elements into the Map that is to be returned. + long arrayRec = getDB().getRecPtr(Field.ClassInfos.getRecord(record)); + QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, arrayRec); + + ClassInfo[] array = pdomArray.get(); + if (array == null) + return classInfos; + + for(ClassInfo classInfo : array) + classInfos.put(classInfo.key, classInfo.value); + + return classInfos; + } + + @Override + protected int getRecordSize() { + return Field.Last.offset; + } + + @Override + public int getNodeType() { + return QtPDOMNodeType.QObject.Type; + } + + // This forwarding method is to get rid of compilation warnings when clients try to call + // #getName on the non-accessible parent. + @Override + public String getName() { + return super.getName(); + } + + public List findBases() throws CoreException { + ICPPClassType cppClassType = getCppClassType(); + if (cppClassType == null) + return Collections.emptyList(); + + List bases = new ArrayList(); + for (ICPPBase base : cppClassType.getBases()) { + if (base.getVisibility() != ICPPBase.v_public) + continue; + + IBinding baseCls = base.getBaseClass(); + if (baseCls == null) + continue; + + PDOMBinding pdomBinding = (PDOMBinding) baseCls.getAdapter(PDOMBinding.class); + QtPDOMQObject baseQObj = ASTNameReference.findFromBinding(QtPDOMQObject.class, pdomBinding); + if (baseQObj != null) + bases.add(baseQObj); + } + + return bases; + } + + @Override + public void addChild(PDOMNode child) throws CoreException { + children.addMember(child); + } + + public List getChildren(Class cls) throws CoreException { + QtPDOMVisitor.All collector = new QtPDOMVisitor.All(cls); + try { + children.accept(collector); + } catch(CoreException e) { + QtPlugin.log(e); + return Collections.emptyList(); + } + + return collector.list; + } + + private static class ClassInfo { + public final String key; + public final String value; + public ClassInfo(String key, String value) { + this.key = key; + this.value = value; + } + + public static final IQtPDOMCodec Codec = new IQtPDOMCodec() { + @Override + public int getElementSize() { + return 2 * Database.PTR_SIZE; + } + + @Override + public ClassInfo[] allocArray(int count) { + return new ClassInfo[count]; + } + + @Override + public ClassInfo decode(QtPDOMLinkage linkage, long record) throws CoreException { + long keyRec = linkage.getDB().getRecPtr(record); + long valRec = linkage.getDB().getRecPtr(record + Database.PTR_SIZE); + return new ClassInfo(linkage.getDB().getString(keyRec).getString(), linkage.getDB().getString(valRec).getString()); + } + + @Override + public void encode(QtPDOMLinkage linkage, long record, ClassInfo element) throws CoreException { + // Delete the existing strings then create and store new ones. + long rec = linkage.getDB().getRecPtr(record); + if (rec != 0) + linkage.getDB().getString(rec).delete(); + linkage.getDB().putRecPtr(record, element == null ? 0 : linkage.getDB().newString(element.key).getRecord()); + + rec = linkage.getDB().getRecPtr(record + Database.PTR_SIZE); + if (rec != 0) + linkage.getDB().getString(rec).delete(); + linkage.getDB().putRecPtr(record + Database.PTR_SIZE, element == null ? 0 : linkage.getDB().newString(element.value).getRecord()); + } + }; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMVisitor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMVisitor.java new file mode 100644 index 00000000000..867b2ac1944 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMVisitor.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.eclipse.cdt.core.dom.IPDOMNode; +import org.eclipse.cdt.core.dom.IPDOMVisitor; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNamedNode; +import org.eclipse.core.runtime.CoreException; + +/** + * A Qt-specific specialization of the generic PDOMVisitor. This class provides + * an empty implementation of {@link #leave(IPDOMNode)}, but required implementations to + * provide {@link #visit(IPDOMNode)}. The class also provides a few commonly required + * implementations. + */ +@SuppressWarnings("restriction") +public abstract class QtPDOMVisitor implements IPDOMVisitor { + + /** + * Collects all nodes that match the given type. This could be used, for example, to get + * all QtPDOMQObject's from the index. + */ + public static class All extends QtPDOMVisitor { + + private final Class cls; + public final ArrayList list = new ArrayList(); + + public All(Class cls) { + this.cls = cls; + } + + @Override + @SuppressWarnings("unchecked") + public boolean visit(IPDOMNode node) throws CoreException { + if (node != null + && cls.isAssignableFrom(node.getClass())) + list.add((T) node); + return true; + } + } + + /** + * A simple interface that is used to select node's from the index based on specific + * criteria. + */ + public static interface IFilter { + public boolean matches(IPDOMNode node) throws CoreException; + } + + /** + * A filter that selects nodes based on their name. + */ + public static class PDOMNamedNodeFilter implements IFilter { + + private final char[] name; + + public PDOMNamedNodeFilter(String name) { + this.name = name.toCharArray(); + } + + @Override + public boolean matches(IPDOMNode node) throws CoreException { + if (node instanceof PDOMNamedNode) + return Arrays.equals(name, ((PDOMNamedNode) node).getNameCharArray()); + return false; + } + } + + /** + * A utility class that searches the index for all nodes that match the given filter. + */ + public static class Find extends QtPDOMVisitor { + + private final Class cls; + private final IFilter filter; + + public T element; + + public Find(Class cls, IFilter filter) { + this.cls = cls; + this.filter = filter; + } + + @Override + @SuppressWarnings("unchecked") + public boolean visit(IPDOMNode node) throws CoreException { + if (element != null) + return false; + + if (cls.isAssignableFrom(node.getClass()) + && filter.matches(node)) + element = (T) node; + + return element == null; + } + } + + @Override + public void leave(IPDOMNode node) throws CoreException { + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyAttributeName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyAttributeName.java new file mode 100644 index 00000000000..0bead196c15 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyAttributeName.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.core.runtime.CoreException; + +public class QtPropertyAttributeName extends ASTDelegatedName implements IQtASTName { + + private final QtASTImageLocation location; + + public QtPropertyAttributeName(IASTName ast, String name, QtASTImageLocation location) { + super(ast); + this.location = location; + } + + @Override + public IASTFileLocation getFileLocation() { + return location; + } + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyName.java new file mode 100644 index 00000000000..12a4cfa4819 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPropertyName.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.cdt.internal.qt.core.pdom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; +import org.eclipse.cdt.qt.core.index.IQProperty; +import org.eclipse.core.runtime.CoreException; + +@SuppressWarnings("restriction") +public class QtPropertyName extends AbstractQObjectMemberName implements IQtASTName { + + private String type; + // TODO The PDOM attrs should only be created in #createPDOMBinding + private List attributes = new ArrayList(); + + public QtPropertyName(QObjectName qobjName, IASTName ast, String name, QtASTImageLocation location) { + super(qobjName, ast, name, location); + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * This permits storage of duplicate attributes, a Codan checker should flag this as an error, but + * while the invalid code exists, the references should continue to be properly resolved. + */ + public void addAttribute(IQProperty.Attribute attr, String value) { + attributes.add(new QtPDOMProperty.Attribute(attr, value)); + } + + /** + * This permits storage of duplicate attributes, a Codan checker should flag this as an error, but + * while the invalid code exists, the references should continue to be properly resolved. + */ + public void addAttribute(IQProperty.Attribute attr, String value, IBinding cppBinding) { + PDOMBinding pdomBinding = cppBinding == null ? null : (PDOMBinding) cppBinding.getAdapter(PDOMBinding.class); + attributes.add(new QtPDOMProperty.Attribute(attr, value, pdomBinding)); + } + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + QtPDOMProperty pdom = new QtPDOMProperty(linkage, getOwner(linkage), this); + pdom.setAttributes(attributes.toArray(new QtPDOMProperty.Attribute[attributes.size()])); + return pdom; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/QtIndex.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/QtIndex.java index 90bdde99d2c..eb8f3a8f1e4 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/QtIndex.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/QtIndex.java @@ -7,8 +7,8 @@ */ package org.eclipse.cdt.qt.core.index; +import org.eclipse.cdt.internal.qt.core.index.QtFactory; import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.cdt.qt.internal.core.index.QtFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePaths.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePaths.java deleted file mode 100644 index 20a75126d36..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePaths.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider; -import org.eclipse.cdt.core.settings.model.CIncludePathEntry; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; -import org.eclipse.cdt.core.settings.model.ICSettingEntry; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.cdt.utils.spawner.ProcessFactory; -import org.eclipse.core.resources.IResource; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * Discovers and persists the list of Qt include paths for a particular installation of - * Qt. The Qt installation is described by the path to qmake. - *

- * Qt uses a tool called qmake to generate makefiles for Qt projects. The tool has a - * query mode that can be used to discover information about the Qt installation. Here - * qmake is used to build a list of all installed Qt include paths. - *

- * These paths are persisted into a file called language-settings.xml in the workspace - * metadata area. - * - * @see QtIncludePathsProvider - */ -public class QtIncludePaths extends LanguageSettingsSerializableProvider { - - /** - * The path to the qmake executable uniquely identifies this installation. - */ - private final String qmakePath; - - /** - * The cached data is reloaded when the qmake executable is modified. - */ - private long qmakeModTime; - - /** - * The cached data is reloaded when the folder holding the include paths - * is removed. - */ - private String qtInstallHeadersPath; - - /** - * The cached data is reloaded when the folder containing the include folders is - * modified. - */ - private long qtInstallHeadersModTime; - - private static final String ATTR_QMAKE = "qmake"; - private static final String ATTR_QMAKE_MOD = "qmakeModification"; - private static final String ATTR_QT_INSTALL_HEADERS = "QT_INSTALL_HEADERS"; - private static final String ATTR_QT_INSTALL_HEADERS_MOD = "qtInstallHeadersModification"; - - /** - * Create a new instance of the include path wrapper for the Qt installation for - * the given qmake binary. - */ - public QtIncludePaths(String qmakePath) { - this.qmakePath = qmakePath; - } - - /** - * Create and load an instance of QtIncludePaths from data that was serialized into the - * given XML element. Return null if an instance cannot be loaded or if the installation - * is no longer valid. - */ - public static QtIncludePaths loadFrom(Node node) { - if (node.getNodeType() != Node.ELEMENT_NODE) - return null; - - Element element = (Element) node; - String qmakePath = element.getAttribute(ATTR_QMAKE); - if (qmakePath == null - || qmakePath.isEmpty()) - return null; - - QtIncludePaths qtIncludePaths = new QtIncludePaths(qmakePath); - qtIncludePaths.load(element); - return qtIncludePaths; - } - - public String getQMakePath() { - return qmakePath; - } - - /** - * Return true if the receiver points to a valid Qt installation and false otherwise. - * The installation is considered valid if an executable qmake binary exists at the - * expected location. - */ - public boolean isValid() { - if (qmakePath == null - || qmakePath.isEmpty()) - return false; - - File qmake = new File(qmakePath); - return qmake.exists() - && qmake.canExecute(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof QtIncludePaths)) - return super.equals(obj); - - // Include paths are equivalent when they point to the same qmake binary. All other - // values are reloaded from that binary and do not need to be directly compared. - QtIncludePaths other = (QtIncludePaths) obj; - return qmakePath == null ? other.qmakePath == null : qmakePath.equals(other.qmakePath); - } - - @Override - public int hashCode() { - return qmakePath == null ? 0 : qmakePath.hashCode(); - } - - /** - * Return a current list of the include paths for this Qt installation. Return null if - * no such paths can be found. - *

- * Updates the cached results if needed. If the settings are updated then the new list - * will be serialized into the workspace metadata area. - */ - @Override - public List getSettingEntries(ICConfigurationDescription configDesc, IResource rc, String languageId) { - List entries = null; - - File qmake = new File(qmakePath); - if (!qmake.exists() - || qmakeModTime != qmake.lastModified()) - entries = reload(); - else { - File qtInstallHeadersDir = new File(qtInstallHeadersPath); - if (!qtInstallHeadersDir.exists() - || qtInstallHeadersModTime != qtInstallHeadersDir.lastModified()) - entries = reload(); - } - - // If the cache was not reloaded, then return the previously discovered entries. - if (entries == null) - return super.getSettingEntries(configDesc, rc, languageId); - - // Otherwise store, persist, and return the newly discovered values. - setSettingEntries(configDesc, rc, languageId, entries); - serializeLanguageSettingsInBackground(null); - return entries; - } - - @Override - public Element serializeAttributes(Element parentElement) { - parentElement.setAttribute(ATTR_QMAKE, qmakePath); - parentElement.setAttribute(ATTR_QMAKE_MOD, Long.toString(qmakeModTime)); - parentElement.setAttribute(ATTR_QT_INSTALL_HEADERS, qtInstallHeadersPath); - parentElement.setAttribute(ATTR_QT_INSTALL_HEADERS_MOD, Long.toString(qtInstallHeadersModTime)); - - // The parent implementation tries to create a new child node (provider) that is used - // as the part for later entries. This isn't needed in this case, we just want to - // use the part that serializes the languages. - return parentElement; - } - - @Override - public void loadAttributes(Element element) { - qmakeModTime = getLongAttribute(element, ATTR_QMAKE_MOD); - qtInstallHeadersPath = element.getAttribute(ATTR_QT_INSTALL_HEADERS); - qtInstallHeadersModTime = getLongAttribute(element, ATTR_QT_INSTALL_HEADERS_MOD); - - // The parent implementation tries to create a new child node (provider) that is used - // as the part for later entries. This isn't needed in this case, we just want to - // use the part that serializes the languages. - } - - /** - * Parse and return the given attribute as a long. Return 0 if the attribute does - * not have a valid value. - */ - private static long getLongAttribute(Element element, String attr) { - String value = element.getAttribute(attr); - if (value == null - || value.isEmpty()) - return 0; - - try { - return Long.parseLong(value); - } catch(NumberFormatException e) { - QtPlugin.log("attribute name:" + attr + " value:" + value, e); - return 0; - } - } - - /** - * Reload and return the entries if possible, return null otherwise. - */ - private List reload() { - // All keys are reset and then updated as their values are discovered. This allows partial - // success to skip over previously calculated values. - qmakeModTime = 0; - qtInstallHeadersPath = null; - qtInstallHeadersModTime = 0; - - File qmake = new File(qmakePath); - if (!qmake.exists() - || !qmake.canExecute()) - return Collections.emptyList(); - - qmakeModTime = qmake.lastModified(); - - // Run `qmake -query QT_INSTALL_HEADERS` to get output like "/opt/qt-5.0.0/include". - BufferedReader reader = null; - Process process = null; - try { - process = ProcessFactory.getFactory().exec(new String[]{ qmakePath, "-query", "QT_INSTALL_HEADERS" }); - reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - qtInstallHeadersPath = reader.readLine(); - } catch(IOException e) { - QtPlugin.log(e); - } finally { - try { - if (reader != null) - reader.close(); - } catch(IOException e) { - /* ignore */ - } finally { - if (process != null) - process.destroy(); - } - } - - if (qtInstallHeadersPath == null) - return Collections.emptyList(); - - File qtInstallHeadersDir = new File(qtInstallHeadersPath); - - qtInstallHeadersModTime = qtInstallHeadersDir.lastModified(); - if (!qtInstallHeadersDir.exists() - || !qtInstallHeadersDir.canRead() - || !qtInstallHeadersDir.isDirectory()) - return Collections.emptyList(); - - // Create an include path entry for all sub-folders in the QT_INSTALL_HEADERS location, including - // the QT_INSTALL_HEADERS folder itself. - File[] files = qtInstallHeadersDir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.exists() && pathname.isDirectory(); - } - }); - - List entries = new ArrayList(files.length + 1); - safeAdd(entries, qtInstallHeadersDir); - for(File file : files) - safeAdd(entries, file); - - return entries; - } - - private static void safeAdd(List entries, File file) { - try { - entries.add(new CIncludePathEntry(file.getCanonicalPath(), ICSettingEntry.READONLY | ICSettingEntry.RESOLVED)); - } catch(IOException e) { - QtPlugin.log(e); - } - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePathsProvider.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePathsProvider.java deleted file mode 100644 index 6c2076bd48d..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtIncludePathsProvider.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.envvar.IEnvironmentVariable; -import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsSerializableProvider; -import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; -import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry; -import org.eclipse.core.resources.IResource; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * This provider uses persistent cache to store the include paths for different - * Qt installations. A Qt installation is uniquely identified by the path to - * the qmake binary within the installation. - *

- * This result is shared among all Build Configurations that use the provider - * with the same value for the QMAKE environment variable. - */ -public class QtIncludePathsProvider extends LanguageSettingsSerializableProvider { - - /** - * The provider identifies Qt installations by the absolute path to the qmake binary. The - * include paths relevant to the installations are computed and persisted in {@link QtIncludePaths}. - */ - private final Map qtInstallHeaders = new HashMap(); - - /** - * The build configuration stores the path to the qmake binary as an environment variable. - */ - private static final String ENVVAR_QMAKE = "QMAKE"; - - private static final String ELEMENT_QMAKE = "qmake"; - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof QtIncludePathsProvider)) - return super.equals(obj); - - /** - * Providers are equal when they have the same cached values. - */ - QtIncludePathsProvider other = (QtIncludePathsProvider) obj; - if (qtInstallHeaders == null) - return other.qtInstallHeaders == null; - return qtInstallHeaders.equals(other.qtInstallHeaders); - } - - @Override - public int hashCode() { - return qtInstallHeaders == null ? 0 : qtInstallHeaders.hashCode(); - } - - @Override - public void loadEntries(Element providerNode) { - super.loadEntries(providerNode); - - // Find and load all qmake child nodes. There will be one node for each Qt - // installation that has been used. Qt installations that are no longer valid - // are not loaded. This means they will be removed from the file the next time - // that the language setting providers are serialized. - NodeList children = providerNode.getChildNodes(); - for (int i = 0; i < children.getLength(); ++i) { - Node child = children.item(i); - if (ELEMENT_QMAKE.equals(child.getNodeName())) { - QtIncludePaths qtIncludePaths = QtIncludePaths.loadFrom(child); - if (qtIncludePaths != null - && qtIncludePaths.isValid()) - qtInstallHeaders.put(qtIncludePaths.getQMakePath(), qtIncludePaths); - } - } - } - - @Override - public void serializeEntries(Element parent) { - // NOTE: This creates its own XML structure where children of the provider node are qmake nodes. - // Within each qmake node is a list of include paths for that installation. Calling the - // base #serializeEntries here would try to write this instance's (empty) list of settings - // to the file. - - // Each value is serialized into a new element in the XML document. - Document document = parent instanceof Document ? (Document)parent : parent.getOwnerDocument(); - for(QtIncludePaths qtIncludePaths : qtInstallHeaders.values()) { - Element child = document.createElement(ELEMENT_QMAKE); - qtIncludePaths.serialize(child); - parent.appendChild(child); - } - } - - /** - * The given build configuration's QMAKE environment variable is used to identify the appropriate - * Qt installation. The language settings are then either returned from the previously persisted - * data or loaded, serialized, and returned. - */ - @Override - public synchronized List getSettingEntries(ICConfigurationDescription configDesc, IResource rc, String languageId) { - // Make sure the requested language is in scope for this provider. - if (!getLanguageScope().contains(languageId)) - return null; - - // The value of the build configuration's QMAKE environment variable is used to select the - // right version of qmake. - IEnvironmentVariable qmake_var = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENVVAR_QMAKE, configDesc, true); - if (qmake_var == null) - return null; - - String qmake = qmake_var.getValue(); - if (qmake == null) - return null; - - // The path to qmake is used as the key into the in-memory cache of header paths. - QtIncludePaths paths = qtInstallHeaders.get(qmake); - if (paths == null) { - paths = new QtIncludePaths(qmake); - qtInstallHeaders.put(qmake, paths); - } - - return paths.getSettingEntries(configDesc, null, languageId); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtMethodUtil.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtMethodUtil.java deleted file mode 100644 index c25a7e511c1..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtMethodUtil.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.bind.DatatypeConverter; - -import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTPointer; -import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; -import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; -import org.eclipse.cdt.internal.qt.core.parser.QtParser; - -/** - * A collection of utility functions for dealing with Qt methods. A Qt method is a normal - * C++ method that has been annotated with empty macro expansions. - */ -@SuppressWarnings("restriction") -public class QtMethodUtil { - - /** - * The Qt implementation uses specific rules for generating a signature that is used - * to map between invokable function declarations and their use. This function has - * be implemented by comparing the output of moc to the various test cases in the - * qt test suite. - */ - public static String getQtNormalizedMethodSignature(String signature) { - - ICPPASTFunctionDeclarator function = QtParser.parseQtMethodReference(signature); - if (function == null) - return null; - - // NOTE: This implementation (both here and in methods that are invoked) used call #getRawSignature - // to get the original tokens. This has been changed to use #toString instead. They seem to - // provide the same value, so this should be OK. The problem with #getRawSignature is that it - // looks for the characters in the file (using offset and length). There isn't a file backing - // the StringScanner, so the result is the empty String. If we find cases where #toString - // returns the wrong value, then this can be changed back to #getRawSignature. Implement the - // AST and LocationResolver to work with ASTNode#getRawSignatureChars: - // protected char[] getRawSignatureChars() { - // final IASTFileLocation floc= getFileLocation(); - // final IASTTranslationUnit ast = getTranslationUnit(); - // if (floc != null && ast != null) { - // ILocationResolver lr= (ILocationResolver) ast.getAdapter(ILocationResolver.class); - // if (lr != null) { - // return lr.getUnpreprocessedSignature(getFileLocation()); - // } - // } - - StringBuilder result = new StringBuilder(); - - // raw sig tries to find the file - String fnName = function.getName().getLastName().toString(); - result.append(stripWS(fnName)); - result.append('('); - - boolean first = true; - for(ICPPASTParameterDeclaration param : function.getParameters()) { - if (first) - first = false; - else - result.append(','); - - IASTDeclSpecifier spec = param.getDeclSpecifier(); - ICPPASTDeclarator declarator = param.getDeclarator(); - - // The parameters are encoded so that we can rely on , being used to separate - // parameters. All other commas (e.g., to separate template arguments within - // the parameter type) will be encoded. - StringBuilder paramSig = new StringBuilder(); - append(paramSig, spec, declarator, true); - - result.append(stripWS(paramSig.toString())); - } - - result.append(')'); - - // Whitespace around operators is not needed, remove it to normalize the signature. - return result.toString(); - } - - public static Collection getDecodedQtMethodSignatures(String qtEncSignatures) { - if (qtEncSignatures == null) - return null; - - StringBuilder signature = new StringBuilder(); - int i = qtEncSignatures.indexOf('('); - String name = qtEncSignatures.substring(0, i); - - signature.append(name); - signature.append('('); - - boolean first = true; - List signatures = new ArrayList(); - qtEncSignatures = qtEncSignatures.substring(i + 1); - Pattern p = Pattern.compile("^([a-zA-Z0-9+/=]*)(@?).*$"); - while(!qtEncSignatures.isEmpty()) { - Matcher m = p.matcher(qtEncSignatures); - if (!m.matches()) - break; - - int next = m.end(2) + 1; - qtEncSignatures = qtEncSignatures.substring(next); - - String param = new String(DatatypeConverter.parseBase64Binary(m.group(1))); - - // If this parameter has a default value, then add a signature for the method up - // to this point. - if (!m.group(2).isEmpty()) - signatures.add(signature.toString() + ')'); - - if (first) - first = false; - else - signature.append(','); - signature.append(param); - } - - signature.append(')'); - signatures.add(signature.toString()); - return signatures; - } - - /** - * The Qt implementation has specific rules for generating a signature that is used - * to map between invokable function declarations and their use. This function has - * been implemented by comparing the output of moc to the various test cases in the - * Qt test suite. - */ - public static String getEncodedQtMethodSignatures(ICPPASTFunctionDeclarator function) { - StringBuilder result = new StringBuilder(); - - String fnName = function.getName().getLastName().toString(); - result.append(stripWS(fnName)); - result.append('('); - - boolean first = true; - for(ICPPASTParameterDeclaration param : function.getParameters()) { - if (first) - first = false; - else - result.append(','); - - IASTDeclSpecifier spec = param.getDeclSpecifier(); - ICPPASTDeclarator declarator = param.getDeclarator(); - - // The parameters are encoded so that we can rely on , being used to separate - // parameters. All other commas (e.g., to separate template arguments within - // the parameter type) will be encoded. - StringBuilder paramSig = new StringBuilder(); - append(paramSig, spec, declarator, true); - - String paramStr = stripWS(paramSig.toString()); - result.append(DatatypeConverter.printBase64Binary(paramStr.getBytes())); - - // A special character is used as a suffix on parameters that have a default value. - // A previous version of this implementation used '=' within the Base64 encoded - // payload. Now that the initializer flag is outside of the payload, '=' is a bad - // choice because it is also a valid Base64 encoded character. - // Like all the other parts of this encoder, the @ must match the value that is used - // in the decoder. - if (declarator.getInitializer() != null) - result.append('@'); - } - - result.append(')'); - - // Whitespace around operators is not needed, remove it to normalize the signature. - return result.toString(); - } - - private static String stripWS(String str) { - return str - .trim() - .replaceAll("\\s+", " ") - .replaceAll(" ([\\*&,()<>]+)", "$1") - .replaceAll("([\\*&,()<>]+) ", "$1"); - } - - private static String asString(IASTPointerOperator ptr) { - if (ptr instanceof ICPPASTReferenceOperator) - return "&"; - if (ptr instanceof IASTPointer) { - StringBuilder str = new StringBuilder(); - IASTPointer astPtr = (IASTPointer) ptr; - str.append('*'); - if (astPtr.isConst()) - str.append(" const"); - if (astPtr.isVolatile()) - str.append(" volatile"); - return str.toString(); - } - - return ptr.toString(); - } - - private static void append(StringBuilder result, IASTDeclSpecifier spec, IASTDeclarator declarator, boolean pruneConst) { - IASTPointerOperator[] ptrs = declarator.getPointerOperators(); - if (ptrs == null) - ptrs = new IASTPointerOperator[0]; - - if (!(spec instanceof ICPPASTDeclSpecifier)) { - result.append(spec.toString()); - return; - } - - ICPPASTDeclSpecifier cppSpec = (ICPPASTDeclSpecifier) spec; - - // Qt considers the type const if it is marked as const, or if it is a reference - // and the previous pointer is const. I.e., we need this: - // const T& -> T - // const T* const & -> T* - boolean isConst = cppSpec.isConst(); - boolean stripLastPtrConst - = pruneConst - && !isConst - && (ptrs.length >= 2 - && ptrs[ptrs.length - 1] instanceof ICPPASTReferenceOperator - && ptrs[ptrs.length - 2] instanceof IASTPointer - && ((IASTPointer) ptrs[ptrs.length - 2]).isConst()); - - if (isConst || stripLastPtrConst) { - if (!pruneConst) - result.append("const "); - else { - // Qt signature generation converts const value and const reference types - // into simple value types. E.g., - // const T => T - // const T & => T - // From observation, they also convert const pointer to const to const - // pointers although I think that is a bug, because simple pointer to - // const are not converted to simple pointers. E.g., - // const T * => const T * - // const T * const => T * const - if (ptrs.length > 0) { - IASTPointerOperator lastPtr = ptrs[ptrs.length - 1]; - if (lastPtr instanceof ICPPASTReferenceOperator) - ptrs = Arrays.copyOf(ptrs, ptrs.length - 1); - else if (!(lastPtr instanceof IASTPointer) - || !((IASTPointer) lastPtr).isConst()) - result.append("const "); - } - } - } - - // Qt does no special handling for volatile. This is likely an oversight. - if (cppSpec.isVolatile()) - result.append("volatile "); - - IASTNode[] children = cppSpec.getChildren(); - if (children == null || children.length <= 0) { - // We use the raw signature to get the text that was used to reference the - // type (without following typedefs, etc.), and then strip out all const - // which has already been handled. - String raw = cppSpec.toString(); - raw = raw.replaceAll("const\\s", ""); - raw = raw.replaceAll("\\sconst", ""); - result.append(raw); - } else { - for(IASTNode child : children) { - result.append( ' ' ); - if (child instanceof ICPPASTTemplateId) { - ICPPASTTemplateId templId = (ICPPASTTemplateId) child; - result.append(templId.getTemplateName()); - result.append('<'); - for(IASTNode templArg : templId.getTemplateArguments()) { - append(result, templArg); - } - result.append('>'); - } else - result.append(child.toString()); - } - } - - // exclude param name, use '=' to indicate an initial value - for(int i = 0; i < ptrs.length; ++i) { - if (!stripLastPtrConst - || i < ptrs.length - 1) - result.append(asString(ptrs[i])); - else - result.append(asString(ptrs[i]).replaceAll("const", "")); - } - } - - private static void append(StringBuilder result, IASTNode node) { - - // JI476551: When the code is parsed without full context, e.g., when parsing a Qt method ref, an - // ambiguous node could be created. Since we only need the original text, we can use - // any of the nodes that triggered the ambiguity. Arbitrarily choose the first one. - if (node instanceof ASTAmbiguousNode) { - IASTNode[] nodes = ((ASTAmbiguousNode) node).getNodes(); - if (nodes != null - && nodes.length > 0) { - append(result, nodes[0]); - return; - } - } - - if (node instanceof ICPPASTTypeId) { - ICPPASTTypeId typeId = (ICPPASTTypeId) node; - IASTDeclSpecifier spec = typeId.getDeclSpecifier(); - IASTDeclarator declarator = typeId.getAbstractDeclarator(); - append(result, spec, declarator, false); - return; - } - - if (!(node instanceof ICPPASTTemplateId)) { - result.append(node.toString()); - return; - } - - ICPPASTTemplateId templId = (ICPPASTTemplateId) node; - result.append(templId.getTemplateName()); - result.append('<'); - boolean first = true; - for (IASTNode child : templId.getTemplateArguments()) { - if (first) - first = false; - else - result.append(", "); - append(result, child); - } - result.append('>'); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/AbstractQField.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/AbstractQField.java deleted file mode 100644 index 90c97e0bd12..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/AbstractQField.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import org.eclipse.cdt.qt.core.index.IQObject; -import org.eclipse.cdt.qt.core.index.IQObject.IMember; - -public abstract class AbstractQField implements IQObject.IMember { - - private final IQObject owner; - protected String name; - - protected AbstractQField(IQObject owner) { - this.owner = owner; - } - - @Override - public IQObject getOwner() { - return owner; - } - - @Override - public boolean isOverride(IMember member) { - if (!AbstractQField.class.isAssignableFrom(member.getClass())) - return false; - - // I haven't been able to find Qt documentation describing how things like - // Q_PROPERY are overridden, but the docs suggest it is just by name. - - AbstractQField other = (AbstractQField) member; - return name == null ? other.name == null : name.equals(other.name); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/CDTIndex.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/CDTIndex.java deleted file mode 100644 index c187dea5881..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/CDTIndex.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import org.eclipse.cdt.core.index.IIndex; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.core.runtime.CoreException; - -/** - * A wrapper around the CDT index that manages the read lock. - */ -public class CDTIndex { - - private final IIndex index; - - public CDTIndex(IIndex index) { - this.index = index; - } - - /** - * An object used for reading from the CDT index. The {@link #access(IIndex)} method - * will only be invoked when the index's read lock has been properly acquired. - */ - public static interface Accessor { - /** - * A method that performs the lookup within the CDT index. The read-lock will - * be acquired before invoking this method. - *

- * The implementation of access must not make calls to {@link CDTIndex#get(Accessor)}. - * If other objects are needed, then have the accessor return a qualified name and - * lookup the object after the implementation of #access completes. - */ - public T access(IIndex index) throws CoreException; - } - - /** - * Use the given accessor to find and return a value from the index. This method ensures - * that the read-lock has been acquired. - */ - public T get(Accessor accessor) { - try { - index.acquireReadLock(); - } catch(InterruptedException e) { - return null; - } - - try { - return accessor.access(index); - } catch(CoreException e) { - QtPlugin.log( e ); - } finally { - index.releaseReadLock(); - } - - return null; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QEnum.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QEnum.java deleted file mode 100644 index 0610f6101f8..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QEnum.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.cdt.core.dom.ast.IEnumerator; -import org.eclipse.cdt.core.dom.ast.IValue; -import org.eclipse.cdt.qt.core.index.IQEnum; - -public class QEnum implements IQEnum { - - private final String name; - private final boolean isFlag; - private final List enumerators; - - public QEnum(String name, boolean isFlag, List enumerators) { - this.name = name; - this.isFlag = isFlag; - this.enumerators = new ArrayList(enumerators.size()); - for (IEnumerator enumerator : enumerators) - this.enumerators.add(new Enumerator(enumerator)); - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean isFlag() { - return isFlag; - } - - @Override - public Collection getEnumerators() { - return enumerators; - } - - private static class Enumerator implements IQEnum.Enumerator { - - private final String name; - private final Long ordinal; - - public Enumerator(IEnumerator enumerator) { - this.name = enumerator.getName(); - - IValue val = enumerator.getValue(); - this.ordinal = val == null ? null : val.numericalValue(); - } - - @Override - public String getName() { - return name; - } - - @Override - public Long getOrdinal() { - return ordinal; - } - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QMethod.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QMethod.java deleted file mode 100644 index 8c5bc7574aa..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QMethod.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import java.util.Collection; -import java.util.Collections; - -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.qt.core.index.IQMethod; -import org.eclipse.cdt.qt.core.index.IQObject; -import org.eclipse.cdt.qt.core.index.IQObject.IMember; -import org.eclipse.cdt.qt.internal.core.QtMethodUtil; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQMethod; -import org.eclipse.core.runtime.CoreException; - -public class QMethod implements IQMethod { - - private final IQObject owner; - private final String name; - private final IQMethod.Kind kind; - private final Collection signatures; - private final Long revision; - - public QMethod(IQObject owner, QtPDOMQMethod pdom) throws CoreException { - this.owner = owner; - this.name = pdom.getName(); - this.kind = pdom.getKind(); - this.signatures = QtMethodUtil.getDecodedQtMethodSignatures(pdom.getQtEncodedSignatures()); - this.revision = pdom.getRevision(); - } - - @Override - public boolean isOverride(IMember member) { - if (!IQMethod.class.isAssignableFrom(member.getClass())) - return false; - - // Methods override when they have the same name and type. - - IQMethod other = (IQMethod) member; - - if (name == null) { - if (other.getName() != null) - return false; - } else if (!name.equals(other.getName())) - return false; - - IBinding otherBinding = other.getBinding(); - if (otherBinding == null) - return getBinding() == null; - - return false ;// TODO -// if (!ICPPMethod.class.isAssignableFrom(otherBinding.getClass())) -// return false; -// -// IType thisType = method.getType(); -// IType otherType = ((ICPPMethod) otherBinding).getType(); -// return thisType == null ? otherType == null : thisType.isSameType(otherType); - } - - @Override - public IBinding getBinding() { - return null; // TODO method; - } - - @Override - public IQObject getOwner() { - return owner; - } - - @Override - public Kind getKind() { - return kind; - } - - @Override - public String getName() { - return name; - } - - @Override - public Collection getSignatures() { - return signatures == null ? Collections.emptyList() : signatures; - } - - @Override - public Long getRevision() { - return revision; - } - - @Override - public String toString() { - return kind.toString() + ' ' + signatures; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObject.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObject.java deleted file mode 100644 index 0f5b83d3faf..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObject.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.qt.core.index.IQEnum; -import org.eclipse.cdt.qt.core.index.IQMethod; -import org.eclipse.cdt.qt.core.index.IQObject; -import org.eclipse.cdt.qt.core.index.IQProperty; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMProperty; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQEnum; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQMethod; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQObject; -import org.eclipse.core.runtime.CoreException; - -public class QObject implements IQObject { - - private final String name; - private final QtPDOMQObject pdomQObject; - private final List bases; - private final IQObject.IMembers slots; - private final IQObject.IMembers signals; - private final IQObject.IMembers invokables; - private final IQObject.IMembers properties; - private final List enums; - private final Map classInfos; - - public QObject(QtIndexImpl qtIndex, CDTIndex cdtIndex, QtPDOMQObject pdomQObject) throws CoreException { - this.name = pdomQObject.getName(); - this.pdomQObject = pdomQObject; - - List baseSlots = new ArrayList(); - List baseSignals = new ArrayList(); - List baseInvokables = new ArrayList(); - List baseProps = new ArrayList(); - - this.bases = new ArrayList(); - for(QtPDOMQObject base : pdomQObject.findBases()) { - QObject baseQObj = new QObject(qtIndex, cdtIndex, base); - this.bases.add(baseQObj); - baseProps.addAll(baseQObj.getProperties().all()); - } - - this.classInfos = pdomQObject.getClassInfos(); - - List slots = new ArrayList(); - List signals = new ArrayList(); - List invokables = new ArrayList(); - for(QtPDOMQMethod pdom : pdomQObject.getChildren(QtPDOMQMethod.class)) - switch(pdom.getKind()) { - case Slot: - slots.add(new QMethod(this, pdom)); - break; - case Signal: - signals.add(new QMethod(this, pdom)); - break; - case Invokable: - invokables.add(new QMethod(this, pdom)); - break; - case Unspecified: - break; - } - - this.slots = QObjectMembers.create(slots, baseSlots); - this.signals = QObjectMembers.create(signals, baseSignals); - this.invokables = QObjectMembers.create(invokables, baseInvokables); - - this.enums = new ArrayList(); - for(QtPDOMQEnum pdom : pdomQObject.getChildren(QtPDOMQEnum.class)) - this.enums.add(new QEnum(pdom.getName(), pdom.isFlag(), pdom.getEnumerators())); - - List props = new ArrayList(); - for(QtPDOMProperty pdom : pdomQObject.getChildren(QtPDOMProperty.class)) { - QProperty qProp = new QProperty(this, pdom.getType(), pdom.getName()); - for(QtPDOMProperty.Attribute attr : pdom.getAttributes()) - qProp.setAttribute(attr.attr, attr.value); - props.add(qProp); - } - this.properties = QObjectMembers.create(props, baseProps); - } - - @Override - public IBinding getBinding() { - return pdomQObject; - } - - @Override - public String getName() { - return name; - } - - @Override - public List getBases() { - return bases; - } - - @Override - public IMembers getSlots() { - return slots; - } - - @Override - public IMembers getSignals() { - return signals; - } - - @Override - public IMembers getInvokables() { - return invokables; - } - - @Override - public IQObject.IMembers getProperties() { - return properties; - } - - @Override - public String getClassInfo(String key) { - String value = classInfos.get(key); - if (value != null) - return value; - - for(IQObject base : bases) { - value = base.getClassInfo(key); - if (value != null) - return value; - } - - return null; - } - - @Override - public Collection getEnums() { - return enums; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObjectMembers.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObjectMembers.java deleted file mode 100644 index 73116d92b2b..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QObjectMembers.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.cdt.qt.core.index.IQObject; - -public class QObjectMembers implements IQObject.IMembers { - - private final List all; - private final Collection locals; - private Collection withoutOverrides; - - public static QObjectMembers create(Collection locals, Collection inherited) { - // NOTE: All must be ordered with the locals before the inherited members. This ensures that - // the algorithm for computing #withoutOverrides will filter out the parent members and - // not the local ones. - // @see withoutOverrides() - ArrayList all = new ArrayList(locals.size() + inherited.size()); - all.addAll(locals); - all.addAll(inherited); - return new QObjectMembers(all, locals); - } - - private QObjectMembers(List all, Collection locals) { - this.all = Collections.unmodifiableList(all); - this.locals = Collections.unmodifiableCollection(locals); - } - - @Override - public Collection all() { - return all; - } - - @Override - public Collection locals() { - return locals; - } - - @Override - public Collection withoutOverrides() { - - if (withoutOverrides == null) - synchronized (all) { - if (withoutOverrides == null) { - - // Naively tests each existing element for override before inserting the new - // element. Most member lists have less than 3 elements, and the largest that - // I've found (in the Qt impl) is about 20; so performance may not be as bad - // as it seems. - // - // An earlier approach tried to use a SortedSet with the #isOverride result in - // the Comparator. The problem with the approach is finding a stable sort order - // when the members don't override each other. - // E.g., if o1 and o2 override each other and m is unrelated, we could get a - // tree like: - // m - // / \ - // o1 o2 - - ArrayList filtered = new ArrayList(all.size()); - for(T member : all) { - boolean isOverridden = false; - for(Iterator i = filtered.iterator(); !isOverridden && i.hasNext(); ) - isOverridden = member.isOverride(i.next()); - if (!isOverridden) - filtered.add(member); - } - - withoutOverrides = Collections.unmodifiableCollection(filtered); - } - } - - return withoutOverrides; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QProperty.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QProperty.java deleted file mode 100644 index f8e2f957718..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QProperty.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import org.eclipse.cdt.qt.core.index.IQObject; -import org.eclipse.cdt.qt.core.index.IQProperty; - -public class QProperty extends AbstractQField implements IQProperty { - - private String type; - private final String[] values = new String[Attribute.values().length]; - - public QProperty(IQObject owner, String type, String name) { - super(owner); - this.type = type; - this.name = name; - } - - public void setAttribute(IQProperty.Attribute attr, String value) { - values[attr.ordinal()] = ( value == null ? "" : value ); - } - - @Override - public String getType() { - return type; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getValue(Attribute attr) { - return values[attr.ordinal()]; - } - - @Override - public String getReadMethodName() { - return Attribute.READ.valueIn(this); - } - - @Override - public String getWriteMethodName() { - return Attribute.WRITE.valueIn(this); - } - - @Override - public String getResetMethodName() { - return Attribute.RESET.valueIn(this); - } - - @Override - public String getNotifyMethodName() { - return Attribute.NOTIFY.valueIn(this); - } - - @Override - public Long getRevision() { - String revision = Attribute.REVISION.valueIn(this); - if (revision != null) - try { - return Long.valueOf(revision); - } catch(NumberFormatException e) { - // This is a problem with the user's C++ code, there is no need to log this exception, - // just ignore the value. - } - - return null; - } - - @Override - public String getDesignable() { - return Attribute.DESIGNABLE.valueIn(this); - } - - @Override - public String getScriptable() { - return Attribute.SCRIPTABLE.valueIn(this); - } - - @Override - public String getStored() { - return Attribute.STORED.valueIn(this); - } - - @Override - public String getUser() { - return Attribute.USER.valueIn(this); - } - - @Override - public boolean isConstant() { - return Attribute.CONSTANT.valueIn(this) != null; - } - - @Override - public boolean isFinal() { - return Attribute.FINAL.valueIn(this) != null; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtFactory.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtFactory.java deleted file mode 100644 index 7d95d6e1515..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtFactory.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.index.IIndex; -import org.eclipse.cdt.core.index.IIndexMacro; -import org.eclipse.cdt.core.index.IndexFilter; -import org.eclipse.cdt.core.model.CoreModel; -import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.cdt.qt.core.index.QtIndex; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; - -public class QtFactory { - - private static final char[] QT_VERSION = "QT_VERSION".toCharArray(); - - public static QtIndex create(IProject project) { - CDTIndex cdtIndex = getCDTIndex(project); - if (cdtIndex == null) { - QtPlugin.log("could not get CDT index from project " + project.getName()); - return null; - } - - QtVersion qtVersion = cdtIndex.get(QtVersionAccessor); - if (qtVersion == null) { - QtPlugin.log("could not find Qt version in CDT index from project " + project.getName()); - return null; - } - - if (qtVersion.major == 4 && qtVersion.minor == 8) - return new QtIndexImpl(cdtIndex); - - // Qt 4.8 is the default implementation, 5.0 support will need to come soon - return new QtIndexImpl(cdtIndex); - } - - private static CDTIndex getCDTIndex(IProject project) { - if (project == null) - return null; - - ICProject cProject = CoreModel.getDefault().create(project); - if (cProject == null) - return null; - - IIndex index = null; - try { - index = CCorePlugin.getIndexManager().getIndex(cProject); - } catch( CoreException e ) { - QtPlugin.log(e); - return null; - } - - return index == null ? null : new CDTIndex(index); - } - - /** - * A small wrapper to hold the result of index lookups for the Qt version. - */ - private static class QtVersion { - public final int major; - public final int minor; - @SuppressWarnings("unused") - public final int patch; - - // QT_VERSION looks like 0x040805 - private static final Pattern Version_regex = Pattern.compile( "0x([a-fA-F\\d]{1,2})([a-fA-F\\d]{2})([a-fA-F\\d]{2})" ); - - public static QtVersion create(String version) { - Matcher m = Version_regex.matcher(version); - if (!m.matches()) - return null; - - try { - int major = Integer.parseInt(m.group(1), 16); - int minor = Integer.parseInt(m.group(2), 16); - int patch = Integer.parseInt(m.group(3), 16); - return new QtVersion(major, minor, patch); - } catch(NumberFormatException e) { - QtPlugin.log(e); - } - return null; - } - - private QtVersion(int major, int minor, int patch) { - this.major = major; - this.minor = minor; - this.patch = patch; - } - } - - private static final CDTIndex.Accessor QtVersionAccessor = new CDTIndex.Accessor() { - @Override - public QtVersion access(IIndex index) throws CoreException { - // Multiple macros might be found, sort the values and choose the highest version. - SortedSet versions = new TreeSet(); - try { - for(IIndexMacro macro : index.findMacros(QT_VERSION, IndexFilter.ALL, null)) - versions.add(new String(macro.getExpansion()).toLowerCase()); - } catch( CoreException e ) { } - - // don't create the Qt index if there is no Qt information in the CDT index - if (versions.size() <= 0) - return null; - - // the highest version has been sorted to the last position - return QtVersion.create(versions.last()); - } - }; -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtIndexImpl.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtIndexImpl.java deleted file mode 100644 index d127c133a8e..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/index/QtIndexImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.index; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.index.IIndex; -import org.eclipse.cdt.core.index.IIndexBinding; -import org.eclipse.cdt.core.index.IndexFilter; -import org.eclipse.cdt.qt.core.index.IQObject; -import org.eclipse.cdt.qt.core.index.QtIndex; -import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQObject; -import org.eclipse.core.runtime.CoreException; - -public class QtIndexImpl extends QtIndex { - - private final CDTIndex cdtIndex; - - private static final IndexFilter QtLinkageFilter = new IndexFilter() { - @Override - public boolean acceptLinkage(ILinkage linkage) { - return linkage.getLinkageID() == ILinkage.QT_LINKAGE_ID; - } - - @Override - public boolean acceptBinding(IBinding binding) throws CoreException { - return true; - } - }; - - public QtIndexImpl(CDTIndex cdtIndex) { - this.cdtIndex = cdtIndex; - } - - @Override - public IQObject findQObject(String[] name) { - return name == null ? null : cdtIndex.get(new QObjectImplAccessor(name)); - } - - private class QObjectImplAccessor implements CDTIndex.Accessor { - - private final char[][] name; - - public QObjectImplAccessor(String[] qualName) { - name = new char[qualName.length][]; - for(int i = 0; i < name.length; ++i) - name[i] = qualName[i].toCharArray(); - } - - @Override - public IQObject access(IIndex index) throws CoreException { - - // TODO can there be more than one result? - for(IIndexBinding binding : index.findBindings(name, QtLinkageFilter, null)) - if (binding instanceof QtPDOMQObject) - return new QObject(QtIndexImpl.this, cdtIndex, (QtPDOMQObject) binding); - - return null; - } - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTDelegatedName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTDelegatedName.java deleted file mode 100644 index 81b66da9fb6..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTDelegatedName.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; -import org.eclipse.cdt.core.dom.ast.ASTVisitor; -import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; -import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTImageLocation; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; -import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.parser.IToken; - -/** - * The Qt linkage introduces several names that are based on names from the C++ linkage. This - * utility class is used to delegate operations to that base C++ name. Methods can be overridden - * by implementing in a subclass. - * - * @see QObjectName - */ -public abstract class ASTDelegatedName implements IASTName { - - protected final IASTName delegate; - - protected IBinding binding; - - protected ASTDelegatedName(IASTName delegate) { - this.delegate = delegate; - } - - @Override - public IASTTranslationUnit getTranslationUnit() { - return delegate.getTranslationUnit(); - } - - @Override - public IASTNodeLocation[] getNodeLocations() { - return delegate.getNodeLocations(); - } - - @Override - public IASTFileLocation getFileLocation() { - return delegate.getFileLocation(); - } - - @Override - public String getContainingFilename() { - return delegate.getContainingFilename(); - } - - @Override - public boolean isPartOfTranslationUnitFile() { - return delegate.isPartOfTranslationUnitFile(); - } - - @Override - public IASTNode getParent() { - return delegate.getParent(); - } - - @Override - public IASTNode[] getChildren() { - return delegate.getChildren(); - } - - @Override - public void setParent(IASTNode node) { - delegate.setParent(node); - } - - @Override - public ASTNodeProperty getPropertyInParent() { - return delegate.getPropertyInParent(); - } - - @Override - public void setPropertyInParent(ASTNodeProperty property) { - delegate.setPropertyInParent(property); - } - - @Override - public boolean accept(ASTVisitor visitor) { - return delegate.accept(visitor); - } - - @Override - public String getRawSignature() { - return delegate.getRawSignature(); - } - - @Override - public boolean contains(IASTNode node) { - return delegate.contains(node); - } - - @Override - public IToken getLeadingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException { - return delegate.getLeadingSyntax(); - } - - @Override - public IToken getTrailingSyntax() throws ExpansionOverlapsBoundaryException, UnsupportedOperationException { - return delegate.getTrailingSyntax(); - } - - @Override - public IToken getSyntax() throws ExpansionOverlapsBoundaryException { - return delegate.getSyntax(); - } - - @Override - public boolean isFrozen() { - return delegate.isFrozen(); - } - - @Override - public boolean isActive() { - return delegate.isActive(); - } - - @Override - public IASTNode getOriginalNode() { - return delegate.getOriginalNode(); - } - - @Override - public char[] getSimpleID() { - return delegate.getSimpleID(); - } - - @Override - public boolean isDeclaration() { - return delegate.isDeclaration(); - } - - @Override - public boolean isReference() { - return delegate.isReference(); - } - - @Override - public boolean isDefinition() { - return delegate.isDefinition(); - } - - @Override - public char[] toCharArray() { - return delegate.toCharArray(); - } - - @Override - public IBinding getBinding() { - return null; - } - - @Override - public IBinding resolveBinding() { - return null; - } - - @Override - public int getRoleOfName(boolean allowResolution) { - return delegate.getRoleOfName(allowResolution); - } - - @Override - public IASTCompletionContext getCompletionContext() { - return delegate.getCompletionContext(); - } - - @Override - public ILinkage getLinkage() { - return delegate.getLinkage(); - } - - @Override - public IASTImageLocation getImageLocation() { - return delegate.getImageLocation(); - } - - @Override - public IASTName getLastName() { - return delegate.getLastName(); - } - - @Override - public IASTName copy() { - return delegate.copy(); - } - - @Override - public IASTName copy(CopyStyle style) { - return delegate.copy(style); - } - - @Override - public void setBinding(IBinding binding) { - this.binding = binding; - } - - @Override - public char[] getLookupKey() { - return delegate.getLookupKey(); - } - - @Override - public IBinding getPreBinding() { - return binding; - } - - @Override - public IBinding resolvePreBinding() { - return resolveBinding(); - } - - @Override - public boolean isQualified() { - return delegate.isQualified(); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTNameReference.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTNameReference.java deleted file mode 100644 index 3ab9467d43f..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/ASTNameReference.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNameOwner; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.index.IIndexName; -import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; -import org.eclipse.cdt.internal.core.index.IIndexFragmentName; -import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; -import org.eclipse.core.runtime.CoreException; - -/** - * Some Qt elements are introduced with empty macro expansions. The Qt linkage handles this - * by creating a new name and then adding it as a reference to the C++ language element. - * This utility helps by containing that C++ name and the location of the Qt name. - */ -@SuppressWarnings("restriction") -public class ASTNameReference extends ASTDelegatedName { - - private final IASTFileLocation location; - - /** - * Create and return a name that will reference the given name. - */ - public ASTNameReference(IASTName name) { - super(name); - this.location = name.getFileLocation(); - } - - /** - * Create and return a name that will reference the given name from the given location. - */ - public ASTNameReference(IASTName name, IASTFileLocation location) { - super(name); - this.location = location; - } - - /** - * Find and return the Qt binding that annotates the given PDOMBinding. E.g., if the input binding - * is an instance of PDOMCPPClassType, then this method will return the QtPDOMQObject that was created - * from that class (or null if there is no such Qt element). - *

- * This is implemented by creating an ASTNameReference within the Qt element binding's definition. That - * name is added as reference from the C++ PDOM binding. - */ - public static T findFromBinding(Class cls, PDOMBinding binding) throws CoreException { - if (binding == null) - return null; - - // Look for external references to the binding. - IPDOMIterator pdomIterator = binding.getExternalReferences(); - while(pdomIterator.hasNext()) { - PDOMName extRef = pdomIterator.next(); - IIndexName caller = extRef.getEnclosingDefinition(); - if (caller instanceof IIndexFragmentName) { - IIndexFragmentBinding extRefBinding = ((IIndexFragmentName) caller).getBinding(); - if (cls.isAssignableFrom(extRefBinding.getClass())) - return cls.cast(extRefBinding); - } - } - - return null; - } - - @Override - public IBinding resolveBinding() { - return delegate.resolveBinding(); - } - - @Override - public IBinding getBinding() { - return delegate.getBinding(); - } - - @Override - public IASTFileLocation getFileLocation() { - return location; - } - - @Override - public boolean isReference() { - return true; - } - - @Override - public boolean isDefinition() { - return false; - } - - @Override - public boolean isDeclaration() { - return false; - } - - @Override - public int getRoleOfName(boolean allowResolution) { - return IASTNameOwner.r_reference; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/AbstractQObjectMemberName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/AbstractQObjectMemberName.java deleted file mode 100644 index 94eff5904e7..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/AbstractQObjectMemberName.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTImageLocation; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNameOwner; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.internal.core.dom.Linkage; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public abstract class AbstractQObjectMemberName extends ASTDelegatedName { - - private final QObjectName owner; - private final String name; - private final IASTImageLocation location; - private ASTNodeProperty propertyInParent; - - protected AbstractQObjectMemberName(QObjectName owner, IASTName ast, String name, IASTImageLocation location) { - super(ast); - this.owner = owner; - this.name = name; - this.location = location; - } - - protected PDOMBinding getOwner(QtPDOMLinkage linkage) throws CoreException { - return linkage.getBinding(owner); - } - - public String getFieldName() { - return name; - } - - @Override - public IASTFileLocation getFileLocation() { - return location; - } - - @Override - public IASTNode getParent() { - return owner; - } - - @Override - public IASTNode[] getChildren() { - return IASTNode.EMPTY_NODE_ARRAY; - } - - @Override - public void setParent(IASTNode node) { - throw new IllegalStateException("attempt to modify parent of QObject field"); //$NON-NLS-1$ - } - - @Override - public ASTNodeProperty getPropertyInParent() { - return propertyInParent; - } - - @Override - public void setPropertyInParent(ASTNodeProperty property) { - propertyInParent = property; - } - - @Override - public char[] getSimpleID() { - return name.toCharArray(); - } - - @Override - public String getRawSignature() { - return name; - } - - @Override - public boolean isDeclaration() { - return false; - } - - @Override - public boolean isReference() { - return false; - } - - @Override - public boolean isDefinition() { - return true; - } - - @Override - public int getRoleOfName(boolean allowResolution) { - return IASTNameOwner.r_definition; - } - - @Override - public ILinkage getLinkage() { - return Linkage.QT_LINKAGE; - } - - @Override - public IASTImageLocation getImageLocation() { - return location; - } - - @Override - public IASTName copy() { - return copy(CopyStyle.withoutLocations); - } - - @Override - public IASTName copy(CopyStyle style) { - throw new UnsupportedOperationException("attempt to copy QObject field"); //$NON-NLS-1$ - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtASTName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtASTName.java deleted file mode 100644 index aead1422f2a..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtASTName.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.core.runtime.CoreException; - -public interface IQtASTName extends IASTName { - /** - * Create and return a new instance of PDOMBinding for the receiver. The implementation - * is allowed to return null if there is no possibility of creating a PDOMBinding. - * The value that is returned must be consistent -- if null is returned one time then - * it must be returned every time. - */ - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException; -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtPDOMCodec.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtPDOMCodec.java deleted file mode 100644 index 040f2a850d4..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/IQtPDOMCodec.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.core.runtime.CoreException; - -/** - * A utility interface for encoding and decoding fixed-sized elements to and - * from the Database. - */ -public interface IQtPDOMCodec { - /** - * Return the number of bytes needed to store a single element. - */ - public int getElementSize(); - - /** - * Allocate and return a new array to hold the specified number of elements. - */ - public T[] allocArray(int count); - - /** - * Examine the database at the specified record to decode an element instance. - */ - public T decode(QtPDOMLinkage linkage, long record) throws CoreException; - - /** - * Encode the given element into the database at the specified record. The codec is - * responsible for releasing storage that is about to be overwritten (if needed). - * The element will be null when the implementation should delete all memory used - * for storage at record. - */ - public void encode(QtPDOMLinkage linkage, long record, T element) throws CoreException; -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/PDOMQtLinkageFactory.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/PDOMQtLinkageFactory.java deleted file mode 100644 index e2b2c190ae9..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/PDOMQtLinkageFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.internal.core.pdom.PDOM; -import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class PDOMQtLinkageFactory implements IPDOMLinkageFactory { - - @Override - public PDOMLinkage getLinkage(PDOM pdom, long record) { - try { - return new QtPDOMLinkage(pdom, record); - } catch(CoreException e) { - QtPlugin.log(e); - } - return null; - } - - @Override - public PDOMLinkage createLinkage(PDOM pdom) throws CoreException { - return new QtPDOMLinkage(pdom); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QMethodName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QMethodName.java deleted file mode 100644 index 59c08673d6b..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QMethodName.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.qt.core.index.IQMethod; -import org.eclipse.core.runtime.CoreException; - -public class QMethodName extends AbstractQObjectMemberName implements IQtASTName { - - private final IQMethod.Kind kind; - private final String qtEncSignatures; - private final Long revision; - - public QMethodName(QObjectName qobjName, IASTName cppName, IQMethod.Kind kind, String qtEncSignatures, Long revision) { - super(qobjName, cppName, cppName.getLastName().toString(), cppName.getImageLocation()); - this.kind = kind; - this.qtEncSignatures = qtEncSignatures; - this.revision = revision; - } - - @Override - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { - return new QtPDOMQMethod(linkage, getOwner(linkage), this, delegate, kind, qtEncSignatures, revision); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QObjectName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QObjectName.java deleted file mode 100644 index d84e11b2338..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QObjectName.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; -import org.eclipse.cdt.core.dom.ast.ASTVisitor; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; -import org.eclipse.cdt.internal.core.dom.Linkage; -import org.eclipse.core.runtime.CoreException; - -/** - * QObjects are C++ classes that have been annotated with Qt marker macros. This class is - * used to introduce the QObject to the Qt linkage. - */ -@SuppressWarnings("restriction") -public class QObjectName extends ASTDelegatedName implements IQtASTName { - - private final ICPPASTCompositeTypeSpecifier spec; - private final List properties = new ArrayList(); - private final Map classInfos = new LinkedHashMap(); - - private IASTNode parent; - private ASTNodeProperty propertyInParent; - - public QObjectName(ICPPASTCompositeTypeSpecifier spec) { - super(spec.getName()); - this.spec = spec; - this.parent = delegate.getParent(); - this.propertyInParent = delegate.getPropertyInParent(); - } - - public List getProperties() { - return properties; - } - - public void addProperty(QtPropertyName property) { - properties.add(property); - } - - public Map getClassInfos() { - return classInfos; - } - - public String addClassInfo(String key, String value) { - return classInfos.put(key, value); - } - - @Override - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { - return new QtPDOMQObject(linkage, this, spec.getName()); - } - - @Override - public IASTTranslationUnit getTranslationUnit() { - return spec.getTranslationUnit(); - } - - @Override - public IASTNode[] getChildren() { - return IASTNode.EMPTY_NODE_ARRAY; - } - - @Override - public IASTNode getParent() { - return parent; - } - - @Override - public void setParent(IASTNode node) { - parent = node; - } - - @Override - public ASTNodeProperty getPropertyInParent() { - return propertyInParent; - } - - @Override - public void setPropertyInParent(ASTNodeProperty property) { - propertyInParent = property; - } - - @Override - public boolean accept(ASTVisitor visitor) { - return false; - } - - @Override - public boolean contains(IASTNode node) { - return false; - } - - @Override - public ILinkage getLinkage() { - return Linkage.QT_LINKAGE; - } - - @Override - public IASTName copy() { - return copy(CopyStyle.withoutLocations); - } - - @Override - public IASTName copy(CopyStyle style) { - return new QObjectName(spec); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTClass.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTClass.java deleted file mode 100644 index 7f873cf29c8..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTClass.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.cdt.core.dom.ast.IASTDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; -import org.eclipse.cdt.qt.core.QtKeywords; -import org.eclipse.cdt.qt.core.index.IQMethod; - -/** - * The AST for a QObject is separated into regions based on macro expansions. These - * regions determine the Qt kind for methods that are declared within them. - *

- * This utility class makes one pass over the C++ class specification to identify - * all such regions. It also provides an iterator that can be used while examining - * the class spec's members. - */ -public class QtASTClass { - - private final Iterator regions; - private final Iterator tags; - private final Iterator revisions; - private Region region; - private Tag tag; - private Revision revision; - - /** - * Must only be called with increasing offset. Internal pointers may be advanced on - * each call. - */ - public IQMethod.Kind getKindFor(int offset) { - - // There are 3 steps: - // 1) The tags counter must always be advanced. Tags only apply to the next declaration - // and therefore the internal counter must always be advanced. Multiple tags are - // collapsed to find the highest precedence value. - // 2) The region counter is advanced to find a region that either contains the offset - // or is the first region after the offset. Regions override tags, so we use the - // region kind if one is found. - // 3) The final result is based on tags (if they were present). - // - // This precedence is based on experimentation with the moc (ver 63). It - // ignores macros tagging a single method when that method is declared within - // a signal/slot region. E.g., the following example has two signals and one slot: - // - // class Q : public QObject - // { - // Q_OBJECT - // signals: void signal1(); - // Q_SLOT void signal2(); /* Tagged with Q_SLOT, but the declaration is within the - // * signals region, so the moc considers it a signal. */ - // public: - // Q_SLOT void slot1(); - // }; - - - // Consume all tags since the last declaration to find the highest precedence tag. - IQMethod.Kind kind = IQMethod.Kind.Unspecified; - while(tag != null && tag.offset < offset) { - kind = getHigherPrecedence(kind, tag.kind); - tag = tags.hasNext() ? tags.next() : null; - } - - // Advance regions to find one that does not end before this offset. - while(region != null && region.end < offset) - region = regions.hasNext() ? regions.next() : null; - - // If the offset is within this region, then use its kind. - if (region != null && region.contains(offset)) - kind = region.kind; - - return kind; - } - - /** - * Must only be called with increasing offset. Internal pointers may be advanced on - * each call. - */ - public Long getRevisionFor(int offset) { - - // Consume all revisions since the last declaration to find one (if any) that applies - // to this declaration. - Long rev = null; - while(revision != null && revision.offset < offset) { - rev = revision.revision; - revision = revisions.hasNext() ? revisions.next() : null; - } - - return rev; - } - - private static IQMethod.Kind getHigherPrecedence(IQMethod.Kind kind1, IQMethod.Kind kind2) { - switch(kind1) { - case Unspecified: - return kind2; - case Invokable: - switch(kind2) { - case Slot: - case Signal: - return kind2; - default: - return kind1; - } - case Signal: - if (kind2 == IQMethod.Kind.Slot) - return kind2; - return kind2; - case Slot: - return kind1; - } - return IQMethod.Kind.Unspecified; - } - - public static QtASTClass create(ICPPASTCompositeTypeSpecifier spec) { - - // There is more detail in Bug 401696 describing why this needs to look at all - // the node locations. Briefly, the CDT parser does not associate empty macros - // with the function when they are the first thing in the declaration. E.g., - // - // #define X - // void func1() {} - // X void func2() {} - // - // Could also look like: - // void func1() {} X - // void func2() {} - // - // The nodes are processed in three stages which are described in detail below. Only - // the first stage looks at the nodes, the later stages just cleanup results from the - // first walk over all node locations. - - // 1) Examine the locations to find all macro expansions. This finds a beginning and - // highest possible end for the regions. It also locates the offset for single-method - // tags (including resolving precedence). - // This allows single-method tags to overlap regions because regions may be shortened - // by a later step. - ArrayList tags = new ArrayList(); - ArrayList revisions = new ArrayList(); - ArrayList regions = new ArrayList(); - Region currRegion = null; - for(IASTNodeLocation location : spec.getNodeLocations()) { - - Tag tag = Tag.create(location); - if (tag != null) - tags.add(tag); - - Revision revision = Revision.create(location); - if (revision != null) - revisions.add(revision); - - Region region = Region.create(location); - if (region != null) { - if (currRegion != null) - currRegion.end = region.begin; - - currRegion = region; - regions.add(region); - } - } - - // 2) Make the regions smaller where visibility labels are introduced. - if (!regions.isEmpty()) { - Iterator iterator = regions.iterator(); - Region region = iterator.next(); - for (IASTDeclaration decl : spec.getMembers()) { - - // Ignore everything other than visibility labels. - if (!(decl instanceof ICPPASTVisibilityLabel)) - continue; - - int offset = decl.getFileLocation().getNodeOffset(); - - // Otherwise terminate all regions that start before this label and advance - // to the first one that follows. - while(region != null && region.begin < offset) { - region.end = offset; - region = iterator.hasNext() ? iterator.next() : null; - } - - // Stop searching for visibility labels after the last region has been terminated. - if (region == null) - break; - } - } - - // 3) Eliminate tags that are within regions. - if (!tags.isEmpty()) { - Iterator iterator = tags.iterator(); - Tag tag = iterator.next(); - for(Region region : regions) { - - // Keep all tags that are before the start of this region. - while(tag != null && tag.offset < region.begin) - tag = iterator.hasNext() ? iterator.next() : null; - - // Delete all tags that are within this region. - while(tag != null && region.contains(tag.offset)) { - iterator.remove(); - tag = iterator.hasNext() ? iterator.next() : null; - } - - // Stop searching when there are no more tags to be examined. - if (tag == null) - break; - } - } - - return new QtASTClass(regions, tags, revisions); - } - - private QtASTClass(List regions, List tags, List revisions) { - this.regions = regions.iterator(); - this.tags = tags.iterator(); - this.revisions = revisions.iterator(); - - this.region = this.regions.hasNext() ? this.regions.next() : null; - this.tag = this.tags.hasNext() ? this.tags.next() : null; - this.revision = this.revisions.hasNext() ? this.revisions.next() : null; - } - - private static class Region { - public final int begin; - public int end = Integer.MAX_VALUE; - public final IQMethod.Kind kind; - - public Region(int begin, IQMethod.Kind kind) { - this.begin = begin; - this.kind = kind; - } - - public boolean contains(int offset) { - return offset >= begin - && offset < end; - } - - /** - * Return a region for the given location or null if the location does not - * introduce a region. - */ - public static Region create(IASTNodeLocation location) { - if (!(location instanceof IASTMacroExpansionLocation)) - return null; - - IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; - IASTFileLocation fileLocation = macroLocation.asFileLocation(); - if (fileLocation == null) - return null; - - int offset = fileLocation.getNodeOffset(); - IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); - String macroName = getMacroName(expansion); - if (QtKeywords.Q_SLOTS.equals(macroName) - || QtKeywords.SLOTS.equals(macroName)) - return new Region(offset, IQMethod.Kind.Slot); - if (QtKeywords.Q_SIGNALS.equals(macroName) - || QtKeywords.SIGNALS.equals(macroName)) - return new Region(offset, IQMethod.Kind.Signal); - return null; - } - } - - private static class Tag { - public final int offset; - public IQMethod.Kind kind; - - private Tag(int begin, IQMethod.Kind kind) { - this.offset = begin; - this.kind = kind; - } - - /** - * Return a tag for the given location or null if the location does not - * introduce a tag. - */ - public static Tag create(IASTNodeLocation location) { - if (!(location instanceof IASTMacroExpansionLocation)) - return null; - - IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; - IASTFileLocation fileLocation = macroLocation.asFileLocation(); - if (fileLocation == null) - return null; - - int offset = fileLocation.getNodeOffset(); - IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); - String macroName = getMacroName(expansion); - if (QtKeywords.Q_SLOT.equals(macroName)) - return new Tag(offset, IQMethod.Kind.Slot); - if (QtKeywords.Q_SIGNAL.equals(macroName)) - return new Tag(offset, IQMethod.Kind.Signal); - if (QtKeywords.Q_INVOKABLE.equals(macroName)) - return new Tag(offset, IQMethod.Kind.Invokable); - return null; - } - } - - private static class Revision { - private final int offset; - private final Long revision; - - // This regular expression matches Q_REVISION macro expansions. It allows C++ integer - // literals as the expansion parameter. The integer literal is provided in capture - // group 1. Hexadecimal and octal prefixes are included in the capture group. Unsigned - // and long suffixes are allowed but are excluded from the capture group. The matcher's - // input string should be trimmed and have all newlines replaced. - private static final Pattern QREVISION_REGEX = Pattern.compile("^Q_REVISION\\s*\\(\\s*((?:0x)?[\\da-fA-F]+)[ulUL]*\\s*\\)$"); - - public Revision(int offset, Long revision) { - this.offset = offset; - this.revision = revision; - } - - /** - * Return a tag for the given location or null if the location does not - * introduce a tag. - */ - public static Revision create(IASTNodeLocation location) { - if (!(location instanceof IASTMacroExpansionLocation)) - return null; - - IASTMacroExpansionLocation macroLocation = (IASTMacroExpansionLocation) location; - IASTFileLocation fileLocation = macroLocation.asFileLocation(); - if (fileLocation == null) - return null; - - int offset = fileLocation.getNodeOffset(); - IASTPreprocessorMacroExpansion expansion = macroLocation.getExpansion(); - String macroName = getMacroName(expansion); - if (!QtKeywords.Q_REVISION.equals(macroName)) - return null; - - String raw = expansion.getRawSignature(); - if (raw == null) - return null; - - // Trim leading and trailing whitespace and remove all newlines. - Matcher m = QREVISION_REGEX.matcher(raw.trim().replaceAll("\\s+", "")); - if (m.matches()) { - try { - return new Revision(offset, Long.parseLong(m.group(1))); - } catch(NumberFormatException e) { - // The number will be parsed incorrectly when the C++ client code does not - // contain a valid integer. We can't do anything about that, so the exception - // is ignored. A codan checker could notify the user of this problem. - } - } - - return null; - } - } - - /** - * Find and return the simple name of the macro that is being expanded or null if the name - * cannot be found. - */ - private static String getMacroName(IASTPreprocessorMacroExpansion expansion) { - if (expansion == null) - return null; - - IASTName name = expansion.getMacroReference(); - return name == null ? null : name.toString(); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTImageLocation.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTImageLocation.java deleted file mode 100644 index e7b063afc66..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTImageLocation.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTImageLocation; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; - -/** - * The location of the signal/slot reference is stored as the location of the parent - * macro expansion + an offset, which is the number of characters between the start - * of the expansion and the start of the argument (including whitespace). E.g. in, - * - *

- * MACRO( expansionParameter )
- * ^      ^                ^ c: end of reference name
- * |      +----------------- b: start of reference name
- * +------------------------ a: start of macro expansion
- * 
- * - * The offset is b - a and length is c - b. This means that the result of 'Find - * References' will highlight just "parameter". - */ -public class QtASTImageLocation implements IASTImageLocation { - - private final IASTFileLocation refLocation; - private final int offset; - private final int length; - - public QtASTImageLocation(IASTFileLocation refLocation, int offset, int length) { - this.refLocation = refLocation; - this.offset = offset; - this.length = length; - } - - public int getOffset() { - return offset; - } - - public int getLength() { - return length; - } - - @Override - public IASTFileLocation asFileLocation() { - return this; - } - - @Override - public String getFileName() { - return refLocation.getFileName(); - } - - @Override - public int getNodeOffset() { - return refLocation.getNodeOffset() + offset; - } - - @Override - public int getNodeLength() { - return length; - } - - @Override - public int getStartingLineNumber() { - return refLocation.getStartingLineNumber(); - } - - @Override - public int getEndingLineNumber() { - return refLocation.getEndingLineNumber(); - } - - @Override - public IASTPreprocessorIncludeStatement getContextInclusionStatement() { - return refLocation.getContextInclusionStatement(); - } - - @Override - public int getLocationKind() { - return REGULAR_CODE; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTVisitor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTVisitor.java deleted file mode 100644 index 32c2b12234e..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtASTVisitor.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.cdt.core.dom.ast.ASTVisitor; -import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; -import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.IScope; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; -import org.eclipse.cdt.core.index.IIndexSymbols; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; -import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; -import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; -import org.eclipse.cdt.qt.core.QtKeywords; -import org.eclipse.cdt.qt.core.index.IQMethod; -import org.eclipse.cdt.qt.core.index.IQProperty; -import org.eclipse.cdt.qt.internal.core.QtMethodUtil; -import org.eclipse.cdt.qt.internal.core.index.QProperty; - -@SuppressWarnings("restriction") -public class QtASTVisitor extends ASTVisitor { - - private final IIndexSymbols symbols; - private final LocationMap locationMap; - - private static final Pattern expansionParamRegex = Pattern.compile("^(?:Q_ENUMS|Q_FLAGS)\\s*\\((.*)\\)$", Pattern.DOTALL); - private static final Pattern qualNameRegex = Pattern.compile("\\s*((?:[^\\s:]+\\s*::\\s*)*[^\\s:]+).*"); - - private static final Pattern declareFlagsRegex = Pattern.compile("^Q_DECLARE_FLAGS\\s*\\(\\s*([^\\s]+),\\s*([^\\s]+)\\s*\\)$", Pattern.DOTALL); - - /** - * A regular expression for scanning the Q_CLASSINFO expansion and extracting the - * expansion parameter key and value. It provides the following capture groups: - *
1 - the key - *
2 - the value - *

- * The key must not have embedded quotes. - */ - private static final Pattern classInfoRegex = Pattern.compile("^Q_CLASSINFO\\s*\\(\\s*\"([^\"]+)\"\\s*,\\s*\"(.*)\"\\s*\\)$", Pattern.DOTALL); - - private static final Pattern leadingWhitespaceRegex = Pattern.compile("^\\s*([^\\s].*)$"); - - private static final Pattern qPropertyRegex = Pattern.compile("^Q_PROPERTY\\s*\\(\\s*(.+?)\\s*([a-zA-Z_][\\w]*+)(?:(?:\\s+(READ\\s+.*))|\\s*)\\s*\\)$", Pattern.DOTALL); - - /** - * A regular expression for scanning Q_PROPERTY attributes. The regular expression is built - * from the values defined in IQProperty#Attribute. It looks like: - *

-	 * (:?READ)|(?:WRITE)|(:?RESET)|...
-	 * 
- * This regular expression is used to recognize valid attributes while scanning the - * Q_PROPERTY macro expansion. - * - * @see QProperty#scanAttributes(String) - */ - private static final Pattern qPropertyAttributeRegex; - static { - StringBuilder regexBuilder = new StringBuilder(); - for(IQProperty.Attribute attr : IQProperty.Attribute.values()) { - if (attr.ordinal() > 0) - regexBuilder.append('|'); - regexBuilder.append("(:?"); - regexBuilder.append(attr.identifier); - regexBuilder.append(")"); - } - qPropertyAttributeRegex = Pattern.compile(regexBuilder.toString()); - } - - public QtASTVisitor(IIndexSymbols symbols, LocationMap locationMap) { - shouldVisitDeclSpecifiers = true; - - this.symbols = symbols; - this.locationMap = locationMap; - } - - @Override - public int visit(IASTDeclSpecifier declSpec) { - if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { - ICPPASTCompositeTypeSpecifier spec = (ICPPASTCompositeTypeSpecifier) declSpec; - - IASTFileLocation loc = spec.getFileLocation(); - IASTPreprocessorIncludeStatement owner = loc == null ? null : loc.getContextInclusionStatement(); - - IASTPreprocessorMacroExpansion[] expansions = locationMap.getMacroExpansions(loc); - - if (isQObject(spec, expansions)) - handleQObject(owner, spec, expansions); - } - - return super.visit(declSpec); - } - - private boolean isQObject(ICPPASTCompositeTypeSpecifier spec, IASTPreprocessorMacroExpansion[] expansions) { - - // The class definition must contain a Q_OBJECT expansion. - for (IASTPreprocessorMacroExpansion expansion : expansions) { - IASTPreprocessorMacroDefinition macro = expansion.getMacroDefinition(); - if (QtKeywords.Q_OBJECT.equals(String.valueOf(macro.getName()))) - return true; - } - - return false; - } - - private class EnumDecl { - private final String name; - private final boolean isFlag; - private final IASTName refName; - private final QtASTImageLocation location; - - public EnumDecl(String name, boolean isFlag, IASTName refName, int offset, int length) { - this.name = name; - this.isFlag = isFlag; - this.refName = refName; - this.location = new QtASTImageLocation(refName.getFileLocation(), offset, length); - } - - public void handle(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, QObjectName qobjName, Map aliases) { - - String alias = aliases.get(name); - - IBinding[] bindings = CPPSemantics.findBindingsForQualifiedName(spec.getScope(), alias == null ? name : alias); - for(IBinding binding : bindings) { - // Create a reference from this Qt name to the target enum's definition. - IASTName cppName = findASTName(binding); - QtEnumName astName = new QtEnumName(qobjName, refName, name, cppName, location, isFlag); - symbols.add(owner, astName, qobjName); - - if (cppName != null) - symbols.add(owner, new ASTNameReference(cppName, location), astName); - } - } - } - - private void handleQObject(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, IASTPreprocessorMacroExpansion[] expansions) { - - // Put the QObject into the symbol map. - QObjectName qobjName = new QObjectName(spec); - symbols.add(owner, qobjName, null); - - // The QObject contains a reference to the C++ class that it annotates. - symbols.add(owner, new ASTNameReference(spec.getName()), qobjName); - - // There are three macros that are significant to QEnums, Q_ENUMS, Q_FLAGS, and Q_DECLARE_FLAGS. - // All macro expansions in the QObject class definition are examined to find instances of these - // three. Two lists are created during this processing. Then those lists are uses to create - // the QEnum instances. - - List enumDecls = new ArrayList(); - Map flagAliases = new HashMap(); - - for (IASTPreprocessorMacroExpansion expansion : expansions) { - - IASTName name = expansion.getMacroReference(); - String macroName = name == null ? null : name.toString(); - if (QtKeywords.Q_OBJECT.equals(macroName)) - continue; - - if (QtKeywords.Q_ENUMS.equals(macroName)) - extractEnumDecls(expansion, false, enumDecls); - else if (QtKeywords.Q_FLAGS.equals(macroName)) - extractEnumDecls(expansion, true, enumDecls); - else if (QtKeywords.Q_DECLARE_FLAGS.equals(macroName)) { - Matcher m = declareFlagsRegex.matcher(expansion.getRawSignature()); - if (m.matches()) { - String flagName = m.group(1); - String enumName = m.group(2); - flagAliases.put(flagName, enumName); - } - } else if(QtKeywords.Q_CLASSINFO.equals(macroName)) { - Matcher m = classInfoRegex.matcher(expansion.getRawSignature()); - if (m.matches()) { - String key = m.group(1); - String value = m.group(2); - qobjName.addClassInfo(key, value); - } - } else if(QtKeywords.Q_PROPERTY.equals(macroName)) - handleQPropertyDefn(owner, qobjName, expansion); - } - - // Process the slot, signal, and invokable method declarations. - extractQMethods(owner, spec, qobjName); - - for(EnumDecl decl : enumDecls) - decl.handle(owner, spec, qobjName, flagAliases); - } - - private void extractEnumDecls(IASTPreprocessorMacroExpansion expansion, boolean isFlag, List decls) { - String signature = expansion.getRawSignature(); - Matcher m = expansionParamRegex.matcher(signature); - if (!m.matches()) - return; - - IASTName refName = expansion.getMacroReference(); - String param = m.group(1); - for(int offset = m.start(1), end = param.length(); !param.isEmpty(); offset += end, param = param.substring(end)) { - m = qualNameRegex.matcher(param); - if (!m.matches()) - break; - - int start = m.start(1); - end = m.end(1); - - String enumName = m.group(1); - decls.add(new EnumDecl(enumName, isFlag, refName, offset + start, end - start)); - } - } - - private void handleQPropertyDefn(IASTPreprocessorIncludeStatement owner, QObjectName qobjName, IASTPreprocessorMacroExpansion expansion) { - Matcher m = qPropertyRegex.matcher(expansion.getRawSignature()); - if (!m.matches()) - return; - - String type = m.group(1); - String name = m.group(2); - - int nameStart = m.start(2); - int nameEnd = m.end(2); - - IASTName refName = expansion.getMacroReference(); - QtASTImageLocation location = new QtASTImageLocation(refName.getFileLocation(), nameStart, nameEnd - nameStart); - - QtPropertyName propertyName = new QtPropertyName(qobjName, refName, name, location); - propertyName.setType(type); - qobjName.addProperty(propertyName); - symbols.add(owner, propertyName, qobjName); - - // Create nodes for all the attributes. - AttrValue[] values = new AttrValue[IQProperty.Attribute.values().length]; - String attributes = m.group(3); - if (attributes == null) - return; - - int attrOffset = m.start(3); - - int lastEnd = 0; - IQProperty.Attribute lastAttr = null; - for(Matcher attributeMatcher = qPropertyAttributeRegex.matcher(attributes); attributeMatcher.find(); lastEnd = attributeMatcher.end()) { - // set the value of attribute found in the previous iteration to the substring between - // the end of that attribute and the start of this one - if (lastAttr != null) { - String value = attributes.substring(lastEnd, attributeMatcher.start()); - int wsOffset = 0; - Matcher ws = leadingWhitespaceRegex.matcher(value); - if (ws.matches()) { - value = ws.group(1); - wsOffset = ws.start(1); - } - - values[lastAttr.ordinal()] = new AttrValue(attrOffset + lastEnd + wsOffset, value.trim()); - } - - // the regex is built from the definition of the enum, so none of the strings that it - // finds will throw an exception - lastAttr = IQProperty.Attribute.valueOf(IQProperty.Attribute.class, attributeMatcher.group(0)); - - // if this attribute doesn't have a value, then put it into the value map immediately - // and make sure it is not used later in this scan - if (!lastAttr.hasValue) { - values[lastAttr.ordinal()] = AttrValue.None; - lastAttr = null; - } - } - - // the value of the last attribute in the expansion is the substring between the end of - // the attribute identifier and the end of the string - if (lastAttr != null) { - String value = attributes.substring(lastEnd); - int wsOffset = 0; - Matcher ws = leadingWhitespaceRegex.matcher(value); - if (ws.matches()) { - value = ws.group(1); - wsOffset = ws.start(1); - } - - values[lastAttr.ordinal()] = new AttrValue(attrOffset + lastEnd + wsOffset, value.trim()); - } - - // Put all values into the property name. - for(int i = 0; i < values.length; ++i) { - IQProperty.Attribute attr = IQProperty.Attribute.values()[i]; - AttrValue value = values[i]; - if (value == null) - continue; - - // If the attribute is not expected to have a C++ binding as the value, then it can - // be immediately added to the Q_PROPERTY. - if (!couldHaveBinding(attr)) { - propertyName.addAttribute(attr, value.value); - continue; - } - - // Otherwise see if one or more bindings can be found for the value of the attribute. - // TODO Check whether the Qt moc allows for inherited methods. - IBinding[] bindings = null; - IASTNode specNode = qobjName.getParent(); - if (specNode instanceof IASTCompositeTypeSpecifier) { - IScope scope = ((IASTCompositeTypeSpecifier) specNode).getScope(); - bindings = CPPSemantics.findBindings(scope, value.value, false); - } - - // If no bindings are found, then the attribute can be immediately added to the Q_PROPERTY. - if (bindings == null || bindings.length <= 0) { - propertyName.addAttribute(attr, value.value); - continue; - } - - // Otherwise create a new attribute for each binding. - for(IBinding foundBinding : bindings) { - propertyName.addAttribute(attr, value.value, foundBinding); - - IASTName cppName = findASTName(foundBinding); - if (cppName != null) { - QtASTImageLocation attrLoc = new QtASTImageLocation(refName.getFileLocation(), value.offset, value.value.length()); - symbols.add(owner, new ASTNameReference(cppName, attrLoc), propertyName); - } - } - } - } - - private static boolean couldHaveBinding(IQProperty.Attribute attr) { - switch(attr) { - case READ: - case WRITE: - case RESET: - case NOTIFY: - case DESIGNABLE: - case SCRIPTABLE: - return true; - - case REVISION: - case STORED: - case USER: - case CONSTANT: - case FINAL: - default: - return false; - } - } - - private static IASTName findASTName(IBinding binding) { - IASTNode node = null; - if (binding instanceof ICPPInternalBinding) { - node = ((ICPPInternalBinding) binding).getDefinition(); - if (node == null) - node = ((ICPPInternalBinding) binding).getDeclarations()[0]; - } - - if (node == null) - return null; - - IASTName astName = node instanceof IASTName ? (IASTName) node : null; - if (astName != null) - return astName; - - if (node instanceof IASTDeclarator) - return ((IASTDeclarator) node).getName(); - - return null; - } - - private static class AttrValue { - public final int offset; - public final String value; - public AttrValue(int offset, String value) { - this.offset = offset; - this.value = value; - } - public static final AttrValue None = new AttrValue(0, null); - } - - private void extractQMethods(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, QObjectName qobjName) { - QtASTClass qtASTClass = QtASTClass.create(spec); - for (IASTDeclaration decl : spec.getMembers()) { - - // We only care about this node if it is within a signal/slot region or if it - // has been tagged with a Qt annotating tag. - int offset = decl.getFileLocation().getNodeOffset(); - IQMethod.Kind kind = qtASTClass.getKindFor(offset); - Long revision = qtASTClass.getRevisionFor(offset); - if (kind == IQMethod.Kind.Unspecified) - continue; - - // Only named methods are processed, so skip this node if it is not a function or - // if it does not have a name. - IASTSimpleDeclaration simpleDecl = getSimpleDecl(decl); - if (simpleDecl == null) - continue; - - ICPPASTFunctionDeclarator decltor = null; - for(IASTDeclarator d : simpleDecl.getDeclarators()) - if (d instanceof ICPPASTFunctionDeclarator) { - decltor = (ICPPASTFunctionDeclarator) d; - break; - } - if (decltor == null) - continue; - - IASTName cppName = decltor.getName(); - if (cppName == null) - continue; - - String qtEncSignatures = QtMethodUtil.getEncodedQtMethodSignatures(decltor); - symbols.add(owner, new QMethodName(qobjName, cppName, kind, qtEncSignatures, revision), qobjName); - } - } - - private static IASTSimpleDeclaration getSimpleDecl(IASTNode node) { - while (node != null && !(node instanceof IASTSimpleDeclaration)) - node = node.getParent(); - return node instanceof IASTSimpleDeclaration ? (IASTSimpleDeclaration) node : null; - } - - /** - * Return the node's IASTName if it is a function and null otherwise. - */ - private static IASTName getFunctionName(IASTDeclaration decl) { - IASTSimpleDeclaration simpleDecl = getSimpleDecl(decl); - if (simpleDecl == null) - return null; - - // Only functions can be signals or slots. Return the name of the first declarator - // that is a function. - for( IASTDeclarator decltor : simpleDecl.getDeclarators()) - if (decltor instanceof IASTFunctionDeclarator) - return decltor.getName(); - - return null; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtEnumName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtEnumName.java deleted file mode 100644 index 8827fb0af3e..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtEnumName.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.core.runtime.CoreException; - -public class QtEnumName extends AbstractQObjectMemberName implements IQtASTName { - - private final IASTName cppEnumName; - private final boolean isFlag; - - public QtEnumName(QObjectName qobjName, IASTName ast, String qtEnumName, IASTName cppEnumName, QtASTImageLocation location, boolean isFlag) { - super(qobjName, ast, qtEnumName, location); - this.cppEnumName = cppEnumName; - this.isFlag = isFlag; - } - - public boolean isFlag() { - return isFlag; - } - - @Override - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { - return new QtPDOMQEnum(linkage, getOwner(linkage), this, cppEnumName); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMASTProcessor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMASTProcessor.java deleted file mode 100644 index ba9b5689d1d..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMASTProcessor.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.index.IIndexSymbols; -import org.eclipse.cdt.core.index.IPDOMASTProcessor; -import org.eclipse.cdt.internal.core.parser.scanner.LocationMap; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPDOMASTProcessor extends IPDOMASTProcessor.Abstract { - @Override - public int process(IASTTranslationUnit ast, IIndexSymbols symbols) throws CoreException { - ast.accept(new QtASTVisitor(symbols, (LocationMap) ast.getAdapter(LocationMap.class))); - return ILinkage.QT_LINKAGE_ID; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMArray.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMArray.java deleted file mode 100644 index ea3f6a649a4..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMArray.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.internal.core.pdom.db.Database; -import org.eclipse.core.runtime.CoreException; - -/** - * A utility class for storing a fixed-size list of fixed-size elements into the Database. - */ -@SuppressWarnings("restriction") -public class QtPDOMArray { - - private static int offsetInitializer = 0; - protected static enum Field { - Count(Database.INT_SIZE), - Data(0); // The size of the block is provided at runtime. - - public final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - private final QtPDOMLinkage linkage; - private final IQtPDOMCodec codec; - private long record; - - public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec codec, long record) { - this.linkage = linkage; - this.codec = codec; - this.record = record; - } - - public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec codec, T[] array) throws CoreException { - this.linkage = linkage; - this.codec = codec; - this.record = 0; - set(array); - } - - public long getRecord() { - return record; - } - - /** - * Return array that is stored in the database. Return null if the receiver is not initialized. - */ - public T[] get() throws CoreException { - if (record == 0) - return null; - - int count = linkage.getDB().getInt(Field.Count.getRecord(record)); - - long elementRec = Field.Data.getRecord(record); - T[] array = codec.allocArray(count); - for(int i = 0; i < count; ++i, elementRec += codec.getElementSize()) - array[i] = codec.decode(linkage, elementRec); - - return array; - } - - /** - * Store the given array into the database. This may change the storage location of the - * receiver. - * @param array The array of elements that should be stored. Setting the value to null is - * equivalent to calling {@link #delete()}, which clears all storage. - */ - public long set(T[] array) throws CoreException { - if (array == null) - return delete(); - - // Initialize the receiver if needed. - if (record == 0) { - record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize())); - linkage.getDB().putInt(Field.Count.getRecord(record), array.length); - } else { - // Check if the storage block needs to be resized. - int count = linkage.getDB().getInt(Field.Count.getRecord(record)); - if (count != array.length) { - linkage.getDB().free(record); - record = linkage.getDB().malloc(Field.Data.offset + (array.length * codec.getElementSize())); - linkage.getDB().putInt(Field.Count.getRecord(record), array.length); - } - } - - // Write the new content into the database. - long elementRec = Field.Data.getRecord(record); - for(int i = 0; i < array.length; ++i, elementRec += codec.getElementSize()) - codec.encode(linkage, elementRec, array[i]); - - return record; - } - - /** - * Release all storage used by the receiver and its elements. - */ - public long delete() throws CoreException { - // If the receiver is already empty, then there is nothing else to do. - if (record == 0) - return record; - - // Otherwise get the size of the stored array and delete each element. - int count = linkage.getDB().getInt(Field.Count.getRecord(record)); - if (count > 0) { - long elementRec = Field.Data.getRecord(record); - for(int i = 0; i < count; ++i, elementRec += codec.getElementSize()) - codec.encode(linkage, elementRec, null); - } - - // Finally, release the entire record. - linkage.getDB().free(record); - record = 0; - return record; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMBinding.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMBinding.java deleted file mode 100644 index d06054aefec..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMBinding.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public abstract class QtPDOMBinding extends PDOMBinding { - - // The offsetInitializer is initialized with the size of the parent. It is incremented - // during loading of the Fields enum. This value does not reliably store the size of - // the QtPDOMBinding record because the enum will not be initialized until it is needed. - // The record size is retrieved as the offset of the special terminal enumerator Last. - private static int offsetInitializer = RECORD_SIZE; - protected static enum Field { - Last(0); - - public final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - protected QtPDOMBinding(QtPDOMLinkage linkage, long record) { - super(linkage, record); - } - - protected QtPDOMBinding(QtPDOMLinkage linkage, PDOMNode parent, IASTName qtName) throws CoreException { - super(linkage, parent, qtName.getSimpleID()); - } - - @Override - protected int getRecordSize() { - return Field.Last.offset; - } - - protected QtPDOMLinkage getQtLinkage() { - PDOMLinkage pdomLinkage = getLinkage(); - return pdomLinkage instanceof QtPDOMLinkage ? (QtPDOMLinkage) pdomLinkage : null; - } - - // Access to the base class is restricted in the cdt.core plugin. Other classes in the qt.core - // plugin that need the qualified name get an access warning. This forwarding function moves - // those warnings to a single place (this method). - @Override - public String[] getQualifiedName() { - return super.getQualifiedName(); - } - - // Access to the base class is restricted in the cdt.core plugin. Other classes in the qt.core - // plugin that need the name get an access warning. This forwarding function moves those warnings - // to a single place (this method). - @Override - public String getName() { - return super.getName(); - } - - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Object getAdapter(Class adapter) { - if (adapter.isAssignableFrom(getClass())) - return this; - - return super.getAdapter(adapter); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMLinkage.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMLinkage.java deleted file mode 100644 index 983de4e8641..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMLinkage.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.IType; -import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; -import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; -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.IBTreeComparator; -import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; -import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPDOMLinkage extends PDOMLinkage { - - private static int offsetInitializer = PDOMLinkage.RECORD_SIZE; - private static enum Field { - Version(Database.INT_SIZE), - Last(0); - - private final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - // The version that has been read from/written to the persisted file. - private int version; - - private final Map cache = new HashMap(); - - public QtPDOMLinkage(PDOM pdom, long record) throws CoreException { - super(pdom, record); - - version = pdom.getDB().getInt(Field.Version.getRecord(record)); - } - - protected QtPDOMLinkage(PDOM pdom) throws CoreException { - super(pdom, ILinkage.QT_LINKAGE_NAME, ILinkage.QT_LINKAGE_NAME.toCharArray()); - - // Initialize the version with whatever is current. - version = QtPDOMNodeType.VERSION; - pdom.getDB().putInt(Field.Version.getRecord(record), version); - } - - public int getVersion() { - return version; - } - - @Override - public String getLinkageName() { - return ILinkage.QT_LINKAGE_NAME; - } - - @Override - public int getLinkageID() { - return ILinkage.QT_LINKAGE_ID; - } - - @Override - public PDOMNode getNode(long record, int nodeType) throws CoreException { - return QtPDOMNodeType.load(this, nodeType, record); - } - - @Override - public IBTreeComparator getIndexComparator() { - return new FindBinding.DefaultBindingBTreeComparator(this); - } - - // IBinding#getAdapter cannot create an instance of PDOMBinding because the Linkage is required. This - // utility method uses #getAdapter to see if an instance has already been create. If not then a new - // is created and stored in the AST binding. - @Override - public PDOMBinding adaptBinding(IBinding binding, boolean includeLocal) throws CoreException { - if (binding == null) - return null; - - // If a binding has already been persisted for this instance then return it now. - QtPDOMBinding pdomBinding = (QtPDOMBinding) binding.getAdapter(QtPDOMBinding.class); - if (pdomBinding != null - && pdomBinding.getLinkage() == this) - return pdomBinding; - - // If a PDOMBinding was created, then add it to the linkage before returning it. - if (pdomBinding != null) { - addChild(pdomBinding); - return pdomBinding; - } - - // Otherwise fall back to looking in the C++ linkage. - return getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID).adaptBinding(binding); - } - - public long getCPPRecord(IASTName cppName) throws CoreException { - - if (cppName == null) - return 0; - - IBinding binding = getPDOM().findBinding(cppName); - if (binding == null) - return 0; - - IPDOMBinding pdomBinding = (IPDOMBinding) binding.getAdapter(IPDOMBinding.class); - if (pdomBinding == null) - return 0; - - if (pdomBinding.getLinkage() == null - || pdomBinding.getLinkage().getLinkageID() != ILinkage.CPP_LINKAGE_ID) - return 0; - - return pdomBinding.getRecord(); - } - - /** - * Return the PDOMBinding for the given Qt name creating a new binding if needed. The - * implementation caches the result using the name instance as the key. This ensures - * one-to-one uniqueness between AST names and PDOMBindings. - *

- * This method is not thread-safe. - */ - public PDOMBinding getBinding(IQtASTName qtAstName) throws CoreException { - // The Qt implementation ensures uniqueness by creating only a single instance of - // the IASTName for each thing that should create a single instance in the PDOM. - // This will work as long as all Qt elements are updated at once, which is currently - // the case. - // - // I don't think this needs to be thread-safe, because things are only added from - // the single indexer task. - PDOMBinding pdomBinding = null; - pdomBinding = cache.get(qtAstName); - if (pdomBinding != null) - return pdomBinding; - - // The result is cached even when null is returned. - pdomBinding = qtAstName.createPDOMBinding(this); - cache.put(qtAstName, pdomBinding); - - // Only add children that are actually created. - if (pdomBinding != null) - addChild(pdomBinding); - - return pdomBinding; - } - - @Override - public PDOMBinding addBinding(IASTName name) throws CoreException { - - // The Qt linkage is able to reference elements in other linkages. This implementation - // needs to decide if the binding associated with this name is from the Qt linkage or - // from one of those external references. - - if (name == null) - return null; - - if (name instanceof IQtASTName) - return getBinding((IQtASTName) name); - - IBinding binding = name.getBinding(); - if (binding == null) - return null; - - // Use the receiving linkage by default, and override only if the binding is found to - // have a linkage with a different id. - PDOMLinkage pdomLinkage = this; - ILinkage linkage = binding.getLinkage(); - if (linkage != null - && linkage.getLinkageID() != getLinkageID()) - pdomLinkage = getPDOM().getLinkage(linkage.getLinkageID()); - - // Handle bindings in unknown linkages as though the name is to be added to this linkage. - return (pdomLinkage == null ? this : pdomLinkage).adaptBinding(binding); - } - - @Override - public int getBindingType(IBinding binding) { - return binding instanceof QtPDOMBinding ? ((QtPDOMBinding) binding).getNodeType() : 0; - } - - @Override - public PDOMBinding addTypeBinding(IBinding binding) throws CoreException { - throw new CoreException(QtPlugin.error("Qt Linkage does not manage types")); //$NON-NLS-1$ - } - - @Override - public IType unmarshalType(ITypeMarshalBuffer buffer) throws CoreException { - throw new CoreException(QtPlugin.error("Qt Linkage does not marshal types")); //$NON-NLS-1$ - } - - @Override - public IBinding unmarshalBinding(ITypeMarshalBuffer buffer) throws CoreException { - throw new CoreException(QtPlugin.error("Qt Linkage does not marshal bindings")); //$NON-NLS-1$ - } - - @Override - public ISerializableEvaluation unmarshalEvaluation(ITypeMarshalBuffer typeMarshalBuffer) throws CoreException { - throw new CoreException(QtPlugin.error("Qt Linkage does not marshal evaluations")); //$NON-NLS-1$ - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMNodeType.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMNodeType.java deleted file mode 100644 index 86734c22aa1..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMNodeType.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.internal.core.index.IIndexBindingConstants; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public enum QtPDOMNodeType { - - QObject, - QEnum, - QProperty, - QMethod; - - public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal(); - - /** - * The current version of the QtPDOMLinkage. This can be used to make sure the persisted - * data matches what is expected by the implementation. Care should be taken to make changes - * backward compatible when possible. - *

- * The version is needed because ordinals for these enumerators are written to the file. - */ - public static final int VERSION = 4; - - public static QtPDOMNodeType forType(int version, int type) { - // Nothing has been deleted or replaced yet, so the version is ignored. - - for(QtPDOMNodeType node : values()) - if (node.Type == type) - return node; - return null; - } - - // This needs to return PDOMNode so that it can be either QtPDOMNode or QtPDOMBinding. - public static PDOMNode load(QtPDOMLinkage linkage, int nodeType, long record) throws CoreException { - QtPDOMNodeType node = QtPDOMNodeType.forType(linkage.getVersion(), nodeType); - if (node == null) - return null; - - switch(node) { - case QObject: - return new QtPDOMQObject(linkage, record); - case QEnum: - return new QtPDOMQEnum(linkage, record); - case QProperty: - return new QtPDOMProperty(linkage, record); - case QMethod: - return new QtPDOMQMethod(linkage, record); - } - - return null; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMProperty.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMProperty.java deleted file mode 100644 index 48823bab01f..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMProperty.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.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.dom.PDOMBinding; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.cdt.qt.core.index.IQProperty; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPDOMProperty extends QtPDOMBinding { - - private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; - protected static enum Field { - Type(Database.PTR_SIZE), - Attributes(Database.PTR_SIZE), - Last(0); - - public final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - public QtPDOMProperty(QtPDOMLinkage linkage, long record) { - super(linkage, record); - } - - public QtPDOMProperty(QtPDOMLinkage linkage, PDOMBinding parent, QtPropertyName qtName) throws CoreException { - super(linkage, parent, qtName); - - setType(qtName.getType()); - - if (parent instanceof QtPDOMQObject) - ((QtPDOMQObject) parent).addChild(this); - } - - @Override - protected int getRecordSize() { - return Field.Last.offset; - } - - @Override - public int getNodeType() { - return QtPDOMNodeType.QProperty.Type; - } - - public void delete() throws CoreException { - long fieldRec = getDB().getRecPtr(Field.Type.getRecord(record)); - if (fieldRec != 0) - getDB().getString(fieldRec).delete(); - getDB().putRecPtr(Field.Type.getRecord(record), 0); - } - - public void setType(String type) throws CoreException { - long rec = getDB().getRecPtr(Field.Type.getRecord(record)); - if (rec != 0) { - IString typeStr = getDB().getString(rec); - if (type == null) { - typeStr.delete(); - return; - } - - // There is nothing to do if the database already stores the same name. - if (type.equals(typeStr.getString())) - return; - } - - getDB().putRecPtr(Field.Type.getRecord(record), getDB().newString(type).getRecord()); - } - - // IType? - public String getType() throws CoreException { - long rec = getDB().getRecPtr(Field.Type.getRecord(record)); - if (rec == 0) - return null; - - return getDB().getString(rec).getString(); - } - - public void setAttributes(Attribute[] attributes) throws CoreException { - long rec = getDB().getRecPtr(Field.Attributes.getRecord(record)); - QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), Attribute.Codec, rec); - rec = pdomArray.set(attributes); - getDB().putRecPtr(Field.Attributes.getRecord(record), rec); - } - - public Attribute[] getAttributes() throws CoreException { - long rec = getDB().getRecPtr(Field.Attributes.getRecord(record)); - QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), Attribute.Codec, rec); - return pdomArray.get(); - } - - public static class Attribute { - public final IQProperty.Attribute attr; - public final String value; - public final long cppRecord; - - public Attribute(IQProperty.Attribute attr, String value) { - this.attr = attr; - this.value = value; - this.cppRecord = 0; - } - - public Attribute(IQProperty.Attribute attr, String value, PDOMBinding cppBinding) { - this.attr = attr; - this.value = value; - this.cppRecord = cppBinding == null ? 0 : cppBinding.getRecord(); - } - - private Attribute(IQProperty.Attribute attr, String value, long cppRecord) { - this.attr = attr; - this.value = value; - this.cppRecord = cppRecord; - } - - private static final IQtPDOMCodec Codec = new IQtPDOMCodec() { - @Override - public int getElementSize() { - return 1 + Database.PTR_SIZE + Database.PTR_SIZE; - } - - @Override - public Attribute[] allocArray(int count) { - return new Attribute[count]; - } - - @Override - public Attribute decode(QtPDOMLinkage linkage, long record) throws CoreException { - byte attrId = linkage.getDB().getByte(record); - long valRec = linkage.getDB().getRecPtr(record + 1); - long cppRec = linkage.getDB().getRecPtr(record + 1 + Database.PTR_SIZE); - - if (attrId < 0 || attrId >= IQProperty.Attribute.values().length) - throw QtPlugin.coreException("invalid QProperty attribute id read from datbase, was " + attrId); - - IQProperty.Attribute attr = IQProperty.Attribute.values()[attrId]; - - String val = valRec == 0 ? "" : linkage.getDB().getString(valRec).getString(); - return new Attribute(attr, val, cppRec); - } - - @Override - public void encode(QtPDOMLinkage linkage, long record, Attribute element) throws CoreException { - linkage.getDB().putByte(record, (byte) element.attr.ordinal()); - - // Delete the existing strings then create and store new ones. - long rec = linkage.getDB().getRecPtr(record + 1); - if (rec != 0) - linkage.getDB().getString(rec).delete(); - - if (element == null || element.value == null) - linkage.getDB().putRecPtr(record + 1, 0); - else - linkage.getDB().putRecPtr(record + 1, linkage.getDB().newString(element.value).getRecord()); - - linkage.getDB().putRecPtr(record + 1 + Database.PTR_SIZE, element.cppRecord); - } - }; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQEnum.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQEnum.java deleted file mode 100644 index ddf2e974278..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQEnum.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IEnumeration; -import org.eclipse.cdt.core.dom.ast.IEnumerator; -import org.eclipse.cdt.internal.core.pdom.db.Database; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPDOMQEnum extends QtPDOMBinding { - - private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; - protected static enum Field { - Flags(1), - CppRecord(Database.PTR_SIZE), - Last(0); - - public final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - private static final int IS_FLAG_MASK = 1; - - private QtPDOMQObject qobj; - - protected QtPDOMQEnum(QtPDOMLinkage linkage, long record) throws CoreException { - super(linkage, record); - } - - public QtPDOMQEnum(QtPDOMLinkage linkage, PDOMBinding parent, IASTName qtName, IASTName cppName) throws CoreException { - super(linkage, parent, qtName); - - getDB().putRecPtr(Field.CppRecord.getRecord(record), linkage.getCPPRecord(cppName)); - - // The flags are set in several sections, and then written to the Database in one operation. - byte flags = 0; - - if (qtName instanceof QtEnumName - && ((QtEnumName) qtName).isFlag()) - flags |= IS_FLAG_MASK; - - // Write the flags to the database. - getDB().putByte(Field.Flags.getRecord(record), flags); - - if (!(parent instanceof QtPDOMQObject)) - this.qobj = null; - else { - this.qobj = (QtPDOMQObject) parent; - this.qobj.addChild(this); - } - } - - @Override - public int getRecordSize() { - return Field.Last.offset; - } - - public IEnumeration getCppEnumeration() throws CoreException { - long cppRec = getDB().getRecPtr(Field.CppRecord.getRecord(record)); - if (cppRec == 0) - return null; - - PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID); - if (cppLinkage == null) - return null; - - PDOMBinding cppBinding = cppLinkage.getBinding(cppRec); - - // TODO - if (cppBinding == null) - return null; - cppBinding.getAdapter(IEnumeration.class); - - return cppBinding instanceof IEnumeration ? (IEnumeration) cppBinding : null; - } - - public boolean isFlag() throws CoreException { - byte flags = getDB().getByte(Field.Flags.getRecord(record)); - return (flags & IS_FLAG_MASK) == IS_FLAG_MASK; - } - - @Override - public int getNodeType() { - return QtPDOMNodeType.QEnum.Type; - } - - public List getEnumerators() throws CoreException { - IEnumeration cppEnum = getCppEnumeration(); - return cppEnum == null ? Collections.emptyList() : Arrays.asList(cppEnum.getEnumerators()); - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQMethod.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQMethod.java deleted file mode 100644 index 98657eadf4c..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQMethod.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.internal.core.pdom.db.Database; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.qt.core.index.IQMethod; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPDOMQMethod extends QtPDOMBinding { - - private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; - protected static enum Field { - Signature(Database.PTR_SIZE), - Revision(8), - Flags(1), - Last(0); - - public final int offset; - - private Field(int sizeof) { - this.offset = offsetInitializer; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - } - - private static final int KIND_IS_INVOKABLE = 1; - private static final int KIND_IS_SIGNAL = 2; - private static final int KIND_IS_SLOT = 3; - private static final int KIND_MASK = 3; - private static final int HAS_REVISION = 4; - - public QtPDOMQMethod(QtPDOMLinkage linkage, long record) throws CoreException { - super(linkage, record); - } - - public QtPDOMQMethod(QtPDOMLinkage linkage, PDOMBinding parent, IASTName qtName, IASTName cppName, IQMethod.Kind kind, String qtEncSignatures, Long revision) throws CoreException { - super(linkage, parent, qtName); - - byte flag = 0; - switch(kind) { - case Invokable: - flag |= KIND_IS_INVOKABLE; - break; - case Signal: - flag |= KIND_IS_SIGNAL; - break; - case Slot: - flag |= KIND_IS_SLOT; - break; - case Unspecified: - break; - } - - if (revision != null) { - flag |= HAS_REVISION; - getDB().putLong(Field.Revision.getRecord(record), revision.longValue()); - } - - getDB().putByte(Field.Flags.getRecord(record), flag); - - long rec = qtEncSignatures == null ? 0 : getDB().newString(qtEncSignatures).getRecord(); - getDB().putRecPtr(Field.Signature.getRecord(record), rec); - - if (parent instanceof QtPDOMQObject) - ((QtPDOMQObject) parent).addChild(this); - } - - @Override - protected int getRecordSize() { - return Field.Last.offset; - } - - public IQMethod.Kind getKind() throws CoreException { - switch(getDB().getByte(Field.Flags.getRecord(record)) & KIND_MASK) { - case KIND_IS_INVOKABLE: - return IQMethod.Kind.Invokable; - case KIND_IS_SIGNAL: - return IQMethod.Kind.Signal; - case KIND_IS_SLOT: - return IQMethod.Kind.Slot; - default: - return IQMethod.Kind.Unspecified; - } - } - - public String getQtEncodedSignatures() throws CoreException { - long rec = getDB().getRecPtr(Field.Signature.getRecord(record)); - return rec == 0 ? null : getDB().getString(rec).getString(); - } - - public Long getRevision() throws CoreException { - byte flag = getDB().getByte(Field.Flags.getRecord(record)); - if ((flag & HAS_REVISION) == 0) - return null; - - return Long.valueOf(getDB().getLong(Field.Revision.getRecord(record))); - } - - @Override - public int getNodeType() { - return QtPDOMNodeType.QMethod.Type; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQObject.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQObject.java deleted file mode 100644 index e8c0e54026e..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMQObject.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; -import org.eclipse.cdt.internal.core.pdom.db.Database; -import org.eclipse.cdt.internal.core.pdom.db.PDOMNodeLinkedList; -import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.core.runtime.CoreException; - -/** - * The persisted form of QObjects. - */ -@SuppressWarnings("restriction") -public class QtPDOMQObject extends QtPDOMBinding { - - private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; - protected static enum Field { - CppRecord(Database.PTR_SIZE, 3), - Children(4 /* From PDOMNodeLinkedList.RECORD_SIZE, which is protected */, 0), - ClassInfos(Database.PTR_SIZE, 2), - Last(0, 0); - - private final int offset; - private final int version; - - private Field(int sizeof, int version) { - this.offset = offsetInitializer; - this.version = version; - offsetInitializer += sizeof; - } - - public long getRecord(long baseRec) { - return baseRec + offset; - } - - /** - * Return true if this linkage in supported in the given instance of the linkage. - */ - public boolean isSupportedIn(QtPDOMLinkage linkage) { - return linkage.getVersion() >= version; - } - } - - private final PDOMNodeLinkedList children; - - protected QtPDOMQObject(QtPDOMLinkage linkage, long record) throws CoreException { - super(linkage, record); - children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record)); - } - - public QtPDOMQObject(QtPDOMLinkage linkage, IASTName qtName, IASTName cppName) throws CoreException { - super(linkage, null, qtName); - - IBinding cppBinding = getPDOM().findBinding(cppName); - if (cppBinding != null) { - IPDOMBinding cppPDOMBinding = (IPDOMBinding) cppBinding.getAdapter(IPDOMBinding.class); - if (cppPDOMBinding != null) { - if (cppPDOMBinding.getLinkage() != null - && cppPDOMBinding.getLinkage().getLinkageID() == ILinkage.CPP_LINKAGE_ID) - getDB().putRecPtr(Field.CppRecord.getRecord(record), cppPDOMBinding.getRecord()); - } - } - - children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record)); - - if (qtName instanceof QObjectName) { - QObjectName qobjName = (QObjectName) qtName; - setClassInfos(qobjName.getClassInfos()); - } - } - - public void delete() throws CoreException { - long fieldRec = Field.ClassInfos.getRecord(record); - new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, fieldRec).delete(); - getDB().putRecPtr(Field.ClassInfos.getRecord(record), 0); - } - - public ICPPClassType getCppClassType() throws CoreException { - long cppRec = getDB().getRecPtr(Field.CppRecord.getRecord(record)); - if (cppRec == 0) - return null; - - PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID); - if (cppLinkage == null) - return null; - - PDOMBinding cppBinding = cppLinkage.getBinding(cppRec); - return cppBinding instanceof ICPPClassType ? (ICPPClassType) cppBinding : null; - } - - public void setClassInfos(Map classInfos) throws CoreException { - - // Make sure the version of the linkage contains this field. - if (!Field.ClassInfos.isSupportedIn(getQtLinkage())) - return; - - // Create an array to be stored to the PDOM. - ClassInfo[] array = new ClassInfo[classInfos.size()]; - Iterator> iterator = classInfos.entrySet().iterator(); - for(int i = 0; i < array.length && iterator.hasNext(); ++i) { - Map.Entry entry = iterator.next(); - array[i] = new ClassInfo(entry.getKey(), entry.getValue()); - } - - // Store the array into the Database. - long arrayRec = getDB().getRecPtr(Field.ClassInfos.getRecord(record)); - QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, arrayRec); - arrayRec = pdomArray.set(array); - - // Update the record that is stored in the receiver's field. - getDB().putRecPtr(Field.ClassInfos.getRecord(record), arrayRec); - } - - public Map getClassInfos() throws CoreException { - Map classInfos = new LinkedHashMap(); - - // Make sure the version of the linkage contains this field. - if (!Field.ClassInfos.isSupportedIn(getQtLinkage())) - return classInfos; - - // Read the array from the Database and insert the elements into the Map that is to be returned. - long arrayRec = getDB().getRecPtr(Field.ClassInfos.getRecord(record)); - QtPDOMArray pdomArray = new QtPDOMArray(getQtLinkage(), ClassInfo.Codec, arrayRec); - - ClassInfo[] array = pdomArray.get(); - if (array == null) - return classInfos; - - for(ClassInfo classInfo : array) - classInfos.put(classInfo.key, classInfo.value); - - return classInfos; - } - - @Override - protected int getRecordSize() { - return Field.Last.offset; - } - - @Override - public int getNodeType() { - return QtPDOMNodeType.QObject.Type; - } - - // This forwarding method is to get rid of compilation warnings when clients try to call - // #getName on the non-accessible parent. - @Override - public String getName() { - return super.getName(); - } - - public List findBases() throws CoreException { - ICPPClassType cppClassType = getCppClassType(); - if (cppClassType == null) - return Collections.emptyList(); - - List bases = new ArrayList(); - for (ICPPBase base : cppClassType.getBases()) { - if (base.getVisibility() != ICPPBase.v_public) - continue; - - IBinding baseCls = base.getBaseClass(); - if (baseCls == null) - continue; - - PDOMBinding pdomBinding = (PDOMBinding) baseCls.getAdapter(PDOMBinding.class); - QtPDOMQObject baseQObj = ASTNameReference.findFromBinding(QtPDOMQObject.class, pdomBinding); - if (baseQObj != null) - bases.add(baseQObj); - } - - return bases; - } - - @Override - public void addChild(PDOMNode child) throws CoreException { - children.addMember(child); - } - - public List getChildren(Class cls) throws CoreException { - QtPDOMVisitor.All collector = new QtPDOMVisitor.All(cls); - try { - children.accept(collector); - } catch(CoreException e) { - QtPlugin.log(e); - return Collections.emptyList(); - } - - return collector.list; - } - - private static class ClassInfo { - public final String key; - public final String value; - public ClassInfo(String key, String value) { - this.key = key; - this.value = value; - } - - public static final IQtPDOMCodec Codec = new IQtPDOMCodec() { - @Override - public int getElementSize() { - return 2 * Database.PTR_SIZE; - } - - @Override - public ClassInfo[] allocArray(int count) { - return new ClassInfo[count]; - } - - @Override - public ClassInfo decode(QtPDOMLinkage linkage, long record) throws CoreException { - long keyRec = linkage.getDB().getRecPtr(record); - long valRec = linkage.getDB().getRecPtr(record + Database.PTR_SIZE); - return new ClassInfo(linkage.getDB().getString(keyRec).getString(), linkage.getDB().getString(valRec).getString()); - } - - @Override - public void encode(QtPDOMLinkage linkage, long record, ClassInfo element) throws CoreException { - // Delete the existing strings then create and store new ones. - long rec = linkage.getDB().getRecPtr(record); - if (rec != 0) - linkage.getDB().getString(rec).delete(); - linkage.getDB().putRecPtr(record, element == null ? 0 : linkage.getDB().newString(element.key).getRecord()); - - rec = linkage.getDB().getRecPtr(record + Database.PTR_SIZE); - if (rec != 0) - linkage.getDB().getString(rec).delete(); - linkage.getDB().putRecPtr(record + Database.PTR_SIZE, element == null ? 0 : linkage.getDB().newString(element.value).getRecord()); - } - }; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMVisitor.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMVisitor.java deleted file mode 100644 index 3dec16f2114..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPDOMVisitor.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.Arrays; - -import org.eclipse.cdt.core.dom.IPDOMNode; -import org.eclipse.cdt.core.dom.IPDOMVisitor; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMNamedNode; -import org.eclipse.core.runtime.CoreException; - -/** - * A Qt-specific specialization of the generic PDOMVisitor. This class provides - * an empty implementation of {@link #leave(IPDOMNode)}, but required implementations to - * provide {@link #visit(IPDOMNode)}. The class also provides a few commonly required - * implementations. - */ -@SuppressWarnings("restriction") -public abstract class QtPDOMVisitor implements IPDOMVisitor { - - /** - * Collects all nodes that match the given type. This could be used, for example, to get - * all QtPDOMQObject's from the index. - */ - public static class All extends QtPDOMVisitor { - - private final Class cls; - public final ArrayList list = new ArrayList(); - - public All(Class cls) { - this.cls = cls; - } - - @Override - @SuppressWarnings("unchecked") - public boolean visit(IPDOMNode node) throws CoreException { - if (node != null - && cls.isAssignableFrom(node.getClass())) - list.add((T) node); - return true; - } - } - - /** - * A simple interface that is used to select node's from the index based on specific - * criteria. - */ - public static interface IFilter { - public boolean matches(IPDOMNode node) throws CoreException; - } - - /** - * A filter that selects nodes based on their name. - */ - public static class PDOMNamedNodeFilter implements IFilter { - - private final char[] name; - - public PDOMNamedNodeFilter(String name) { - this.name = name.toCharArray(); - } - - @Override - public boolean matches(IPDOMNode node) throws CoreException { - if (node instanceof PDOMNamedNode) - return Arrays.equals(name, ((PDOMNamedNode) node).getNameCharArray()); - return false; - } - } - - /** - * A utility class that searches the index for all nodes that match the given filter. - */ - public static class Find extends QtPDOMVisitor { - - private final Class cls; - private final IFilter filter; - - public T element; - - public Find(Class cls, IFilter filter) { - this.cls = cls; - this.filter = filter; - } - - @Override - @SuppressWarnings("unchecked") - public boolean visit(IPDOMNode node) throws CoreException { - if (element != null) - return false; - - if (cls.isAssignableFrom(node.getClass()) - && filter.matches(node)) - element = (T) node; - - return element == null; - } - } - - @Override - public void leave(IPDOMNode node) throws CoreException { - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyAttributeName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyAttributeName.java deleted file mode 100644 index 7739e76d4cb..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyAttributeName.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.core.runtime.CoreException; - -public class QtPropertyAttributeName extends ASTDelegatedName implements IQtASTName { - - private final QtASTImageLocation location; - - public QtPropertyAttributeName(IASTName ast, String name, QtASTImageLocation location) { - super(ast); - this.location = location; - } - - @Override - public IASTFileLocation getFileLocation() { - return location; - } - - @Override - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { - return null; - } -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyName.java deleted file mode 100644 index 36b19fef9e7..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/pdom/QtPropertyName.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.cdt.qt.internal.core.pdom; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; -import org.eclipse.cdt.qt.core.index.IQProperty; -import org.eclipse.core.runtime.CoreException; - -@SuppressWarnings("restriction") -public class QtPropertyName extends AbstractQObjectMemberName implements IQtASTName { - - private String type; - // TODO The PDOM attrs should only be created in #createPDOMBinding - private List attributes = new ArrayList(); - - public QtPropertyName(QObjectName qobjName, IASTName ast, String name, QtASTImageLocation location) { - super(qobjName, ast, name, location); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - /** - * This permits storage of duplicate attributes, a Codan checker should flag this as an error, but - * while the invalid code exists, the references should continue to be properly resolved. - */ - public void addAttribute(IQProperty.Attribute attr, String value) { - attributes.add(new QtPDOMProperty.Attribute(attr, value)); - } - - /** - * This permits storage of duplicate attributes, a Codan checker should flag this as an error, but - * while the invalid code exists, the references should continue to be properly resolved. - */ - public void addAttribute(IQProperty.Attribute attr, String value, IBinding cppBinding) { - PDOMBinding pdomBinding = cppBinding == null ? null : (PDOMBinding) cppBinding.getAdapter(PDOMBinding.class); - attributes.add(new QtPDOMProperty.Attribute(attr, value, pdomBinding)); - } - - @Override - public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { - QtPDOMProperty pdom = new QtPDOMProperty(linkage, getOwner(linkage), this); - pdom.setAttributes(attributes.toArray(new QtPDOMProperty.Attribute[attributes.size()])); - return pdom; - } -} diff --git a/qt/org.eclipse.cdt.qt.tests/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.tests/META-INF/MANIFEST.MF index 2e2cf2a9d36..a6110d5794a 100644 --- a/qt/org.eclipse.cdt.qt.tests/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.tests/META-INF/MANIFEST.MF @@ -1,8 +1,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: Tests +Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.qt.tests -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.1.0.qualifier Bundle-Activator: org.eclipse.cdt.qt.tests.QtTestPlugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, @@ -17,3 +17,4 @@ Require-Bundle: org.eclipse.ui, org.eclipse.cdt.ui Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-Vendor: %vendorName diff --git a/qt/org.eclipse.cdt.qt.tests/plugin.properties b/qt/org.eclipse.cdt.qt.tests/plugin.properties new file mode 100644 index 00000000000..243e869b19c --- /dev/null +++ b/qt/org.eclipse.cdt.qt.tests/plugin.properties @@ -0,0 +1,8 @@ +# 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 + +pluginName=C/C++ Qt Test Suite +providerName=Eclipse CDT diff --git a/qt/org.eclipse.cdt.qt.tests/pom.xml b/qt/org.eclipse.cdt.qt.tests/pom.xml index a284bdd3c5e..00e53027593 100644 --- a/qt/org.eclipse.cdt.qt.tests/pom.xml +++ b/qt/org.eclipse.cdt.qt.tests/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT org.eclipse.cdt.qt.tests eclipse-test-plugin diff --git a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF index 856b83c6f2a..ddddef63eeb 100644 --- a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF @@ -1,16 +1,16 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-Name: CDT Qt Support UI +Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.qt.ui;singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.1.0.qualifier Bundle-Activator: org.eclipse.cdt.qt.ui.QtUIPlugin -Bundle-Vendor: Eclipse CDT +Bundle-Vendor: %providerName Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.cdt.ui, org.eclipse.cdt.core, - org.eclipse.cdt.qt.core, + org.eclipse.cdt.qt.core;bundle-version="[1.1.0,2.0.0)", org.eclipse.jface.text, org.eclipse.core.resources Bundle-RequiredExecutionEnvironment: JavaSE-1.6 diff --git a/qt/org.eclipse.cdt.qt.ui/plugin.properties b/qt/org.eclipse.cdt.qt.ui/plugin.properties index 5f970b962b6..5784ad40ca8 100644 --- a/qt/org.eclipse.cdt.qt.ui/plugin.properties +++ b/qt/org.eclipse.cdt.qt.ui/plugin.properties @@ -4,5 +4,8 @@ # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html +pluginName=C/C++ Qt Support UI +providerName=Eclipse CDT + qtHighlighting.extName=Qt Semantic Highlighting qtHighlighting.displayName=Qt Keywords \ No newline at end of file diff --git a/qt/org.eclipse.cdt.qt.ui/plugin.xml b/qt/org.eclipse.cdt.qt.ui/plugin.xml index e03dd26e7ab..69dc0e2226c 100644 --- a/qt/org.eclipse.cdt.qt.ui/plugin.xml +++ b/qt/org.eclipse.cdt.qt.ui/plugin.xml @@ -29,7 +29,7 @@ name="Qt Completion Proposal Computer"> diff --git a/qt/org.eclipse.cdt.qt.ui/pom.xml b/qt/org.eclipse.cdt.qt.ui/pom.xml index 1b474a09b75..0f66153d5a9 100644 --- a/qt/org.eclipse.cdt.qt.ui/pom.xml +++ b/qt/org.eclipse.cdt.qt.ui/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT org.eclipse.cdt.qt.ui eclipse-plugin diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QtCompletionProposalComputer.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QtCompletionProposalComputer.java new file mode 100644 index 00000000000..78511171803 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/internal/qt/ui/QtCompletionProposalComputer.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.qt.ui; + +import java.util.ArrayList; +import java.util.Collection; +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.core.dom.ast.ASTTypeUtil; +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +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.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; +import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal; +import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistInvocationContext; +import org.eclipse.cdt.internal.ui.text.contentassist.ParsingBasedProposalComputer; +import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.QtNature; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.qt.ui.QtUIPlugin; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.text.contentassist.ICEditorContentAssistInvocationContext; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.contentassist.ICompletionProposal; + +@SuppressWarnings("restriction") +public class QtCompletionProposalComputer extends ParsingBasedProposalComputer { + private boolean isApplicable(ICEditorContentAssistInvocationContext context) { + ITranslationUnit tu = context.getTranslationUnit(); + if (tu == null) + return false; + + ICProject cProject = tu.getCProject(); + if (cProject == null) + return false; + + IProject project = cProject.getProject(); + if (project == null) + return false; + + try { + return project.hasNature(QtNature.ID); + } catch (CoreException e) { + CUIPlugin.log(e); + return false; + } + } + + private static boolean is_QObject_connect( + ICEditorContentAssistInvocationContext context, + IASTCompletionContext astContext, IASTName name) { + IASTName connectName = name.getLastName(); + if (!QtKeywords.CONNECT.equals(new String(connectName.getSimpleID()))) + return false; + + IBinding[] funcBindings = astContext.findBindings(connectName, + !context.isContextInformationStyle()); + for (IBinding funcBinding : funcBindings) + if (funcBinding instanceof ICPPFunction) { + IBinding ownerBinding = ((ICPPFunction) funcBinding).getOwner(); + if (ownerBinding != null + && QtKeywords.QOBJECT.equals(ownerBinding.getName())) + return true; + } + + return false; + } + + private static class Completion { + private final String replacement; + private final String display; + private final int cursorOffset; + + public static final Completion SIGNAL = new Completion("SIGNAL()", + "SIGNAL(a)", -1); + public static final Completion SLOT = new Completion("SLOT()", + "SLOT(a)", -1); + + public Completion(String replacement) { + this(replacement, replacement, 0); + } + + public Completion(String replacement, String display, int cursorOffset) { + this.replacement = replacement; + this.display = display; + this.cursorOffset = cursorOffset; + } + + public ICompletionProposal createProposal( + ICEditorContentAssistInvocationContext context) { + int repLength = replacement.length(); + int repOffset = context.getInvocationOffset(); + CCompletionProposal p = new CCompletionProposal(replacement, + repOffset, repLength, null, display, + RelevanceConstants.DEFAULT_TYPE_RELEVANCE, + context.getViewer()); + p.setCursorPosition(repLength + cursorOffset); + return p; + } + + @Override + public String toString() { + if (replacement == null) + return super.toString(); + return replacement + '@' + cursorOffset; + } + } + + private static interface MethodFilter { + public boolean keep(ICPPMethod method); + + public static class Qt { + public static final MethodFilter Signal = new MethodFilter() { + @Override + public boolean keep(ICPPMethod method) { + ITagReader tagReader = CCorePlugin.getTagService() + .findTagReader(method); + if (tagReader == null) + return false; + + ITag tag = tagReader.getTag(QtPlugin.SIGNAL_SLOT_TAGGER_ID); + if (tag == null) + return false; + + int result = tag.getByte(0); + return result != ITag.FAIL + && ((result & QtPlugin.SignalSlot_Mask_signal) == QtPlugin.SignalSlot_Mask_signal); + } + }; + + public static final MethodFilter Slot = new MethodFilter() { + @Override + public boolean keep(ICPPMethod method) { + ITagReader tagReader = CCorePlugin.getTagService() + .findTagReader(method); + if (tagReader == null) + return false; + + ITag tag = tagReader.getTag(QtPlugin.SIGNAL_SLOT_TAGGER_ID); + if (tag == null) + return false; + + int result = tag.getByte(0); + return result != ITag.FAIL + && ((result & QtPlugin.SignalSlot_Mask_slot) == QtPlugin.SignalSlot_Mask_slot); + } + }; + } + } + + private static Iterable filterMethods(final ICPPClassType cls, + final MethodFilter filter) { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private int index = 0; + private final ICPPMethod[] methods = cls.getMethods(); + + @Override + public boolean hasNext() { + for (; index < methods.length; ++index) + if (filter.keep(methods[index])) + return true; + return false; + } + + @Override + public ICPPMethod next() { + return methods[index++]; + } + + @Override + public void remove() { + } + }; + } + }; + } + + private static String getSignature(ICPPMethod method) { + StringBuilder signature = new StringBuilder(); + + signature.append(method.getName()); + signature.append('('); + boolean first = true; + for (ICPPParameter param : method.getParameters()) { + if (first) + first = false; + else + signature.append(", "); + signature.append(ASTTypeUtil.getType(param.getType())); + } + + signature.append(')'); + return signature.toString(); + } + + private static void addCompletionsFor(Collection completions, + IASTInitializerClause init, MethodFilter filter) { + if (!(init instanceof ICPPASTInitializerClause)) + return; + + ICPPEvaluation eval = ((ICPPASTInitializerClause) init).getEvaluation(); + if (eval == null) + return; + + IType type = eval.getTypeOrFunctionSet(init); + while (type instanceof IPointerType) + type = ((IPointerType) type).getType(); + + if (type instanceof ICPPClassType) + for (ICPPMethod signal : filterMethods((ICPPClassType) type, filter)) + completions.add(new Completion(getSignature(signal))); + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int indexOfClosingPeer(String code, char left, char right, + int pos) { + int level = 0; + final int length = code.length(); + while (pos < length) { + char ch = code.charAt(pos); + if (ch == left) { + ++level; + } else if (ch == right) { + if (--level == 0) { + return pos; + } + } + ++pos; + } + return -1; + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int[] computeCommaPositions(String code) { + final int length = code.length(); + int pos = 0; + List positions = new ArrayList(); + positions.add(new Integer(-1)); + while (pos < length && pos != -1) { + char ch = code.charAt(pos); + switch (ch) { + case ',': + positions.add(new Integer(pos)); + break; + case '(': + pos = indexOfClosingPeer(code, '(', ')', pos); + break; + case '<': + pos = indexOfClosingPeer(code, '<', '>', pos); + break; + case '[': + pos = indexOfClosingPeer(code, '[', ']', pos); + break; + default: + break; + } + if (pos != -1) + pos++; + } + positions.add(new Integer(length)); + + int[] fields = new int[positions.size()]; + for (int i = 0; i < fields.length; i++) + fields[i] = positions.get(i).intValue(); + return fields; + } + + private void addConnectParameterCompletions( + List proposals, + ICEditorContentAssistInvocationContext context, + IASTCompletionNode completionNode, String prefix) { + IASTName[] names = completionNode.getNames(); + List completions = new LinkedList(); + + for (IASTName name : names) { + // The node isn't properly hooked up, must have backtracked out of + // this node + if (name.getTranslationUnit() == null) + continue; + + IASTCompletionContext astContext = name.getCompletionContext(); + if (astContext == null || !(astContext instanceof IASTNode)) + continue; + IASTNode astNode = (IASTNode) astContext; + + if (is_QObject_connect(context, astContext, name)) { + int parseOffset = context.getParseOffset(); + int invocationOffset = context.getInvocationOffset(); + + String unparsed = ""; + try { + unparsed = context.getDocument().get(parseOffset, + invocationOffset - parseOffset); + } catch (BadLocationException e) { + QtUIPlugin.log(e); + } + + if (unparsed.length() > 0 && unparsed.charAt(0) == '(') + unparsed = unparsed.substring(1); + + int[] commas = computeCommaPositions(unparsed); + switch (commas.length) { + case 3: + completions.add(Completion.SIGNAL); + break; + case 5: + completions.add(Completion.SLOT); + break; + } + } else if (astNode.getPropertyInParent() == IASTFunctionCallExpression.ARGUMENT) { + IASTNode parent = astNode.getParent(); + if (!(parent instanceof IASTFunctionCallExpression)) + continue; + IASTFunctionCallExpression call = (IASTFunctionCallExpression) parent; + IASTExpression nameExpr = call.getFunctionNameExpression(); + if (!(nameExpr instanceof IASTIdExpression)) + continue; + IASTIdExpression funcNameIdExpr = (IASTIdExpression) nameExpr; + IASTName funcName = funcNameIdExpr.getName(); + + if (!is_QObject_connect(context, astContext, funcName)) + continue; + + IASTInitializerClause[] args = call.getArguments(); + switch (args.length) { + case 2: + addCompletionsFor(completions, args[0], + MethodFilter.Qt.Signal); + break; + case 4: + addCompletionsFor(completions, args[2], + MethodFilter.Qt.Slot); + break; + } + } + } + + for (Completion completion : completions) { + ICompletionProposal proposal = completion.createProposal(context); + if (proposal != null) + proposals.add(proposal); + } + } + + @Override + protected List computeCompletionProposals( + CContentAssistInvocationContext context, + IASTCompletionNode completionNode, String prefix) + throws CoreException { + if (!isApplicable(context)) + return Collections.emptyList(); + + List proposals = new ArrayList(); + addConnectParameterCompletions(proposals, context, completionNode, + prefix); + return proposals; + } +} 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 deleted file mode 100644 index 2e6e6d53823..00000000000 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (c) 2013 QNX Software Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ - -package org.eclipse.cdt.qt.internal.ui; - -import java.util.ArrayList; -import java.util.Collection; -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.core.dom.ast.ASTTypeUtil; -import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; -import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; -import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; -import org.eclipse.cdt.core.dom.ast.IASTIdExpression; -import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; -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.IPointerType; -import org.eclipse.cdt.core.dom.ast.IType; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; -import org.eclipse.cdt.core.dom.ast.tag.ITag; -import org.eclipse.cdt.core.dom.ast.tag.ITagReader; -import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.core.model.ITranslationUnit; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; -import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal; -import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistInvocationContext; -import org.eclipse.cdt.internal.ui.text.contentassist.ParsingBasedProposalComputer; -import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants; -import org.eclipse.cdt.qt.core.QtKeywords; -import org.eclipse.cdt.qt.core.QtNature; -import org.eclipse.cdt.qt.core.QtPlugin; -import org.eclipse.cdt.ui.CUIPlugin; -import org.eclipse.cdt.ui.text.contentassist.ICEditorContentAssistInvocationContext; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.contentassist.ICompletionProposal; - -@SuppressWarnings("restriction") -public class QtCompletionProposalComputer extends ParsingBasedProposalComputer { - private boolean isApplicable(ICEditorContentAssistInvocationContext context) { - ITranslationUnit tu = context.getTranslationUnit(); - if (tu == null) - return false; - - ICProject cProject = tu.getCProject(); - if (cProject == null) - return false; - - IProject project = cProject.getProject(); - if (project == null) - return false; - - try { - return project.hasNature(QtNature.ID); - } catch (CoreException e) { - CUIPlugin.log(e); - return false; - } - } - - private static boolean is_QObject_connect( - ICEditorContentAssistInvocationContext context, - IASTCompletionContext astContext, IASTName name) { - IASTName connectName = name.getLastName(); - if (!QtKeywords.CONNECT.equals(new String(connectName.getSimpleID()))) - return false; - - IBinding[] funcBindings = astContext.findBindings(connectName, - !context.isContextInformationStyle()); - for (IBinding funcBinding : funcBindings) - if (funcBinding instanceof ICPPFunction) { - IBinding ownerBinding = ((ICPPFunction) funcBinding).getOwner(); - if (ownerBinding != null - && QtKeywords.QOBJECT.equals(ownerBinding.getName())) - return true; - } - - return false; - } - - private static class Completion { - private final String replacement; - private final String display; - private final int cursorOffset; - - public static final Completion SIGNAL = new Completion("SIGNAL()", - "SIGNAL(a)", -1); - public static final Completion SLOT = new Completion("SLOT()", - "SLOT(a)", -1); - - public Completion(String replacement) { - this(replacement, replacement, 0); - } - - public Completion(String replacement, String display, int cursorOffset) { - this.replacement = replacement; - this.display = display; - this.cursorOffset = cursorOffset; - } - - public ICompletionProposal createProposal( - ICEditorContentAssistInvocationContext context) { - int repLength = replacement.length(); - int repOffset = context.getInvocationOffset(); - CCompletionProposal p = new CCompletionProposal(replacement, - repOffset, repLength, null, display, - RelevanceConstants.DEFAULT_TYPE_RELEVANCE, - context.getViewer()); - p.setCursorPosition(repLength + cursorOffset); - return p; - } - - @Override - public String toString() { - if (replacement == null) - return super.toString(); - return replacement + '@' + cursorOffset; - } - } - - private static interface MethodFilter { - public boolean keep(ICPPMethod method); - - public static class Qt { - public static final MethodFilter Signal = new MethodFilter() { - @Override - public boolean keep(ICPPMethod method) { - ITagReader tagReader = CCorePlugin.getTagService() - .findTagReader(method); - if (tagReader == null) - return false; - - ITag tag = tagReader.getTag(QtPlugin.SIGNAL_SLOT_TAGGER_ID); - if (tag == null) - return false; - - int result = tag.getByte(0); - return result != ITag.FAIL - && ((result & QtPlugin.SignalSlot_Mask_signal) == QtPlugin.SignalSlot_Mask_signal); - } - }; - - public static final MethodFilter Slot = new MethodFilter() { - @Override - public boolean keep(ICPPMethod method) { - ITagReader tagReader = CCorePlugin.getTagService() - .findTagReader(method); - if (tagReader == null) - return false; - - ITag tag = tagReader.getTag(QtPlugin.SIGNAL_SLOT_TAGGER_ID); - if (tag == null) - return false; - - int result = tag.getByte(0); - return result != ITag.FAIL - && ((result & QtPlugin.SignalSlot_Mask_slot) == QtPlugin.SignalSlot_Mask_slot); - } - }; - } - } - - private static Iterable filterMethods(final ICPPClassType cls, - final MethodFilter filter) { - return new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - private int index = 0; - private final ICPPMethod[] methods = cls.getMethods(); - - @Override - public boolean hasNext() { - for (; index < methods.length; ++index) - if (filter.keep(methods[index])) - return true; - return false; - } - - @Override - public ICPPMethod next() { - return methods[index++]; - } - - @Override - public void remove() { - } - }; - } - }; - } - - private static String getSignature(ICPPMethod method) { - StringBuilder signature = new StringBuilder(); - - signature.append(method.getName()); - signature.append('('); - boolean first = true; - for (ICPPParameter param : method.getParameters()) { - if (first) - first = false; - else - signature.append(", "); - signature.append(ASTTypeUtil.getType(param.getType())); - } - - signature.append(')'); - return signature.toString(); - } - - private static void addCompletionsFor(Collection completions, - IASTInitializerClause init, MethodFilter filter) { - if (!(init instanceof ICPPASTInitializerClause)) - return; - - ICPPEvaluation eval = ((ICPPASTInitializerClause) init).getEvaluation(); - if (eval == null) - return; - - IType type = eval.getTypeOrFunctionSet(init); - while (type instanceof IPointerType) - type = ((IPointerType) type).getType(); - - if (type instanceof ICPPClassType) - for (ICPPMethod signal : filterMethods((ICPPClassType) type, filter)) - completions.add(new Completion(getSignature(signal))); - } - - // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator - private static int indexOfClosingPeer(String code, char left, char right, - int pos) { - int level = 0; - final int length = code.length(); - while (pos < length) { - char ch = code.charAt(pos); - if (ch == left) { - ++level; - } else if (ch == right) { - if (--level == 0) { - return pos; - } - } - ++pos; - } - return -1; - } - - // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator - private static int[] computeCommaPositions(String code) { - final int length = code.length(); - int pos = 0; - List positions = new ArrayList(); - positions.add(new Integer(-1)); - while (pos < length && pos != -1) { - char ch = code.charAt(pos); - switch (ch) { - case ',': - positions.add(new Integer(pos)); - break; - case '(': - pos = indexOfClosingPeer(code, '(', ')', pos); - break; - case '<': - pos = indexOfClosingPeer(code, '<', '>', pos); - break; - case '[': - pos = indexOfClosingPeer(code, '[', ']', pos); - break; - default: - break; - } - if (pos != -1) - pos++; - } - positions.add(new Integer(length)); - - int[] fields = new int[positions.size()]; - for (int i = 0; i < fields.length; i++) - fields[i] = positions.get(i).intValue(); - return fields; - } - - private void addConnectParameterCompletions( - List proposals, - ICEditorContentAssistInvocationContext context, - IASTCompletionNode completionNode, String prefix) { - IASTName[] names = completionNode.getNames(); - List completions = new LinkedList(); - - for (IASTName name : names) { - // The node isn't properly hooked up, must have backtracked out of - // this node - if (name.getTranslationUnit() == null) - continue; - - IASTCompletionContext astContext = name.getCompletionContext(); - if (astContext == null || !(astContext instanceof IASTNode)) - continue; - IASTNode astNode = (IASTNode) astContext; - - if (is_QObject_connect(context, astContext, name)) { - int parseOffset = context.getParseOffset(); - int invocationOffset = context.getInvocationOffset(); - - String unparsed = ""; - try { - unparsed = context.getDocument().get(parseOffset, - invocationOffset - parseOffset); - } catch (BadLocationException e) { - CCorePlugin.log(e); - } - - if (unparsed.length() > 0 && unparsed.charAt(0) == '(') - unparsed = unparsed.substring(1); - - int[] commas = computeCommaPositions(unparsed); - switch (commas.length) { - case 3: - completions.add(Completion.SIGNAL); - break; - case 5: - completions.add(Completion.SLOT); - break; - } - } else if (astNode.getPropertyInParent() == IASTFunctionCallExpression.ARGUMENT) { - IASTNode parent = astNode.getParent(); - if (!(parent instanceof IASTFunctionCallExpression)) - continue; - IASTFunctionCallExpression call = (IASTFunctionCallExpression) parent; - IASTExpression nameExpr = call.getFunctionNameExpression(); - if (!(nameExpr instanceof IASTIdExpression)) - continue; - IASTIdExpression funcNameIdExpr = (IASTIdExpression) nameExpr; - IASTName funcName = funcNameIdExpr.getName(); - - if (!is_QObject_connect(context, astContext, funcName)) - continue; - - IASTInitializerClause[] args = call.getArguments(); - switch (args.length) { - case 2: - addCompletionsFor(completions, args[0], - MethodFilter.Qt.Signal); - break; - case 4: - addCompletionsFor(completions, args[2], - MethodFilter.Qt.Slot); - break; - } - } - } - - for (Completion completion : completions) { - ICompletionProposal proposal = completion.createProposal(context); - if (proposal != null) - proposals.add(proposal); - } - } - - @Override - protected List computeCompletionProposals( - CContentAssistInvocationContext context, - IASTCompletionNode completionNode, String prefix) - throws CoreException { - if (!isApplicable(context)) - return Collections.emptyList(); - - List proposals = new ArrayList(); - addConnectParameterCompletions(proposals, context, completionNode, - prefix); - return proposals; - } -} diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java index a8fab56b811..a24fb4de002 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java @@ -7,6 +7,10 @@ */ package org.eclipse.cdt.qt.ui; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; @@ -56,4 +60,45 @@ public class QtUIPlugin extends AbstractUIPlugin { return plugin; } + public static CoreException coreException(String msg) { + return new CoreException(new Status(IStatus.INFO, PLUGIN_ID, msg)); + } + + public static IStatus info(String msg) { + return new Status(IStatus.INFO, PLUGIN_ID, msg); + } + + public static IStatus error(String msg) { + return error(msg, null); + } + + public static IStatus error(String msg, Throwable e) { + return new Status(IStatus.ERROR, PLUGIN_ID, msg, e); + } + + public static void log(String e) { + log(IStatus.INFO, e, null); + } + + public static void log(Throwable e) { + String msg= e.getMessage(); + if (msg == null) { + log("Error", e); //$NON-NLS-1$ + } else { + log("Error: " + msg, e); //$NON-NLS-1$ + } + } + + public static void log(String message, Throwable e) { + Throwable nestedException; + if (e instanceof CModelException + && (nestedException = ((CModelException)e).getException()) != null) { + e = nestedException; + } + log(IStatus.ERROR, message, e); + } + + public static void log(int code, String msg, Throwable e) { + getDefault().getLog().log(new Status(code, PLUGIN_ID, msg, e)); + } } -- cgit v1.2.3