1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 422841: Add QEnum to QtIndex

The Qt meta-object system allows C++ enums to be added as simple enums
and as flags.  There is more detail at:

    http://qt-project.org/doc/qt-4.8/qobject.html#Q_ENUMS
and http://qt-project.org/doc/qt-4.8/qflags.html

This patch adds IQEnum to the QtIndex.  IQEnums are contained in
IQObjects and therefore are accessed with the IQObject.getEnums.

An IQEnum holds its name, enumerators, and a boolean indicating whether
the instance represents a Qt flag.

A Qt flag is an enum where the enumerators are intended to be used with
bitwise operations.  The Q_DECLARE_FLAGS macro is used to introduce a
type-safe container for the flags.

This patch also adds unit tests for this new functionality.

Change-Id: If51524e93533bae82a3263f3c7973a31793a8a83
Signed-off-by: Andrew Eidsness <eclipse@jfront.com>
Reviewed-on: https://git.eclipse.org/r/19147
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
Tested-by: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
Andrew Eidsness 2013-11-29 15:09:55 -05:00 committed by Doug Schaefer
parent dc746352a3
commit 0f482a80b2
11 changed files with 812 additions and 19 deletions

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.cdt.qt.core.index;
import java.util.Collection;
/**
* Represents expansions of the Q_ENUMS macro within a class declaration.
* <pre>
* class B : public QObject
* {
* Q_OBJECT
* enum E { enumerator };
* Q_ENUMS( E )
* };
*
* class Q : public QObject
* {
* Q_OBJECT
* Q_ENUMS( B::E E0 )
* Q_ENUMS( E1 )
* enum E0 { e0a, e0b = 2 };
* enum E1 { e1 };
* }
* </pre>
* NOTE: http://qt-project.org/doc/qt-4.8/qobject.html#Q_ENUMS
* <blockquote>
* If you want to register an enum that is declared in another class, the enum must be fully qualified
* with the name of the class defining it. In addition, the class defining the enum has to inherit
* QObject as well as declare the enum using Q_ENUMS().
* </blockquote>
* So, the lookup for the C++ enum only needs to look in the same class spec when the name is not
* qualified. When it is qualified, then it needs to find the QObject and then look at its Q_ENUMS.
*/
public interface IQEnum {
/**
* Returns the name of the enumerator as referenced in parameter in the Q_ENUMS
* macro expansion. In the sample code in the class declaration, this would return
* "B::E", "E0", or "E1".
*/
public String getName();
/**
* Returns true if this enumeration was introduced to the Qt meta-object system with
* a Q_FLAGS expansion and false if it was introduced with Q_ENUMS.
*/
public boolean isFlag();
/**
* Returns an unsorted collection of the enumerators contained in the enum references
* in the Q_ENUMS macro expansion.
* <p>
* NOTE: It would be nice if the textual order of the enumerators was preserved by the
* underlying CDT index, but it is not. The {@link Enumerator#getOrdinal()} method can
* be used to recover some ordering information.
*/
public Collection<Enumerator> getEnumerators();
/**
* A small wrapper class for the enumerators that are declared within the enum that is
* referenced by the parameter of the Q_ENUMS macro expansion.
*/
public interface Enumerator {
/**
* Returns the name of the enumerator.
*/
public String getName();
/**
* Returns the ordinal (either explicitly or implicitly) assigned to the enumerator.
*/
public Long getOrdinal();
}
}

View file

@ -7,6 +7,7 @@
*/
package org.eclipse.cdt.qt.core.index;
import java.util.Collection;
import java.util.List;
/**
@ -36,4 +37,11 @@ public interface IQObject extends IQElement {
* base classes.
*/
public List<IQObject> getBases();
/**
* Returns an unsorted collection of all Q_ENUMS macro expansions within this QObject's class
* declaration.
* @see IQEnum
*/
public Collection<IQEnum> getEnums();
}

View file

@ -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.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<IQEnum.Enumerator> enumerators;
public QEnum(String name, boolean isFlag, List<IEnumerator> enumerators) {
this.name = name;
this.isFlag = isFlag;
this.enumerators = new ArrayList<IQEnum.Enumerator>(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<IQEnum.Enumerator> 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;
}
}
}

View file

