diff options
18 files changed, 626 insertions, 182 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 09a799d0892..ef743880d95 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -245,10 +245,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 160.0 - Store specialized template parameters of class/function template specializations, bug 407497. * 161.0 - Allow reference to PDOMBinding from other PDOMLinkages, bug 422681. * 162.0 - PDOMNode now stores the factoryId for loading, bug 422681. + * 163.0 - QtLinkage changed storage format of QObject to accommodate QGadget. */ - private static final int MIN_SUPPORTED_VERSION= version(162, 0); - private static final int MAX_SUPPORTED_VERSION= version(162, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(162, 0); + private static final int MIN_SUPPORTED_VERSION= version(163, 0); + private static final int MAX_SUPPORTED_VERSION= version(163, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(163, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QGadget.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QGadget.java new file mode 100644 index 00000000000..c88d4f7e206 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/index/QGadget.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 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.internal.qt.core.pdom.QtPDOMQEnum; +import org.eclipse.cdt.internal.qt.core.pdom.AbstractQtPDOMClass; +import org.eclipse.cdt.qt.core.index.IQEnum; +import org.eclipse.cdt.qt.core.index.IQGadget; +import org.eclipse.core.runtime.CoreException; + +public class QGadget implements IQGadget { + + private final String name; + private final List<IQEnum> enums; + + public QGadget(QtIndexImpl qtIndex, CDTIndex cdtIndex, AbstractQtPDOMClass pdomQGadget) throws CoreException { + this.name = pdomQGadget.getName(); + + this.enums = new ArrayList<IQEnum>(); + for(QtPDOMQEnum pdom : pdomQGadget.getChildren(QtPDOMQEnum.class)) + this.enums.add(new QEnum(pdom.getName(), pdom.isFlag(), pdom.getEnumerators())); + } + + @Override + public String getName() { + return name; + } + + @Override + public Collection<IQEnum> getEnums() { + return enums; + } +} 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 index 7390f91d368..9bc3f02bd72 100644 --- 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 @@ -12,7 +12,9 @@ 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.AbstractQtPDOMClass; import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQObject; +import org.eclipse.cdt.qt.core.index.IQGadget; import org.eclipse.cdt.qt.core.index.IQObject; import org.eclipse.cdt.qt.core.index.QtIndex; import org.eclipse.core.runtime.CoreException; @@ -42,6 +44,11 @@ public class QtIndexImpl extends QtIndex { return name == null ? null : cdtIndex.get(new QObjectImplAccessor(name)); } + @Override + public IQGadget findQGadget(String[] name) { + return name == null ? null : cdtIndex.get(new QGadgetImplAccessor(name)); + } + private class QObjectImplAccessor implements CDTIndex.Accessor<IQObject> { private final char[][] name; @@ -63,4 +70,26 @@ public class QtIndexImpl extends QtIndex { return null; } } + + private class QGadgetImplAccessor implements CDTIndex.Accessor<IQGadget> { + + private final char[][] name; + + public QGadgetImplAccessor(String[] qualName) { + name = new char[qualName.length][]; + for(int i = 0; i < name.length; ++i) + name[i] = qualName[i].toCharArray(); + } + + @Override + public IQGadget access(IIndex index) throws CoreException { + + // TODO can there be more than one result? + for(IIndexBinding binding : index.findBindings(name, QtLinkageFilter, null)) + if (binding instanceof AbstractQtPDOMClass) + return new QGadget(QtIndexImpl.this, cdtIndex, (AbstractQtPDOMClass) binding); + + return null; + } + } } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQClassName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQClassName.java new file mode 100644 index 00000000000..1474f8e25d0 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQClassName.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014 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.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; + +/** + * Qt provides two types of annotations for C++ classes (Q_GADGET and Q_OBJECT). This + * class. This class is used to store the common parts of these Qt classes to the + * Qt linkage. + */ +@SuppressWarnings("restriction") +public abstract class AbstractQClassName extends ASTDelegatedName implements IQtASTName { + + private final ICPPASTCompositeTypeSpecifier spec; + + private IASTNode parent; + private ASTNodeProperty propertyInParent; + + public AbstractQClassName(ICPPASTCompositeTypeSpecifier spec) { + super(spec.getName()); + this.spec = spec; + this.parent = delegate.getParent(); + this.propertyInParent = delegate.getPropertyInParent(); + } + + protected abstract QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage, IASTName name) throws CoreException; + protected abstract IASTName copy(CopyStyle style, ICPPASTCompositeTypeSpecifier spec); + + @Override + public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException { + return createPDOMBinding(linkage, 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 copy(style, spec); + } +} 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 index edc404fa52c..db3352f6f5e 100644 --- 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 @@ -21,12 +21,12 @@ import org.eclipse.core.runtime.CoreException; @SuppressWarnings("restriction") public abstract class AbstractQObjectMemberName extends ASTDelegatedName { - private final QObjectName owner; + private final IQtASTName owner; private final String name; private final IASTImageLocation location; private ASTNodeProperty propertyInParent; - protected AbstractQObjectMemberName(QObjectName owner, IASTName ast, String name, IASTImageLocation location) { + protected AbstractQObjectMemberName(IQtASTName owner, IASTName ast, String name, IASTImageLocation location) { super(ast); this.owner = owner; this.name = name; diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQtPDOMClass.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQtPDOMClass.java new file mode 100644 index 00000000000..474e8300fb7 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/AbstractQtPDOMClass.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 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.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.IBinding; +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; + +/** + * Qt has two types of annotation that can be applied to classes (Q_GADGET and G_OBJECT). + * This class stores the information that is common to each. + */ +@SuppressWarnings("restriction") +public abstract class AbstractQtPDOMClass extends QtPDOMBinding { + + private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + protected static enum Field { + CppRecord(Database.PTR_SIZE), + Children(4 /* From PDOMNodeLinkedList.RECORD_SIZE, which is protected */), + Last(0); + + public final int offset; + + private Field(int sizeof) { + this.offset = offsetInitializer; + offsetInitializer += sizeof; + } + + public long getRecord(long baseRec) { + return baseRec + offset; + } + } + + private final PDOMNodeLinkedList children; + + protected AbstractQtPDOMClass(QtPDOMLinkage linkage, long record) throws CoreException { + super(linkage, record); + children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record)); + } + + public AbstractQtPDOMClass(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)); + } + + 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; + } + + @Override + protected int getRecordSize() { + return Field.Last.offset; + } + + // 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(); + } + + @Override + public void addChild(PDOMNode child) throws CoreException { + children.addMember(child); + } + + public <T extends QtPDOMBinding> List<T> getChildren(Class<T> cls) throws CoreException { + QtPDOMVisitor.All<T> collector = new QtPDOMVisitor.All<T>(cls); + try { + children.accept(collector); + } catch(CoreException e) { + QtPlugin.log(e); + return Collections.emptyList(); + } + + return collector.list; + } +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QGadgetName.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QGadgetName.java new file mode 100644 index 00000000000..22b670838c0 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QGadgetName.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 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.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.core.runtime.CoreException; + +/** + * QGadgets are C++ classes that have been annotated with Qt marker macros. This class is + * used to introduce the QGadget to the Qt linkage. The only feature of Q_GADGET is the + * ability to host Q_ENUMs. + */ +public class QGadgetName extends AbstractQClassName { + + public QGadgetName(ICPPASTCompositeTypeSpecifier spec) { + super(spec); + } + + @Override + protected QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage, IASTName name) throws CoreException { + return new QtPDOMQGadget(linkage, this, name); + } + + @Override + protected IASTName copy(CopyStyle style, ICPPASTCompositeTypeSpecifier spec) { + return new QGadgetName(spec); + } +} 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 index 06544b49b38..d1d78258046 100644 --- 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 @@ -12,35 +12,21 @@ 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 { +public class QObjectName extends AbstractQClassName { - private final ICPPASTCompositeTypeSpecifier spec; private final List<QtPropertyName> properties = new ArrayList<QtPropertyName>(); private final Map<String, String> classInfos = new LinkedHashMap<String, String>(); - private IASTNode parent; - private ASTNodeProperty propertyInParent; - public QObjectName(ICPPASTCompositeTypeSpecifier spec) { - super(spec.getName()); - this.spec = spec; - this.parent = delegate.getParent(); - this.propertyInParent = delegate.getPropertyInParent(); + super(spec); } public List<QtPropertyName> getProperties() { @@ -60,62 +46,12 @@ public class QObjectName extends ASTDelegatedName implements IQtASTName { } @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); + protected QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage, IASTName name) throws CoreException { + return new QtPDOMQObject(linkage, this, name); } @Override - public IASTName copy(CopyStyle style) { + protected IASTName copy(CopyStyle style, ICPPASTCompositeTypeSpecifier spec) { return new QObjectName(spec); } } 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 index 7fd1918aaa7..1629f2b341f 100644 --- 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 @@ -114,6 +114,8 @@ public class QtASTVisitor extends ASTVisitor { if (isQObject(spec, expansions)) handleQObject(owner, spec, expansions); + if (isQGadget(spec, expansions)) + handleQClass(owner, spec, new QGadgetName(spec), expansions); } return super.visit(declSpec); @@ -148,6 +150,18 @@ public class QtASTVisitor extends ASTVisitor { return false; } + private boolean isQGadget(ICPPASTCompositeTypeSpecifier spec, IASTPreprocessorMacroExpansion[] expansions) { + + // The class definition must contain a Q_GADGET expansion. + for (IASTPreprocessorMacroExpansion expansion : expansions) { + IASTPreprocessorMacroDefinition macro = expansion.getMacroDefinition(); + if (QtKeywords.Q_GADGET.equals(String.valueOf(macro.getName()))) + return true; + } + + return false; + } + private class EnumDecl { private final String name; private final boolean isFlag; @@ -161,7 +175,7 @@ public class QtASTVisitor extends ASTVisitor { this.location = new QtASTImageLocation(refName.getFileLocation(), offset, length); } - public void handle(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, QObjectName qobjName, Map<String, String> aliases) { + public void handle(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, IQtASTName qobjName, Map<String, String> aliases) { String alias = aliases.get(name); @@ -182,10 +196,37 @@ public class QtASTVisitor extends ASTVisitor { // Put the QObject into the symbol map. QObjectName qobjName = new QObjectName(spec); - symbols.add(owner, qobjName, null); + handleQClass(owner, spec, qobjName, expansions); + + 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_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); + } - // The QObject contains a reference to the C++ class that it annotates. - symbols.add(owner, new ASTNameReference(spec.getName()), qobjName); + // Process the slot, signal, and invokable method declarations. + extractQMethods(owner, spec, qobjName); + } + + private void handleQClass(IASTPreprocessorIncludeStatement owner, ICPPASTCompositeTypeSpecifier spec, IQtASTName qtName, IASTPreprocessorMacroExpansion[] expansions) { + + // Put the Qt name into the symbol map. + symbols.add(owner, qtName, null); + + // The QClass contains a reference to the C++ class that it annotates. + symbols.add(owner, new ASTNameReference(spec.getName()), qtName); // 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 @@ -213,22 +254,11 @@ public class QtASTVisitor extends ASTVisitor { 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); + decl.handle(owner, spec, qtName, flagAliases); } private void extractEnumDecls(IASTPreprocessorMacroExpansion expansion, boolean isFlag, List<EnumDecl> decls) { 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 index 77a98b2f217..edefd269ac9 100644 --- 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 @@ -15,7 +15,7 @@ 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) { + public QtEnumName(IQtASTName qobjName, IASTName ast, String qtEnumName, IASTName cppEnumName, QtASTImageLocation location, boolean isFlag) { super(qobjName, ast, qtEnumName, location); this.cppEnumName = cppEnumName; this.isFlag = isFlag; 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 index f79c65749d4..0210e1d34c9 100644 --- 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 @@ -17,7 +17,8 @@ public enum QtPDOMNodeType { QObject, QEnum, QProperty, - QMethod; + QMethod, + QGadget; public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal(); @@ -27,8 +28,11 @@ public enum QtPDOMNodeType { * backward compatible when possible. * <p> * The version is needed because ordinals for these enumerators are written to the file. + * <p> + * This version can be reset when the PDOM's version changes because older Qt linkages will + * be dropped (along with everything else in that PDOM). */ - public static final int VERSION = 4; + public static final int VERSION = 1; public static QtPDOMNodeType forType(int version, int type) { // Nothing has been deleted or replaced yet, so the version is ignored. @@ -54,6 +58,8 @@ public enum QtPDOMNodeType { return new QtPDOMProperty(linkage, record); case QMethod: return new QtPDOMQMethod(linkage, record); + case QGadget: + return new QtPDOMQGadget(linkage, record); } return null; 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 index e17a61b36db..3130de9ded2 100644 --- 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 @@ -43,8 +43,6 @@ public class QtPDOMQEnum extends QtPDOMBinding { private static final int IS_FLAG_MASK = 1; - private QtPDOMQObject qobj; - protected QtPDOMQEnum(QtPDOMLinkage linkage, long record) throws CoreException { super(linkage, record); } @@ -64,12 +62,8 @@ public class QtPDOMQEnum extends QtPDOMBinding { // 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); - } + if(parent instanceof AbstractQtPDOMClass) + ((AbstractQtPDOMClass) parent).addChild(this); } @Override diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQGadget.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQGadget.java new file mode 100644 index 00000000000..a5f361fd233 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/pdom/QtPDOMQGadget.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 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 QtPDOMQGadget extends AbstractQtPDOMClass { + + protected QtPDOMQGadget(QtPDOMLinkage linkage, long record) throws CoreException { + super(linkage, record); + } + + public QtPDOMQGadget(QtPDOMLinkage linkage, IASTName qtName, IASTName cppName) throws CoreException { + super(linkage, qtName, cppName); + } + + @Override + public int getNodeType() { + return QtPDOMNodeType.QGadget.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 index ce599868cfd..b7d4016d40c 100644 --- 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 @@ -14,75 +14,40 @@ 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 { +public class QtPDOMQObject extends AbstractQtPDOMClass { - private static int offsetInitializer = QtPDOMBinding.Field.Last.offset; + private static int offsetInitializer = AbstractQtPDOMClass.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); + ClassInfos(Database.PTR_SIZE), + Last(0); - private final int offset; - private final int version; + public final int offset; - private Field(int sizeof, int version) { + private Field(int sizeof) { 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)); + super(linkage, qtName, cppName); if (qtName instanceof QObjectName) { QObjectName qobjName = (QObjectName) qtName; @@ -96,25 +61,8 @@ public class QtPDOMQObject extends QtPDOMBinding { 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<String, String> 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<Map.Entry<String, String>> iterator = classInfos.entrySet().iterator(); @@ -135,10 +83,6 @@ public class QtPDOMQObject extends QtPDOMBinding { public Map<String, String> getClassInfos() throws CoreException { Map<String, String> classInfos = new LinkedHashMap<String, String>(); - // 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<ClassInfo> pdomArray = new QtPDOMArray<QtPDOMQObject.ClassInfo>(getQtLinkage(), ClassInfo.Codec, arrayRec); @@ -193,23 +137,6 @@ public class QtPDOMQObject extends QtPDOMBinding { return bases; } - @Override - public void addChild(PDOMNode child) throws CoreException { - children.addMember(child); - } - - public <T extends QtPDOMBinding> List<T> getChildren(Class<T> cls) throws CoreException { - QtPDOMVisitor.All<T> collector = new QtPDOMVisitor.All<T>(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; diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/IQGadget.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/IQGadget.java new file mode 100644 index 00000000000..4271557f562 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/index/IQGadget.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 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.core.index; + +import java.util.Collection; + +/** + * Represents classes that have been tagged as Q_GADGETs. Q_GADGETs are normal + * C++ class declarations that have been tagged with the Q_GADGET macro and are + * therefore able to add enums and flags to the Qt meta-object system. + */ +public interface IQGadget { + /** + * Returns the name of the class. + */ + public String getName(); + + /** + * Returns an unsorted collection of all Q_ENUMS macro expansions within this QObject's class + * declaration. + * @see IQEnum + */ + public Collection<IQEnum> getEnums(); +} 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 eb8f3a8f1e4..f67a60bc583 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 @@ -62,4 +62,12 @@ public abstract class QtIndex { * the index does not have a subclass of QObject with the given name. */ public abstract IQObject findQObject(String[] qualifiedName); + + /** + * Find and return a class that has been marked with the Q_GADGET macro. These are + * normal C++ classes that are able to introduce Q_ENUMS and Q_FLAGS to the Qt + * meta-object system. Returns null if the index does not have a Q_GADGET with + * the given name. + */ + public abstract IQGadget findQGadget(String[] qualifiedName); } diff --git a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java index 6bae3815f45..e5504e0abba 100644 --- a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java +++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/AllQtTests.java @@ -16,6 +16,7 @@ public class AllQtTests extends TestSuite { return new TestSuite( QMakeTests.class, + QGadgetTests.class, QObjectTests.class, QtContentAssistantTests.class, QtIndexTests.class, diff --git a/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/QGadgetTests.java b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/QGadgetTests.java new file mode 100644 index 00000000000..4bc698e43d4 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.tests/src/org/eclipse/cdt/qt/tests/QGadgetTests.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2014 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.tests; + +import java.util.Collection; + +import org.eclipse.cdt.qt.core.index.IQEnum; +import org.eclipse.cdt.qt.core.index.IQGadget; +import org.eclipse.cdt.qt.core.index.QtIndex; + +public class QGadgetTests extends BaseQtTestCase { + + // #include "junit-QObject.hh" + // class G + // { + // Q_GADGET + // }; + public void testFindQGadget() throws Exception { + loadComment("qgadget.hh"); + + QtIndex qtIndex = QtIndex.getIndex(fProject); + assertNotNull(qtIndex); + + IQGadget qgadget = qtIndex.findQGadget(new String[]{ "G" }); + if (!isIndexOk("G", qgadget)) + return; + assertNotNull(qgadget); + + assertEquals("G", qgadget.getName()); + assertNotNull(qgadget.getEnums()); + assertEquals(0, qgadget.getEnums().size()); + } + + // #include "junit-QObject.hh" + // class G0 + // { + // Q_GADGET + // public: + // enum EB { eb0 = 0xff }; + // }; + // class G + // { + // Q_GADGET + // + // enum E0 { e0a, e0b }; + // + // Q_ENUMS( E0 G0::EB ) + // Q_ENUMS( E1 ) + // + // enum E1 { e1a, e1b = 2 }; + // }; + public void testEnums() throws Exception { + loadComment("qgadget_enums.hh"); + + QtIndex qtIndex = QtIndex.getIndex(fProject); + assertNotNull(qtIndex); + + IQGadget qgadget = qtIndex.findQGadget(new String[]{ "G" }); + if (!isIndexOk("G", qgadget)) + return; + assertNotNull(qgadget); + + Collection<IQEnum> qEnums = qgadget.getEnums(); + assertNotNull(qEnums); + assertEquals(3, qEnums.size()); + for(IQEnum qEnum : qEnums) { + String name = qEnum.getName(); + assertFalse(qEnum.isFlag()); + if ("E0".equals(name)) { + Collection<IQEnum.Enumerator> enumerators = qEnum.getEnumerators(); + assertNotNull(enumerators); + assertEquals(2, enumerators.size()); + for (IQEnum.Enumerator enumerator : enumerators) { + Long ordinal = enumerator.getOrdinal(); + if (Long.valueOf(0).equals(ordinal)) + assertEquals("e0a", enumerator.getName()); + else if (Long.valueOf(1).equals(ordinal)) + assertEquals("e0b", enumerator.getName()); + else + fail("unexpected " + name + "::" + enumerator.getName() + " = " + String.valueOf(ordinal)); + } + } else if("E1".equals(name)) { + Collection<IQEnum.Enumerator> enumerators = qEnum.getEnumerators(); + assertNotNull(enumerators); + assertEquals(2, enumerators.size()); + for (IQEnum.Enumerator enumerator : enumerators) { + Long ordinal = enumerator.getOrdinal(); + if (Long.valueOf(0).equals(ordinal)) + assertEquals("e1a", enumerator.getName()); + else if (Long.valueOf(2).equals(ordinal)) + assertEquals("e1b", enumerator.getName()); + else + fail("unexpected " + name + "::" + enumerator.getName() + " = " + String.valueOf(ordinal)); + } + } else if("G0::EB".equals(name)) { + Collection<IQEnum.Enumerator> enumerators = qEnum.getEnumerators(); + assertNotNull(enumerators); + assertEquals(1, enumerators.size()); + for (IQEnum.Enumerator enumerator : enumerators) { + Long ordinal = enumerator.getOrdinal(); + if (Long.valueOf(255).equals(ordinal)) + assertEquals("eb0", enumerator.getName()); + else + fail("unexpected " + name + "::" + enumerator.getName() + " = " + String.valueOf(ordinal)); + } + } else { + fail("unexpected Q_ENUM " + name); + } + } + } + + // #include "junit-QObject.hh" + // class G + // { + // Q_GADGET + // enum Enum { e0 }; + // Q_DECLARE_FLAGS(Flag, Enum) + // Q_FLAGS(Flag); + // enum Enum2 { e2 }; + // Q_FLAGS(Flag2); + // Q_DECLARE_FLAGS(Flag2, Enum2) + // Q_DECLARE_FLAGS(Flag2b, Enum2) + // enum Enum3 { e3 }; + // Q_DECLARE_FLAGS(Flag3, Enum3) + // }; + public void testFlags() throws Exception { + loadComment("qgadget_flags.hh"); + + QtIndex qtIndex = QtIndex.getIndex(fProject); + assertNotNull(qtIndex); + + IQGadget qgadget = qtIndex.findQGadget(new String[]{ "G" }); + if (!isIndexOk("G", qgadget)) + return; + assertNotNull(qgadget); + + Collection<IQEnum> qEnums = qgadget.getEnums(); + assertNotNull(qEnums); + assertEquals(2, qEnums.size()); + + for(IQEnum qEnum : qEnums) { + assertNotNull(qEnum); + assertTrue(qEnum.isFlag()); + if ("Flag".equals(qEnum.getName())) { + Collection<IQEnum.Enumerator> enumerators = qEnum.getEnumerators(); + assertNotNull(enumerators); + assertEquals(1, enumerators.size()); + assertEquals("e0", enumerators.iterator().next().getName()); + } else if("Flag2".equals(qEnum.getName())) { + Collection<IQEnum.Enumerator> enumerators = qEnum.getEnumerators(); + assertNotNull(enumerators); + assertEquals(1, enumerators.size()); + assertEquals("e2", enumerators.iterator().next().getName()); + } else + fail("unexpected Q_FLAGS " + qEnum.getName()); + } + } +} |