@ -8,10 +8,14 @@
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.IBinding;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.qt.core.index.IQEnum;
import org.eclipse.cdt.qt.core.index.IQObject;
import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQEnum;
import org.eclipse.cdt.qt.internal.core.pdom.QtPDOMQObject;
import org.eclipse.core.runtime.CoreException;
@ -20,6 +24,7 @@ public class QObject implements IQObject {
private final String name;
private final QtPDOMQObject pdomQObject;
private final List<IQObject> bases;
private final List<IQEnum> enums;
public QObject(QtIndexImpl qtIndex, CDTIndex cdtIndex, QtPDOMQObject pdomQObject) throws CoreException {
this.name = pdomQObject.getName();
@ -28,6 +33,13 @@ public class QObject implements IQObject {
this.bases = new ArrayList<IQObject>();
for(QtPDOMQObject base : pdomQObject.findBases())
this.bases.add(new QObject(qtIndex, cdtIndex, base));
this.enums = new ArrayList<IQEnum>();
for(IField field : pdomQObject.getFields())
if (field instanceof QtPDOMQEnum) {
QtPDOMQEnum qEnum = (QtPDOMQEnum) field;
this.enums.add(new QEnum(field.getName(), qEnum.isFlag(), qEnum.getEnumerators()));
}
}
@Override
@ -44,4 +56,9 @@ public class QObject implements IQObject {
public List<IQObject> getBases() {
return bases;
}
@Override
public Collection<IQEnum> getEnums() {
return enums;
}
}

View file

@ -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.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,
*
* <pre>
* MACRO( expansionParameter )
* ^ ^ ^ c: end of reference name
* | +----------------- b: start of reference name
* +------------------------ a: start of macro expansion
* </pre>
*
* 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;
}
}

View file

@ -7,14 +7,26 @@
*/
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.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
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.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
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;
@ -24,6 +36,11 @@ 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*\\((.*)\\)$");
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*\\)$");
public QtASTVisitor(IIndexSymbols symbols, LocationMap locationMap) {
shouldVisitDeclSpecifiers = true;
@ -31,24 +48,6 @@ public class QtASTVisitor extends ASTVisitor {
this.locationMap = locationMap;
}
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 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);
}
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
@ -65,4 +64,108 @@ public class QtASTVisitor extends ASTVisitor {
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<String, String> 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 = null;
if (binding instanceof ICPPInternalBinding) {
IASTNode node = ((ICPPInternalBinding) binding).getDefinition();
cppName = node instanceof IASTName ? (IASTName) node : null;
}
QtEnumName astName = new QtEnumName(qobjName, refName, name, cppName, location, isFlag);
symbols.add(owner, astName, qobjName);
if (cppName != null)
symbols.add(owner, new ASTDelegatedName.Reference(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);
// 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 the those lists are uses to create
// the QEnum instances.
List<EnumDecl> enumDecls = new ArrayList<QtASTVisitor.EnumDecl>();
Map<String, String> flagAliases = new HashMap<String, String>();
for (IASTPreprocessorMacroExpansion expansion : expansions) {
String macroName = String.valueOf(expansion.getMacroReference());
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);
}
}
}
for(EnumDecl decl : enumDecls)
decl.handle(owner, spec, qobjName, flagAliases);
}
private void extractEnumDecls(IASTPreprocessorMacroExpansion expansion, boolean isFlag, List<EnumDecl> 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));
}
}
}

View file

@ -0,0 +1,135 @@
/*
* 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.core.dom.ast.IBinding;
import org.eclipse.cdt.internal.core.dom.Linkage;
@SuppressWarnings("restriction")
public class QtEnumName extends ASTDelegatedName {
private final QObjectName qobjName;
private final String qtEnumName;
private final IASTName cppEnumName;
private final QtASTImageLocation location;
private final boolean isFlag;
private ASTNodeProperty propertyInParent;
public QtEnumName(QObjectName qobjName, IASTName ast, String qtEnumName, IASTName cppEnumName, QtASTImageLocation location, boolean isFlag) {
super(ast);
this.qobjName = qobjName;
this.qtEnumName = qtEnumName;
this.cppEnumName = cppEnumName;
this.location = location;
this.isFlag = isFlag;
}
public boolean isFlag() {
return isFlag;
}
@Override
protected IBinding createBinding() {
IBinding owner = qobjName.getBinding();
QtBinding qobj = owner == null ? null : (QtBinding) owner.getAdapter(QtBinding.class);
return new QtBinding(QtPDOMNodeType.QEnum, qobj, this, cppEnumName);
}
@Override
public IASTFileLocation getFileLocation() {
return location;
}
@Override
public IASTNode getParent() {
return qobjName;
}
@Override
public IASTNode[] getChildren() {
return IASTNode.EMPTY_NODE_ARRAY;
}
@Override
public void setParent(IASTNode node) {
throw new IllegalStateException("attempt to modify parent of Qt Enum"); //$NON-NLS-1$
}
@Override
public ASTNodeProperty getPropertyInParent() {
return propertyInParent;
}
@Override
public void setPropertyInParent(ASTNodeProperty property) {
propertyInParent = property;
}
@Override
public char[] getSimpleID() {
return qtEnumName.toCharArray();
}
@Override
public String getRawSignature() {
return qtEnumName;
}
@Override
public IASTNode getOriginalNode() {
return this;
}
@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) {
return new QtEnumName(qobjName, delegate, qtEnumName, cppEnumName, location, isFlag);
}
}

View file

@ -130,6 +130,9 @@ public class QtPDOMLinkage extends PDOMLinkage {
case QObject:
pdomBinding = new QtPDOMQObject(this, qtBinding);
break;
case QEnum:
pdomBinding = new QtPDOMQEnum(this, adaptBinding(qtBinding.getOwner()), qtBinding);
break;
}
// If a PDOMBinding was created, then add it to the linkage before returning it.

View file

@ -14,7 +14,8 @@ import org.eclipse.core.runtime.CoreException;
@SuppressWarnings("restriction")
public enum QtPDOMNodeType {
QObject;
QObject,
QEnum;
public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal();
@ -45,6 +46,8 @@ public enum QtPDOMNodeType {
switch(node) {
case QObject:
return new QtPDOMQObject(linkage, record);
case QEnum:
return new QtPDOMQEnum(linkage, record);
}
return null;

View file

@ -0,0 +1,159 @@
/*
* 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.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.qt.core.QtPlugin;
import org.eclipse.core.runtime.CoreException;
@SuppressWarnings("restriction")
public class QtPDOMQEnum extends QtPDOMBinding implements IField {
private static int offsetInitializer = QtPDOMBinding.Field.Last.offset;
protected static enum Field {
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 IS_FLAG_MASK = 1;
private QtPDOMQObject qobj;
protected QtPDOMQEnum(QtPDOMLinkage linkage, long record) throws CoreException {
super(linkage, record);
}
public QtPDOMQEnum(QtPDOMLinkage linkage, PDOMBinding parent, QtBinding binding) throws CoreException {
super(linkage, parent, binding);
// The flags are set in several sections, and then written to the Database in one operation.
byte flags = 0;
IASTName qtName = binding.getQtName();
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 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;
}
@Override
public ICompositeType getCompositeTypeOwner() {
if (qobj == null)
try {
IBinding parent = getParentBinding();
if (parent instanceof QtPDOMQObject)
qobj = (QtPDOMQObject) parent;
} catch(CoreException e) {
QtPlugin.log(e);
}
return qobj;
}
public List<IEnumerator> getEnumerators() throws CoreException {
IBinding cppBinding = getCppBinding();
if (!(cppBinding instanceof IEnumeration))
return Collections.emptyList();
IEnumeration cppEnum = (IEnumeration) cppBinding;
return Arrays.asList(cppEnum.getEnumerators());
}
/**
* A singleton that is used as the type for all instances of the QtEnum.
*/
private static final IType Type = new IType() {
@Override
public Object clone() {
// This is a stateless singleton instance, there is nothing to clone.
return this;
}
@Override
public boolean isSameType(IType type) {
return type == this;
}
};
@Override
public IType getType() {
return Type;
}
@Override
public IValue getInitialValue() {
return null;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isExtern() {
return false;
}
@Override
public boolean isAuto() {
return false;
}
@Override
public boolean isRegister() {
return false;
}
}

View file

@ -10,6 +10,7 @@ package org.eclipse.cdt.qt.tests;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.cdt.qt.core.index.IQEnum;
import org.eclipse.cdt.qt.core.index.IQObject;
import org.eclipse.cdt.qt.core.index.QtIndex;
@ -46,4 +47,132 @@ public class QObjectTests extends BaseQtTestCase {
IQObject qobj_D2 = qtIndex.findQObject(new String[]{ "D2" });
assertNull(qobj_D2);
}
// #include "junit-QObject.hh"
// template <typename T> class QList {};
// class QString {};
// class Q0 : public QObject
// {
// Q_OBJECT
// public:
// enum EB { eb0 = 0xff };
// };
// class Q : public QObject
// {
// Q_OBJECT
//
// enum E0 { e0a, e0b };
//
// Q_ENUMS( E0 Q0::EB )
// Q_ENUMS( E1 )
//
// enum E1 { e1a, e1b = 2 };
// };
public void testEnums() throws Exception {
loadComment("qenums.hh");
QtIndex qtIndex = QtIndex.getIndex(fProject);
assertNotNull(qtIndex);
IQObject qobj = qtIndex.findQObject(new String[]{ "Q" });
if (!isIndexOk("Q", qobj))
return;
assertNotNull(qobj);
Collection<IQEnum> qEnums = qobj.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("Q0::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"
// template <typename T> class QList {};
// class Q : public QObject
// {
// Q_OBJECT
// 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("qflags.hh");
QtIndex qtIndex = QtIndex.getIndex(fProject);
assertNotNull(qtIndex);
IQObject qobj = qtIndex.findQObject(new String[]{ "Q" });
if (!isIndexOk("Q", qobj))
return;
assertNotNull(qobj);
Collection<IQEnum> qEnums = qobj.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());
}
}
}