mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 09:46:02 +02:00
Bug 422841: Add Q_PROPERTY to the QtIndex
This extends IQObject so that it can return the list of Q_PROPERTY expansions. Each Q_PROPERTY is represented by the new IQProperty. The attributes of the property are stored in IQProperty.Attribute. Where applicable, the attributes insert a reference from the associated C++ binding. This means that the Q_PROPERTY expansion will be included in the list of references for the C++ binding. This also simplifies the process for adding new PDOMBindings to the Qt linkage. New instances are stored in an implementation of IQtASTName and able to directly create and return a new QtPDOMBinding. This avoids creating three parallel inheritance hierachies (compared to the previous Qt PDOM implementations). The patch includes test cases to check handling of Q_PROPERTY expansions. Change-Id: I7d256d1a938d24a9eb726c472fb150a02f26eb32 Signed-off-by: Andrew Eidsness <eclipse@jfront.com> Reviewed-on: https://git.eclipse.org/r/19602 Tested-by: Hudson CI Reviewed-by: Doug Schaefer <dschaefer@qnx.com> IP-Clean: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
parent
431dff5671
commit
2d9f3f1028
26 changed files with 2096 additions and 505 deletions
|
@ -8,6 +8,7 @@
|
|||
package org.eclipse.cdt.qt.core;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.eclipse.core.runtime.QualifiedName;
|
||||
|
@ -40,6 +41,10 @@ public class QtPlugin extends Plugin {
|
|||
instance = this;
|
||||
}
|
||||
|
||||
public static CoreException coreException(String msg) {
|
||||
return new CoreException(new Status(IStatus.INFO, ID, msg));
|
||||
}
|
||||
|
||||
public static IStatus info(String msg) {
|
||||
return new Status(IStatus.INFO, ID, msg);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,54 @@ import java.util.List;
|
|||
* @see IQMethod
|
||||
*/
|
||||
public interface IQObject extends IQElement {
|
||||
|
||||
/**
|
||||
* The interface to be implemented by elements that can be returned as members of an
|
||||
* implementation of {@link IQObject}.
|
||||
*/
|
||||
public static interface IMember {
|
||||
/**
|
||||
* Return the QObject class that declares this member. Does not return null.
|
||||
*/
|
||||
public IQObject getOwner();
|
||||
|
||||
/**
|
||||
* Returns true if it is <strong>*possible*</strong> for this member and the parameter
|
||||
* to override each the other. A true result indicates that <strong>*if*</strong> the members
|
||||
* owner's are related by inheritance then one will override the other; the implementation
|
||||
* does not check that there actually is such an inheritance relationship.
|
||||
*/
|
||||
public boolean isOverride(IMember member);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for unmodifiable collections of members of a class. Accessors provide filtered
|
||||
* views of the member list.
|
||||
*
|
||||
* @see #all()
|
||||
* @see #locals()
|
||||
* @see #withoutOverrides()
|
||||
*/
|
||||
public static interface IMembers<T extends IMember> {
|
||||
/**
|
||||
* Returns an unmodifiable collection with all locally declared, inherited, and overridden
|
||||
* members. Does not return null.
|
||||
*/
|
||||
public Collection<T> all();
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable collection with only the members that are locally declared in the
|
||||
* source class. Does not return null.
|
||||
*/
|
||||
public Collection<T> locals();
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable collection of all locally declared and inherited members with the
|
||||
* overridden members filtered out. Does not return null.
|
||||
*/
|
||||
public Collection<T> withoutOverrides();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the class.
|
||||
*/
|
||||
|
@ -38,6 +86,11 @@ public interface IQObject extends IQElement {
|
|||
*/
|
||||
public List<IQObject> getBases();
|
||||
|
||||
/**
|
||||
* Returns the expansions of the Q_PROPERTY macro. Does not return null.
|
||||
*/
|
||||
public IMembers<IQProperty> getProperties();
|
||||
|
||||
/**
|
||||
* Examines the Q_CLASSINFO expansions to return the value associated with the given
|
||||
* key. Returns null if there isn't a Q_CLASSINFO for the given key.
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A container for things declared as Q_PROPERTY within a subclass of QObject. In Qt 4.8,
|
||||
* Q_PROPERTY looks like:
|
||||
* <pre>
|
||||
* Q_PROPERTY( type name
|
||||
* READ getFunction
|
||||
* [WRITE setFunction]
|
||||
* [RESET resetFunction]
|
||||
* [NOTIFY notifySignal]
|
||||
* [REVISION int]
|
||||
* [DESIGNABLE bool]
|
||||
* [SCRIPTABLE bool]
|
||||
* [STORED bool]
|
||||
* [USER bool]
|
||||
* [CONSTANT]
|
||||
* [FINAL] )
|
||||
* </pre>
|
||||
* This interface provides structured access to the elements of the Q_PROPERTY expansion.
|
||||
*/
|
||||
public interface IQProperty extends IQObject.IMember {
|
||||
|
||||
/**
|
||||
* The attributes that were defined in Qt 4.8. This is the full set of attributes
|
||||
* that will be parsed from Q_PROPERTY expansions.
|
||||
*/
|
||||
public static enum Attribute {
|
||||
// This enum is used when scanning Q_PROPERTY expansions, only attributes listed here
|
||||
// will be extracted from the expansion. This enum should be expanded with new values
|
||||
// as needed (based on the version of Qt). See QProperty#scanAttributes.
|
||||
READ("getFunction"),
|
||||
WRITE("setFunction"),
|
||||
RESET("resetFunction"),
|
||||
NOTIFY("notifySignal"),
|
||||
REVISION("int"),
|
||||
DESIGNABLE("bool"),
|
||||
SCRIPTABLE("bool"),
|
||||
STORED("bool"),
|
||||
USER("bool"),
|
||||
CONSTANT(null),
|
||||
FINAL(null);
|
||||
|
||||
/**
|
||||
* A string containing the C++ identifier for this attribute.
|
||||
*/
|
||||
public final String identifier = toString();
|
||||
|
||||
/**
|
||||
* Stores the attribute parameter name if it exists and null for attributes
|
||||
* without parameters. The parameter name comes from the Qt documentation
|
||||
* and is only intended for documentation.
|
||||
*/
|
||||
public final String paramName;
|
||||
|
||||
/**
|
||||
* True when this attribute is expected to have a value and false otherwise.
|
||||
*/
|
||||
public final boolean hasValue;
|
||||
|
||||
private Attribute(String paramName) {
|
||||
this.paramName = paramName;
|
||||
this.hasValue = paramName != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to access the value of a property through this
|
||||
* enum, e.g.,
|
||||
* <pre>
|
||||
* IQProperty qprop;
|
||||
* String readFunction = IQProperty.Attribute.READ.valueId( qprop );
|
||||
* </pre>
|
||||
* Returns null if there is no associated value in the given property.
|
||||
*/
|
||||
public String valueIn(IQProperty qprop) {
|
||||
return qprop == null ? null : qprop.getValue(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the property. This is the first field in the Q_PROPERTY expansion.
|
||||
*/
|
||||
public String getType();
|
||||
|
||||
/**
|
||||
* Returns the name of the property. This is the second field in the Q_PROPERTY expansion.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Return the value of the attribute associated with the given key. E.g., in
|
||||
* <pre>
|
||||
* Q_PROPERTY( bool allowed READ isAllowed )
|
||||
* <pre>
|
||||
* The parameter Attribute.READ would return "isAllowed".
|
||||
*
|
||||
* Returns null if the given key is not described in the property.
|
||||
*/
|
||||
public String getValue(Attribute attr);
|
||||
|
||||
/**
|
||||
* Return the value of READ or null if READ is not described in the property.
|
||||
*/
|
||||
public String getReadMethodName();
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of WRITE or null if WRITE is not described in the property.
|
||||
*/
|
||||
public String getWriteMethodName();
|
||||
|
||||
/**
|
||||
* Return the value of RESET or null if RESET is not described in the property.
|
||||
*/
|
||||
public String getResetMethodName();
|
||||
|
||||
/**
|
||||
* Return the value of NOTIFY or null if NOTIFY is not described in the property.
|
||||
*/
|
||||
public String getNotifyMethodName();
|
||||
|
||||
/**
|
||||
* Return the value of REVISION or null if REVISION is not described in the property.
|
||||
* The return type is Long in order to accommodate unsigned C++ 32-bit values.
|
||||
*/
|
||||
public Long getRevision();
|
||||
|
||||
/**
|
||||
* Return the value of DESIGNABLE or null if DESIGNABLE is not described in the property.
|
||||
*/
|
||||
public String getDesignable();
|
||||
|
||||
/**
|
||||
* Return the value of SCRIPTABLE or null if SCRIPTABLE is not described in the property.
|
||||
*/
|
||||
public String getScriptable();
|
||||
|
||||
/**
|
||||
* Return the value of STORED or null if STORED is not described in the property.
|
||||
*/
|
||||
public String getStored();
|
||||
|
||||
/**
|
||||
* Return the value of USER or null if USER is not described in the property.
|
||||
*/
|
||||
public String getUser();
|
||||
|
||||
/**
|
||||
* Return true if CONSTANT was specified in the Q_PROPERTY expansion and false otherwise.
|
||||
*/
|
||||
public boolean isConstant();
|
||||
|
||||
/**
|
||||
* Return true if FINAL was specified in the Q_PROPERTY expansion and false otherwise.
|
||||
*/
|
||||
public boolean isFinal();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Scan the given field and extracts the strings defining the attributes of the
|
||||
* field. Returns false if the expansion parameter, does not represent a Q_PROPERTY,
|
||||
* does not have related information, or if the information does not match the
|
||||
* expected format.
|
||||
*/
|
||||
protected abstract boolean scanDefn(String expansionParam);
|
||||
|
||||
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 Q_PROPERY is overridden,
|
||||
// but the docs suggest it is just by name.
|
||||
|
||||
AbstractQField other = (AbstractQField) member;
|
||||
return name == null ? other.name == null : name.equals(other.name);
|
||||
}
|
||||
}
|
|
@ -13,9 +13,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
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.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.QtPDOMQObject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
@ -25,6 +26,7 @@ public class QObject implements IQObject {
|
|||
private final String name;
|
||||
private final QtPDOMQObject pdomQObject;
|
||||
private final List<IQObject> bases;
|
||||
private final IQObject.IMembers<IQProperty> properties;
|
||||
private final List<IQEnum> enums;
|
||||
private final Map<String, String> classInfos;
|
||||
|
||||
|
@ -32,18 +34,29 @@ public class QObject implements IQObject {
|
|||
this.name = pdomQObject.getName();
|
||||
this.pdomQObject = pdomQObject;
|
||||
|
||||
List<IQProperty> baseProps = new ArrayList<IQProperty>();
|
||||
|
||||
this.bases = new ArrayList<IQObject>();
|
||||
for(QtPDOMQObject base : pdomQObject.findBases())
|
||||
this.bases.add(new QObject(qtIndex, cdtIndex, base));
|
||||
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();
|
||||
|
||||
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()));
|
||||
}
|
||||
for(QtPDOMQEnum pdom : pdomQObject.getFields(QtPDOMQEnum.class))
|
||||
this.enums.add(new QEnum(pdom.getName(), pdom.isFlag(), pdom.getEnumerators()));
|
||||
|
||||
List<IQProperty> props = new ArrayList<IQProperty>();
|
||||
for(QtPDOMProperty pdom : pdomQObject.getFields(QtPDOMProperty.class)) {
|
||||
QProperty qProp = new QProperty(this, pdom.getTypeStr(), pdom.getName());
|
||||
for(QtPDOMProperty.Attribute attr : pdom.getAttributes())
|
||||
qProp.setAttribute(attr.attr, attr.value);
|
||||
props.add(qProp);
|
||||
}
|
||||
this.properties = QObjectMembers.create(props, baseProps);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,6 +74,11 @@ public class QObject implements IQObject {
|
|||
return bases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQObject.IMembers<IQProperty> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassInfo(String key) {
|
||||
String value = classInfos.get(key);
|
||||
|
|
|
@ -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.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<T extends IQObject.IMember> implements IQObject.IMembers<T> {
|
||||
|
||||
private final List<T> all;
|
||||
private final Collection<T> locals;
|
||||
private Collection<T> withoutOverrides;
|
||||
|
||||
public static <T extends IQObject.IMember> QObjectMembers<T> create(Collection<T> locals, Collection<T> 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<T> all = new ArrayList<T>(locals.size() + inherited.size());
|
||||
all.addAll(locals);
|
||||
all.addAll(inherited);
|
||||
return new QObjectMembers<T>(all, locals);
|
||||
}
|
||||
|
||||
private QObjectMembers(List<T> all, Collection<T> locals) {
|
||||
this.all = Collections.unmodifiableList(all);
|
||||
this.locals = Collections.unmodifiableCollection(locals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> all() {
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> locals() {
|
||||
return locals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> 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<T> filtered = new ArrayList<T>(all.size());
|
||||
for(T member : all) {
|
||||
boolean isOverridden = false;
|
||||
for(Iterator<T> i = filtered.iterator(); !isOverridden && i.hasNext(); )
|
||||
isOverridden = member.isOverride(i.next());
|
||||
if (!isOverridden)
|
||||
filtered.add(member);
|
||||
}
|
||||
|
||||
withoutOverrides = Collections.unmodifiableCollection(filtered);
|
||||
}
|
||||
}
|
||||
|
||||
return withoutOverrides;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* 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.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* A regular expression for scanning the full Q_PROPERTY expansion and extracting the
|
||||
* expansion parameter. It provides the following capture groups:
|
||||
* 1 - the type
|
||||
* 2 - the name
|
||||
* 3 - the trimmed remainder of the expansion parameter (starting with READ)
|
||||
*
|
||||
* This REGEX handles cases like:
|
||||
* Q_PROPERTY(T* t READ ... )
|
||||
* Q_PROPERTY(T * t READ ... )
|
||||
* Q_PROPERTY(T *t READ ... )
|
||||
* This REGEX assumes that READ will directly follow the property name. This is implied,
|
||||
* although not explicitly stated in the Qt documentation.
|
||||
*
|
||||
* It also allows the option of having no other attribute (just type and name). The Qt
|
||||
* documentation forbids this, but it is used in QtSensors/
|
||||
*/
|
||||
private static final Pattern EXPANSION_REGEX = Pattern.compile("^(.+?)\\s*([a-zA-Z_][\\w]*+)(?:(?:\\s+(READ\\s+.*))|\\s*)$");
|
||||
|
||||
/**
|
||||
* A regular expression for scanning Q_PROPERTY attributes. The regular expression is built
|
||||
* from the values defined in IQProperty#Attribute. It looks like:
|
||||
* <pre>
|
||||
* (:?READ)|(?:WRITE)|(:?RESET)|...
|
||||
* </pre>
|
||||
* This regular expression is used to recognize valid attributes while scanning the
|
||||
* Q_PROPERTY macro expansion.
|
||||
*
|
||||
* @see QProperty#scanAttributes(String)
|
||||
*/
|
||||
private static final Pattern ATTRIBUTE_REGEX;
|
||||
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(")");
|
||||
}
|
||||
ATTRIBUTE_REGEX = Pattern.compile(regexBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given field and extracts the strings defining the attributes of the
|
||||
* Q_PROPERTY. Returns false if the field is does not represent a Q_PROPERTY, does
|
||||
* not have attribute-related information, or if the information does not match the
|
||||
* expected format.
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected boolean scanDefn(String expansionParam) {
|
||||
Matcher m = EXPANSION_REGEX.matcher(expansionParam);
|
||||
if (!m.matches())
|
||||
return false;
|
||||
|
||||
this.type = m.group(1);
|
||||
this.name = m.group(2);
|
||||
return scanAttributes(m.group(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string to extract values for all recognized attributes. A regular expression
|
||||
* is used to find the attributes, substrings between attributes are assigned as values.
|
||||
* Attributes that don't expect a value (as determined by {@link IQProperty#Attribute#hasValue}),
|
||||
* as assigned "true".
|
||||
*/
|
||||
private boolean scanAttributes(String attributes) {
|
||||
if (attributes == null)
|
||||
return true;
|
||||
|
||||
int lastEnd = 0;
|
||||
IQProperty.Attribute lastAttr = null;
|
||||
for(Matcher attributeMatcher = ATTRIBUTE_REGEX.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());
|
||||
values[lastAttr.ordinal()] = 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()] = Boolean.TRUE.toString();
|
||||
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);
|
||||
values[lastAttr.ordinal()] = value.trim();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ 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.IASTNameOwner;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
|
@ -35,53 +34,6 @@ public abstract class ASTDelegatedName implements IASTName {
|
|||
|
||||
protected IBinding binding;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static class Reference extends ASTDelegatedName {
|
||||
|
||||
private final IASTFileLocation location;
|
||||
|
||||
public Reference(IASTName name, IASTFileLocation location) {
|
||||
super(name);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IBinding createBinding() {
|
||||
return delegate.resolveBinding();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IBinding createBinding();
|
||||
|
||||
protected ASTDelegatedName(IASTName delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
@ -208,14 +160,12 @@ public abstract class ASTDelegatedName implements IASTName {
|
|||
|
||||
@Override
|
||||
public IBinding getBinding() {
|
||||
return binding;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinding resolveBinding() {
|
||||
if (binding == null)
|
||||
binding = createBinding();
|
||||
return binding;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.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).
|
||||
* <p>
|
||||
* 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 extends QtPDOMBinding> T findFromBinding(Class<T> cls, PDOMBinding binding) throws CoreException {
|
||||
if (binding == null)
|
||||
return null;
|
||||
|
||||
// Look for external references to the binding.
|
||||
IPDOMIterator<PDOMName> 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;
|
||||
}
|
||||
}
|
|
@ -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.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 AbstractQObjectFieldName extends ASTDelegatedName {
|
||||
|
||||
private final QObjectName owner;
|
||||
private final String name;
|
||||
private final QtASTImageLocation location;
|
||||
private ASTNodeProperty propertyInParent;
|
||||
|
||||
protected AbstractQObjectFieldName(QObjectName owner, IASTName ast, String name, QtASTImageLocation 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$
|
||||
}
|
||||
}
|
|
@ -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.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;
|
||||
}
|
|
@ -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.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<T> {
|
||||
/**
|
||||
* 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;
|
||||
}
|
|
@ -7,7 +7,9 @@
|
|||
*/
|
||||
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;
|
||||
|
@ -16,18 +18,19 @@ 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.IBinding;
|
||||
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 {
|
||||
public class QObjectName extends ASTDelegatedName implements IQtASTName {
|
||||
|
||||
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;
|
||||
|
@ -40,6 +43,14 @@ public class QObjectName extends ASTDelegatedName {
|
|||
this.propertyInParent = delegate.getPropertyInParent();
|
||||
}
|
||||
|
||||
public List<QtPropertyName> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void addProperty(QtPropertyName property) {
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public Map<String, String> getClassInfos() {
|
||||
return classInfos;
|
||||
}
|
||||
|
@ -49,8 +60,8 @@ public class QObjectName extends ASTDelegatedName {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IBinding createBinding() {
|
||||
return new QtBinding(QtPDOMNodeType.QObject, this, spec.getName());
|
||||
public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException {
|
||||
return new QtPDOMQObject(linkage, this, spec.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,9 @@ 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.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
|
@ -23,12 +25,15 @@ 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.IScope;
|
||||
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;
|
||||
import org.eclipse.cdt.qt.core.index.IQProperty;
|
||||
import org.eclipse.cdt.qt.internal.core.index.QProperty;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class QtASTVisitor extends ASTVisitor {
|
||||
|
@ -36,10 +41,10 @@ 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 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*\\)$");
|
||||
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
|
||||
|
@ -49,7 +54,35 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
* <p>
|
||||
* The key must not have embedded quotes.
|
||||
*/
|
||||
private static final Pattern classInfoRegex = Pattern.compile("^Q_CLASSINFO\\s*\\(\\s*\"([^\"]+)\"\\s*,\\s*\"(.*)\"\\s*\\)$");
|
||||
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:
|
||||
* <pre>
|
||||
* (:?READ)|(?:WRITE)|(:?RESET)|...
|
||||
* </pre>
|
||||
* 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;
|
||||
|
@ -117,7 +150,7 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
symbols.add(owner, astName, qobjName);
|
||||
|
||||
if (cppName != null)
|
||||
symbols.add(owner, new ASTDelegatedName.Reference(cppName, location), astName);
|
||||
symbols.add(owner, new ASTNameReference(cppName, location), astName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,9 +161,12 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
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 the those lists are uses to create
|
||||
// three. Two lists are created during this processing. Then those lists are uses to create
|
||||
// the QEnum instances.
|
||||
|
||||
List<EnumDecl> enumDecls = new ArrayList<QtASTVisitor.EnumDecl>();
|
||||
|
@ -140,6 +176,7 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
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))
|
||||
|
@ -158,7 +195,8 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
String value = m.group(2);
|
||||
qobjName.addClassInfo(key, value);
|
||||
}
|
||||
}
|
||||
} else if(QtKeywords.Q_PROPERTY.equals(macroName))
|
||||
handleQPropertyDefn(owner, qobjName, expansion);
|
||||
}
|
||||
|
||||
for(EnumDecl decl : enumDecls)
|
||||
|
@ -185,4 +223,167 @@ public class QtASTVisitor extends ASTVisitor {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,89 +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.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.internal.core.dom.Linkage;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class QtBinding implements IBinding {
|
||||
|
||||
private final QtPDOMNodeType type;
|
||||
private final QtBinding owner;
|
||||
private final IASTName qtName;
|
||||
private final IASTName cppName;
|
||||
|
||||
private QtPDOMBinding pdomBinding;
|
||||
|
||||
public QtBinding(QtPDOMNodeType type, IASTName qtName, IASTName cppName) {
|
||||
this(type, null, qtName, cppName);
|
||||
}
|
||||
|
||||
public QtBinding(QtPDOMNodeType type, QtBinding owner, IASTName qtName, IASTName cppName) {
|
||||
this.type = type;
|
||||
this.owner = owner;
|
||||
this.qtName = qtName;
|
||||
this.cppName = cppName;
|
||||
}
|
||||
|
||||
public QtPDOMNodeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public IASTName getQtName() {
|
||||
return qtName;
|
||||
}
|
||||
|
||||
public IASTName getCppName() {
|
||||
return cppName;
|
||||
}
|
||||
|
||||
public void setPDOMBinding(QtPDOMBinding pdomBinding) {
|
||||
this.pdomBinding = pdomBinding;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public Object getAdapter(Class adapter) {
|
||||
if (getClass().isAssignableFrom(adapter))
|
||||
return this;
|
||||
if (QtPDOMBinding.class.isAssignableFrom(adapter))
|
||||
return pdomBinding;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.valueOf(getNameCharArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getNameCharArray() {
|
||||
return qtName.getSimpleID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILinkage getLinkage() {
|
||||
return Linkage.QT_LINKAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinding getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IScope getScope() throws DOMException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -7,33 +7,17 @@
|
|||
*/
|
||||
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;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class QtEnumName extends ASTDelegatedName {
|
||||
public class QtEnumName extends AbstractQObjectFieldName implements IQtASTName {
|
||||
|
||||
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;
|
||||
super(qobjName, ast, qtEnumName, location);
|
||||
this.cppEnumName = cppEnumName;
|
||||
this.location = location;
|
||||
this.isFlag = isFlag;
|
||||
}
|
||||
|
||||
|
@ -42,94 +26,7 @@ public class QtEnumName extends ASTDelegatedName {
|
|||
}
|
||||
|
||||
@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);
|
||||
public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException {
|
||||
return new QtPDOMQEnum(linkage, getOwner(linkage), this, cppEnumName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.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<T> {
|
||||
|
||||
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<T> codec;
|
||||
private long record;
|
||||
|
||||
public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec<T> codec, long record) {
|
||||
this.linkage = linkage;
|
||||
this.codec = codec;
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
public QtPDOMArray(QtPDOMLinkage linkage, IQtPDOMCodec<T> 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;
|
||||
}
|
||||
}
|
|
@ -7,13 +7,11 @@
|
|||
*/
|
||||
package org.eclipse.cdt.qt.internal.core.pdom;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ILinkage;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
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.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")
|
||||
|
@ -40,39 +38,36 @@ public abstract class QtPDOMBinding extends PDOMBinding {
|
|||
super(linkage, record);
|
||||
}
|
||||
|
||||
protected QtPDOMBinding(QtPDOMLinkage linkage, PDOMNode parent, QtBinding qtBinding) throws CoreException {
|
||||
super(linkage, parent, qtBinding.getNameCharArray());
|
||||
qtBinding.setPDOMBinding(this);
|
||||
|
||||
getDB().putRecPtr(Field.CppRecord.getRecord(record), linkage.getCPPRecord(qtBinding));
|
||||
protected QtPDOMBinding(QtPDOMLinkage linkage, PDOMNode parent, IASTName qtName) throws CoreException {
|
||||
super(linkage, parent, qtName.getSimpleID());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getRecordSize() {
|
||||
return Field.Last.offset;
|
||||
}
|
||||
|
||||
public long getCppRecord() {
|
||||
try {
|
||||
return getDB().getRecPtr(Field.CppRecord.getRecord(record));
|
||||
} catch (CoreException e) {
|
||||
QtPlugin.log(e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public IBinding getCppBinding() throws CoreException {
|
||||
long cppRec = getCppRecord();
|
||||
if (cppRec == 0)
|
||||
return null;
|
||||
|
||||
PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID);
|
||||
if (cppLinkage == null)
|
||||
return null;
|
||||
|
||||
return cppLinkage.getBinding(cppRec);
|
||||
}
|
||||
//
|
||||
// public long getCppRecord() {
|
||||
// try {
|
||||
// return getDB().getRecPtr(Field.CppRecord.getRecord(record));
|
||||
// } catch (CoreException e) {
|
||||
// QtPlugin.log(e);
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// public IBinding getCppBinding() throws CoreException {
|
||||
// long cppRec = getCppRecord();
|
||||
// if (cppRec == 0)
|
||||
// return null;
|
||||
//
|
||||
// PDOMLinkage cppLinkage = getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID);
|
||||
// if (cppLinkage == null)
|
||||
// return null;
|
||||
//
|
||||
// return cppLinkage.getBinding(cppRec);
|
||||
// }
|
||||
|
||||
protected QtPDOMLinkage getQtLinkage() {
|
||||
PDOMLinkage pdomLinkage = getLinkage();
|
||||
|
@ -87,6 +82,14 @@ public abstract class QtPDOMBinding extends PDOMBinding {
|
|||
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) {
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
*/
|
||||
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;
|
||||
|
@ -14,10 +17,8 @@ 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.BTree;
|
||||
import org.eclipse.cdt.internal.core.pdom.db.Database;
|
||||
import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
|
||||
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.FindBinding;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
|
||||
|
@ -32,7 +33,6 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
private static int offsetInitializer = PDOMLinkage.RECORD_SIZE;
|
||||
private static enum Field {
|
||||
Version(Database.INT_SIZE),
|
||||
CppIndex(Database.PTR_SIZE),
|
||||
Last(0);
|
||||
|
||||
private final int offset;
|
||||
|
@ -50,16 +50,12 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
// The version that has been read from/written to the persisted file.
|
||||
private int version;
|
||||
|
||||
// An index of C++ -> Qt Bindings. This is used for fast lookup of things like the QObject
|
||||
// for a C++ class in the base specifier list. Each entry in the index is a pair like
|
||||
// { CPP_Record, Qt_Record }, the CPP_Record is used for comparison when searching the index.
|
||||
private final BTree cppIndex;
|
||||
private final Map<IQtASTName, PDOMBinding> cache = new HashMap<IQtASTName, PDOMBinding>();
|
||||
|
||||
public QtPDOMLinkage(PDOM pdom, long record) throws CoreException {
|
||||
super(pdom, record);
|
||||
|
||||
version = pdom.getDB().getInt(Field.Version.getRecord(record));
|
||||
cppIndex = new BTree(pdom.getDB(), Field.CppIndex.getRecord(record), new CppRecordIndexComparator());
|
||||
}
|
||||
|
||||
protected QtPDOMLinkage(PDOM pdom) throws CoreException {
|
||||
|
@ -68,11 +64,6 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
// Initialize the version with whatever is current.
|
||||
version = QtPDOMNodeType.VERSION;
|
||||
pdom.getDB().putInt(Field.Version.getRecord(record), version);
|
||||
|
||||
long cppIndexRec = Field.CppIndex.getRecord(record);
|
||||
Database db = pdom.getDB();
|
||||
db.putRecPtr(cppIndexRec, 0);
|
||||
cppIndex = new BTree(db, cppIndexRec, new CppRecordIndexComparator());
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
|
@ -89,16 +80,6 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
return ILinkage.QT_LINKAGE_ID;
|
||||
}
|
||||
|
||||
public QtPDOMBinding findFromCppRecord(long cppRec) throws CoreException {
|
||||
CppRecordIndexFinder finder = new CppRecordIndexFinder(cppRec);
|
||||
cppIndex.accept(finder);
|
||||
if (finder.foundQtRec == null)
|
||||
return null;
|
||||
|
||||
PDOMNode node = getNode(finder.foundQtRec.longValue());
|
||||
return node instanceof QtPDOMBinding ? (QtPDOMBinding) node : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDOMNode getNode(long record, int nodeType) throws CoreException {
|
||||
return QtPDOMNodeType.load(this, nodeType, record);
|
||||
|
@ -123,18 +104,6 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
&& pdomBinding.getLinkage() == this)
|
||||
return pdomBinding;
|
||||
|
||||
// Otherwise try to create a new PDOMBinding.
|
||||
QtBinding qtBinding = (QtBinding) binding.getAdapter(QtBinding.class);
|
||||
if (qtBinding != null)
|
||||
switch(qtBinding.getType()) {
|
||||
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.
|
||||
if (pdomBinding != null) {
|
||||
addChild(pdomBinding);
|
||||
|
@ -145,19 +114,8 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
return getPDOM().getLinkage(ILinkage.CPP_LINKAGE_ID).adaptBinding(binding);
|
||||
}
|
||||
|
||||
public void addChild(QtPDOMBinding child) throws CoreException {
|
||||
super.addChild(child);
|
||||
public long getCPPRecord(IASTName cppName) throws CoreException {
|
||||
|
||||
Database db = getDB();
|
||||
long pair = db.malloc(Database.PTR_SIZE * 2);
|
||||
db.putRecPtr(pair, child.getCppRecord());
|
||||
db.putRecPtr(pair + Database.PTR_SIZE, child.getRecord());
|
||||
cppIndex.insert(pair);
|
||||
}
|
||||
|
||||
public long getCPPRecord(QtBinding qtBinding) throws CoreException {
|
||||
|
||||
IASTName cppName = qtBinding.getCppName();
|
||||
if (cppName == null)
|
||||
return 0;
|
||||
|
||||
|
@ -176,14 +134,69 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
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.
|
||||
* <p>
|
||||
* 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 {
|
||||
return name == null ? null : adaptBinding(name.getBinding());
|
||||
|
||||
// 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 QtBinding ? ((QtBinding) binding).getType().Type : 0;
|
||||
return binding instanceof QtPDOMBinding ? ((QtPDOMBinding) binding).getNodeType() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,44 +218,4 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
|||
public ISerializableEvaluation unmarshalEvaluation(ITypeMarshalBuffer typeMarshalBuffer) throws CoreException {
|
||||
throw new CoreException(QtPlugin.error("Qt Linkage does not marshal evaluations")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private class CppRecordIndexComparator implements IBTreeComparator {
|
||||
|
||||
@Override
|
||||
public int compare(long record1, long record2) throws CoreException {
|
||||
Database db = getDB();
|
||||
|
||||
Long cppRec1 = Long.valueOf(db.getRecPtr(record1));
|
||||
long cppRec2 = Long.valueOf(db.getRecPtr(record2));
|
||||
return cppRec1.compareTo(cppRec2);
|
||||
}
|
||||
}
|
||||
|
||||
private class CppRecordIndexFinder extends CppRecordIndexComparator implements IBTreeVisitor {
|
||||
|
||||
private final Long targetCppRec;
|
||||
public Long foundQtRec;
|
||||
|
||||
public CppRecordIndexFinder(long targetCppRec) {
|
||||
this.targetCppRec = Long.valueOf(targetCppRec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(long record) throws CoreException {
|
||||
Long cppRec = Long.valueOf(getDB().getRecPtr(record));
|
||||
return cppRec.compareTo(targetCppRec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(long record) throws CoreException {
|
||||
// Stop searching after the record is found.
|
||||
if (foundQtRec != null)
|
||||
return false;
|
||||
|
||||
// The record is the pair, so the Qt rec is the second element.
|
||||
long qtRec = getDB().getRecPtr(record + Database.PTR_SIZE);
|
||||
foundQtRec = Long.valueOf(qtRec);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ import org.eclipse.core.runtime.CoreException;
|
|||
public enum QtPDOMNodeType {
|
||||
|
||||
QObject,
|
||||
QEnum;
|
||||
QEnum,
|
||||
QProperty,
|
||||
QPropertyAttribute;
|
||||
|
||||
public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal();
|
||||
|
||||
|
@ -26,7 +28,7 @@ public enum QtPDOMNodeType {
|
|||
* <p>
|
||||
* The version is needed because ordinals for these enumerators are written to the file.
|
||||
*/
|
||||
public static final int VERSION = 2;
|
||||
public static final int VERSION = 3;
|
||||
|
||||
public static QtPDOMNodeType forType(int version, int type) {
|
||||
// Nothing has been deleted or replaced yet, so the version is ignored.
|
||||
|
@ -48,6 +50,8 @@ public enum QtPDOMNodeType {
|
|||
return new QtPDOMQObject(linkage, record);
|
||||
case QEnum:
|
||||
return new QtPDOMQEnum(linkage, record);
|
||||
case QProperty:
|
||||
return new QtPDOMProperty(linkage, record);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* 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.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||
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.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 implements IField {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private QtPDOMQObject qobj;
|
||||
|
||||
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))
|
||||
this.qobj = null;
|
||||
else {
|
||||
this.qobj = (QtPDOMQObject) parent;
|
||||
this.qobj.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());
|
||||
}
|
||||
|
||||
// TODO IType?
|
||||
public String getTypeStr() 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<Attribute> pdomArray = new QtPDOMArray<Attribute>(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<Attribute> pdomArray = new QtPDOMArray<Attribute>(getQtLinkage(), Attribute.Codec, rec);
|
||||
return pdomArray.get();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO use the real type?
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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<Attribute> Codec = new IQtPDOMCodec<Attribute>() {
|
||||
@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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ 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.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||
|
@ -19,7 +20,9 @@ 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.db.Database;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
|
||||
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
|
||||
import org.eclipse.cdt.qt.core.QtPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
|
@ -29,6 +32,7 @@ public class QtPDOMQEnum extends QtPDOMBinding implements IField {
|
|||
private static int offsetInitializer = QtPDOMBinding.Field.Last.offset;
|
||||
protected static enum Field {
|
||||
Flags(1),
|
||||
CppRecord(Database.PTR_SIZE),
|
||||
Last(0);
|
||||
|
||||
public final int offset;
|
||||
|
@ -51,13 +55,14 @@ public class QtPDOMQEnum extends QtPDOMBinding implements IField {
|
|||
super(linkage, record);
|
||||
}
|
||||
|
||||
public QtPDOMQEnum(QtPDOMLinkage linkage, PDOMBinding parent, QtBinding binding) throws CoreException {
|
||||
super(linkage, parent, binding);
|
||||
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;
|
||||
|
||||
IASTName qtName = binding.getQtName();
|
||||
if (qtName instanceof QtEnumName
|
||||
&& ((QtEnumName) qtName).isFlag())
|
||||
flags |= IS_FLAG_MASK;
|
||||
|
@ -78,6 +83,25 @@ public class QtPDOMQEnum extends QtPDOMBinding implements IField {
|
|||
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;
|
||||
|
@ -103,12 +127,8 @@ public class QtPDOMQEnum extends QtPDOMBinding implements IField {
|
|||
}
|
||||
|
||||
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());
|
||||
IEnumeration cppEnum = getCppEnumeration();
|
||||
return cppEnum == null ? Collections.<IEnumerator>emptyList() : Arrays.asList(cppEnum.getEnumerators());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,10 +9,12 @@ 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.ICompositeType;
|
||||
|
@ -22,9 +24,10 @@ import org.eclipse.cdt.core.dom.ast.IType;
|
|||
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.IString;
|
||||
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;
|
||||
|
@ -41,20 +44,31 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
// The record size is retrieved as the offset of the special terminal enumerator Last.
|
||||
private static int offsetInitializer = QtPDOMBinding.Field.Last.offset;
|
||||
protected static enum Field {
|
||||
Children(4 /* From PDOMNodeLinkedList.RECORD_SIZE, which is protected */),
|
||||
ClassInfos(Database.PTR_SIZE),
|
||||
Last(0);
|
||||
CppRecord(Database.PTR_SIZE, 3),
|
||||
Children(4 /* From PDOMNodeLinkedList.RECORD_SIZE, which is protected */, 0),
|
||||
ClassInfos(Database.PTR_SIZE, 2),
|
||||
Properties(Database.PTR_SIZE, 3),
|
||||
Last(0, 0);
|
||||
|
||||
private final int offset;
|
||||
private final int version;
|
||||
|
||||
private Field(int sizeof) {
|
||||
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;
|
||||
|
@ -64,77 +78,92 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
children = new PDOMNodeLinkedList(linkage, Field.Children.getRecord(record));
|
||||
}
|
||||
|
||||
public QtPDOMQObject(QtPDOMLinkage linkage, QtBinding binding) throws CoreException {
|
||||
super(linkage, null, binding);
|
||||
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));
|
||||
|
||||
IASTName qtName = binding.getQtName();
|
||||
if (qtName instanceof QObjectName)
|
||||
setClassInfos(((QObjectName) qtName).getClassInfos());
|
||||
if (qtName instanceof QObjectName) {
|
||||
QObjectName qobjName = (QObjectName) qtName;
|
||||
setClassInfos(qobjName.getClassInfos());
|
||||
}
|
||||
}
|
||||
|
||||
public void delete() throws CoreException {
|
||||
long fieldRec = Field.ClassInfos.getRecord(record);
|
||||
new QtPDOMArray<ClassInfo>(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);
|
||||
|
||||
// TODO
|
||||
if (cppBinding == null)
|
||||
return null;
|
||||
cppBinding.getAdapter(ICPPClassType.class);
|
||||
|
||||
return cppBinding instanceof ICPPClassType ? (ICPPClassType) cppBinding : null;
|
||||
}
|
||||
|
||||
public void setClassInfos(Map<String, String> classInfos) throws CoreException {
|
||||
|
||||
// ClassInfo was not supported before version 2.
|
||||
if (getQtLinkage().getVersion() < 2)
|
||||
// Make sure the version of the linkage contains this field.
|
||||
if (!Field.ClassInfos.isSupportedIn(getQtLinkage()))
|
||||
return;
|
||||
|
||||
// Delete all entries that are currently in the list.
|
||||
long block = getDB().getRecPtr(Field.ClassInfos.getRecord(record));
|
||||
if (block != 0) {
|
||||
int numEntries = getDB().getInt(block);
|
||||
for(long b = block + Database.INT_SIZE, end = block + (numEntries * 2 * Database.PTR_SIZE); b < end; b += Database.PTR_SIZE)
|
||||
getDB().getString(b).delete();
|
||||
getDB().free(block);
|
||||
// Create an array to be stored to the PDOM.
|
||||
ClassInfo[] array = new ClassInfo[classInfos.size()];
|
||||
Iterator<Map.Entry<String, String>> iterator = classInfos.entrySet().iterator();
|
||||
for(int i = 0; i < array.length && iterator.hasNext(); ++i) {
|
||||
Map.Entry<String, String> entry = iterator.next();
|
||||
array[i] = new ClassInfo(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// Clear the pointer if the incoming map is empty.
|
||||
if (classInfos.isEmpty()) {
|
||||
getDB().putRecPtr(Field.ClassInfos.getRecord(record), 0);
|
||||
return;
|
||||
}
|
||||
// Store the array into the Database.
|
||||
long arrayRec = getDB().getRecPtr(Field.ClassInfos.getRecord(record));
|
||||
QtPDOMArray<ClassInfo> pdomArray = new QtPDOMArray<QtPDOMQObject.ClassInfo>(getQtLinkage(), ClassInfo.Codec, arrayRec);
|
||||
arrayRec = pdomArray.set(array);
|
||||
|
||||
// Otherwise create a block large enough to hold the incoming list and then populate it.
|
||||
block = getDB().malloc(Database.INT_SIZE + (classInfos.size() * 2 * Database.PTR_SIZE));
|
||||
getDB().putInt(block, classInfos.size());
|
||||
|
||||
long b = block + Database.INT_SIZE;
|
||||
for(Map.Entry<String, String> classInfo : classInfos.entrySet()) {
|
||||
IString key = getDB().newString(classInfo.getKey());
|
||||
IString val = getDB().newString(classInfo.getValue());
|
||||
|
||||
getDB().putRecPtr(b, key.getRecord()); b += Database.PTR_SIZE;
|
||||
getDB().putRecPtr(b, val.getRecord()); b += Database.PTR_SIZE;
|
||||
}
|
||||
|
||||
// Put the new block into the PDOM.
|
||||
getDB().putRecPtr(Field.ClassInfos.getRecord(record), block);
|
||||
// Update the record that is stored in the receiver's field.
|
||||
getDB().putRecPtr(Field.ClassInfos.getRecord(record), arrayRec);
|
||||
}
|
||||
|
||||
public Map<String, String> getClassInfos() throws CoreException {
|
||||
Map<String, String> classInfos = new LinkedHashMap<String, String>();
|
||||
|
||||
// ClassInfo was not supported before version 2.
|
||||
if (getQtLinkage().getVersion() < 2)
|
||||
// Make sure the version of the linkage contains this field.
|
||||
if (!Field.ClassInfos.isSupportedIn(getQtLinkage()))
|
||||
return classInfos;
|
||||
|
||||
long block = getDB().getRecPtr(Field.ClassInfos.getRecord(record));
|
||||
if (block != 0) {
|
||||
int numEntries = getDB().getInt(block);
|
||||
block += Database.INT_SIZE;
|
||||
// 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);
|
||||
|
||||
for(long end = block + (numEntries * 2 * Database.PTR_SIZE); block < end; /* in loop body */) {
|
||||
long rec = getDB().getRecPtr(block);
|
||||
IString key = getDB().getString(rec);
|
||||
block += Database.PTR_SIZE;
|
||||
ClassInfo[] array = pdomArray.get();
|
||||
if (array == null)
|
||||
return classInfos;
|
||||
|
||||
rec = getDB().getRecPtr(block);
|
||||
IString val = getDB().getString(rec);
|
||||
block += Database.PTR_SIZE;
|
||||
|
||||
classInfos.put(key.getString(), val.getString());
|
||||
}
|
||||
}
|
||||
for(ClassInfo classInfo : array)
|
||||
classInfos.put(classInfo.key, classInfo.value);
|
||||
|
||||
return classInfos;
|
||||
}
|
||||
|
@ -157,12 +186,12 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
}
|
||||
|
||||
public List<QtPDOMQObject> findBases() throws CoreException {
|
||||
IBinding cppBinding = getCppBinding();
|
||||
if (!(cppBinding instanceof ICPPClassType))
|
||||
ICPPClassType cppClassType = getCppClassType();
|
||||
if (cppClassType == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<QtPDOMQObject> bases = new ArrayList<QtPDOMQObject>();
|
||||
for (ICPPBase base : ((ICPPClassType) cppBinding).getBases()) {
|
||||
for (ICPPBase base : cppClassType.getBases()) {
|
||||
if (base.getVisibility() != ICPPBase.v_public)
|
||||
continue;
|
||||
|
||||
|
@ -170,18 +199,12 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
if (baseCls == null)
|
||||
continue;
|
||||
|
||||
IPDOMBinding pdomBase = (IPDOMBinding) baseCls.getAdapter(IPDOMBinding.class);
|
||||
if (pdomBase == null)
|
||||
continue;
|
||||
|
||||
QtPDOMBinding qtPDOMBinding = getQtLinkage().findFromCppRecord(pdomBase.getRecord());
|
||||
if (qtPDOMBinding == null)
|
||||
continue;
|
||||
|
||||
QtPDOMQObject pdomQObj = (QtPDOMQObject) qtPDOMBinding.getAdapter(QtPDOMQObject.class);
|
||||
if (pdomQObj != null)
|
||||
bases.add(pdomQObj);
|
||||
PDOMBinding pdomBinding = (PDOMBinding) baseCls.getAdapter(PDOMBinding.class);
|
||||
QtPDOMQObject baseQObj = ASTNameReference.findFromBinding(QtPDOMQObject.class, pdomBinding);
|
||||
if (baseQObj != null)
|
||||
bases.add(baseQObj);
|
||||
}
|
||||
|
||||
return bases;
|
||||
}
|
||||
|
||||
|
@ -213,6 +236,18 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
children.addMember(child);
|
||||
}
|
||||
|
||||
public <T extends IField> List<T> getFields(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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IField[] getFields() {
|
||||
QtPDOMVisitor.All<IField> collector = new QtPDOMVisitor.All<IField>(IField.class);
|
||||
|
@ -241,9 +276,7 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
@Override
|
||||
public IScope getCompositeScope() {
|
||||
try {
|
||||
IBinding cppBinding = getCppBinding();
|
||||
if (cppBinding instanceof ICompositeType)
|
||||
return ((ICompositeType) cppBinding).getCompositeScope();
|
||||
return getCppClassType().getCompositeScope();
|
||||
} catch(CoreException e) {
|
||||
QtPlugin.log(e);
|
||||
}
|
||||
|
@ -255,4 +288,46 @@ public class QtPDOMQObject extends QtPDOMBinding implements ICompositeType {
|
|||
public Object clone() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
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<ClassInfo> Codec = new IQtPDOMCodec<ClassInfo>() {
|
||||
@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());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 AbstractQObjectFieldName implements IQtASTName {
|
||||
|
||||
private String type;
|
||||
private List<QtPDOMProperty.Attribute> attributes = new ArrayList<QtPDOMProperty.Attribute>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -7,11 +7,18 @@
|
|||
*/
|
||||
package org.eclipse.cdt.qt.tests;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.qt.core.index.IQEnum;
|
||||
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||
import org.eclipse.cdt.qt.core.index.IQProperty;
|
||||
import org.eclipse.cdt.qt.core.index.IQProperty.Attribute;
|
||||
import org.eclipse.cdt.qt.core.index.QtIndex;
|
||||
|
||||
public class QObjectTests extends BaseQtTestCase {
|
||||
|
@ -48,41 +55,6 @@ public class QObjectTests extends BaseQtTestCase {
|
|||
assertNull(qobj_D2);
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// class B : public QObject
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_CLASSINFO( "key1", "value1" )
|
||||
// Q_CLASSINFO( "key2", "value\"2" )
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
// class D : public B
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_CLASSINFO( "key2", "overridden value" )
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
public void testClassInfos() throws Exception {
|
||||
loadComment("classinfos.hh");
|
||||
|
||||
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||
assertNotNull(qtIndex);
|
||||
|
||||
IQObject qobj_b = qtIndex.findQObject(new String[]{ "B" });
|
||||
if (!isIndexOk("B", qobj_b))
|
||||
return;
|
||||
assertNotNull(qobj_b);
|
||||
assertEquals("value1", qobj_b.getClassInfo("key1"));
|
||||
assertEquals("value\\\"2", qobj_b.getClassInfo("key2"));
|
||||
|
||||
IQObject qobj_d = qtIndex.findQObject(new String[]{ "D" });
|
||||
assertNotNull(qobj_d);
|
||||
assertEquals("value1", qobj_d.getClassInfo("key1")); // inherited
|
||||
assertEquals("overridden value", qobj_d.getClassInfo("key2"));
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// template <typename T> class QList {};
|
||||
// class QString {};
|
||||
|
@ -210,4 +182,237 @@ public class QObjectTests extends BaseQtTestCase {
|
|||
fail("unexpected Q_FLAGS " + qEnum.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// class B : public QObject
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_PROPERTY(bool allowed READ isAllowed)
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
public void testOwner() throws Exception {
|
||||
loadComment("owner.hh");
|
||||
|
||||
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||
assertNotNull(qtIndex);
|
||||
|
||||
IQObject qobj = qtIndex.findQObject(new String[]{ "B" });
|
||||
if (!isIndexOk("B", qobj))
|
||||
return;
|
||||
assertNotNull(qobj);
|
||||
|
||||
Collection<IQProperty> properties = qobj.getProperties().locals();
|
||||
assertNotNull(properties);
|
||||
assertEquals(1, properties.size());
|
||||
|
||||
IQProperty property = properties.iterator().next();
|
||||
assertNotNull(property);
|
||||
assertTrue(qobj == property.getOwner());
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// template <typename T> class T {};
|
||||
// class Q : public QObject
|
||||
// {
|
||||
// Q_OBJECT
|
||||
//
|
||||
// bool getProp() const;
|
||||
//
|
||||
// // strange cases found by grep'ing for Q_PROPERTY in the qt4 headers
|
||||
// Q_PROPERTY( bool prop1 READ getProp )
|
||||
// Q_PROPERTY( T<bool> prop2 READ getProp )
|
||||
// Q_PROPERTY( T<bool *> prop3 READ getProp )
|
||||
// Q_PROPERTY( bool *prop4 READ getProp )
|
||||
// Q_PROPERTY( bool prop5 )
|
||||
// Q_PROPERTY( bool *prop6 )
|
||||
//
|
||||
// Q_PROPERTY( bool read1 READ readMethod )
|
||||
// Q_PROPERTY( bool read2 READ readMethod2 FINAL )
|
||||
//
|
||||
// // from qtoolbar.h
|
||||
// Q_PROPERTY( Namespace::Type allowedAreas1 )
|
||||
// Q_PROPERTY( Qt::ToolBarAreas allowedAreas2 READ allowedAreas WRITE setAllowedAreas
|
||||
// DESIGNABLE (qobject_cast<QMainWindow *>(parentWidget()) != 0)
|
||||
// NOTIFY allowedAreasChanged )
|
||||
//
|
||||
// bool readMethod();
|
||||
// bool readMethod2() const { return false; }
|
||||
// Qt::ToolBarAreas allowedAreas() const;
|
||||
// void setAllowedAreas( Qt::ToolBarAreas ) { }
|
||||
// Q_SIGNAL void allowedAreasChanged();
|
||||
// };
|
||||
public void testQProperties() throws Exception {
|
||||
loadComment("q_property.hh");
|
||||
|
||||
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||
assertNotNull(qtIndex);
|
||||
|
||||
IQObject qobj = qtIndex.findQObject(new String[]{ "Q" });
|
||||
if (!isIndexOk("Q", qobj))
|
||||
return;
|
||||
assertNotNull(qobj);
|
||||
|
||||
assert_checkQProperties(
|
||||
qobj,
|
||||
new ExpectedQProperty("bool", "prop1", Attribute.READ, "getProp"),
|
||||
new ExpectedQProperty("T<bool>", "prop2", Attribute.READ, "getProp"),
|
||||
new ExpectedQProperty("T<bool *>", "prop3", Attribute.READ, "getProp"),
|
||||
new ExpectedQProperty("bool *", "prop4", Attribute.READ, "getProp"),
|
||||
new ExpectedQProperty("bool", "prop5"),
|
||||
new ExpectedQProperty("bool *", "prop6"),
|
||||
|
||||
new ExpectedQProperty("bool", "read1", Attribute.READ, "readMethod"),
|
||||
new ExpectedQProperty("bool", "read2", Attribute.READ ,"readMethod2", Attribute.FINAL),
|
||||
|
||||
new ExpectedQProperty("Namespace::Type", "allowedAreas1" ),
|
||||
new ExpectedQProperty("Qt::ToolBarAreas", "allowedAreas2",
|
||||
Attribute.READ, "allowedAreas",
|
||||
Attribute.WRITE, "setAllowedAreas",
|
||||
Attribute.DESIGNABLE, "(qobject_cast<QMainWindow *>(parentWidget()) != 0)",
|
||||
Attribute.NOTIFY, "allowedAreasChanged")
|
||||
);
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// class B : public QObject
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_PROPERTY(bool allowed READ isAllowed)
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
// class D1 : public B
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_PROPERTY(bool allowed READ isAllowed_d)
|
||||
// public:
|
||||
// bool isAllowed_d() const { return false; }
|
||||
// };
|
||||
public void testGetOverridden() throws Exception {
|
||||
loadComment("getOverridden.hh");
|
||||
|
||||
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||
assertNotNull(qtIndex);
|
||||
|
||||
IQObject base_qobj = qtIndex.findQObject(new String[]{ "B" });
|
||||
if (!isIndexOk("B", base_qobj))
|
||||
return;
|
||||
assertNotNull(base_qobj);
|
||||
|
||||
IQObject.IMembers<IQProperty> base_qprops = base_qobj.getProperties();
|
||||
assertNotNull(base_qprops);
|
||||
assertEquals(1, base_qprops.all().size());
|
||||
assertEquals(1, base_qprops.locals().size());
|
||||
assertEquals(1, base_qprops.withoutOverrides().size());
|
||||
|
||||
IQObject derived_qobj1 = qtIndex.findQObject(new String[]{ "D1" });
|
||||
assertNotNull(derived_qobj1);
|
||||
IQObject.IMembers<IQProperty> derived_qprops1 = derived_qobj1.getProperties();
|
||||
assertNotNull(derived_qprops1);
|
||||
assertEquals(2, derived_qprops1.all().size());
|
||||
assertEquals(1, derived_qprops1.locals().size());
|
||||
assertEquals(1, derived_qprops1.withoutOverrides().size());
|
||||
}
|
||||
|
||||
// #include "junit-QObject.hh"
|
||||
// class B : public QObject
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_CLASSINFO( "key1", "value1" )
|
||||
// Q_CLASSINFO( "key2", "value\"2" )
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
// class D : public B
|
||||
// {
|
||||
// Q_OBJECT
|
||||
// Q_CLASSINFO( "key2", "overridden value" )
|
||||
// public:
|
||||
// bool isAllowed() const { return false; }
|
||||
// };
|
||||
public void testClassInfos() throws Exception {
|
||||
loadComment("classinfos.hh");
|
||||
|
||||
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||
assertNotNull(qtIndex);
|
||||
|
||||
IQObject qobj_b = qtIndex.findQObject(new String[]{ "B" });
|
||||
if (!isIndexOk("B", qobj_b))
|
||||
return;
|
||||
assertNotNull(qobj_b);
|
||||
assertEquals("value1", qobj_b.getClassInfo("key1"));
|
||||
assertEquals("value\\\"2", qobj_b.getClassInfo("key2"));
|
||||
|
||||
IQObject qobj_d = qtIndex.findQObject(new String[]{ "D" });
|
||||
assertNotNull(qobj_d);
|
||||
assertEquals("value1", qobj_d.getClassInfo("key1")); // inherited
|
||||
assertEquals("overridden value", qobj_d.getClassInfo("key2"));
|
||||
}
|
||||
|
||||
private static class ExpectedQProperty {
|
||||
public final String type;
|
||||
public final String name;
|
||||
Object[] attributes;
|
||||
public ExpectedQProperty(String type, String name, Object... attributes) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method for testing Q_PROPERTYs. The given object is checked for the list of
|
||||
* values. Only the locally declared properties are checked and the list must be complete.
|
||||
*/
|
||||
private static void assert_checkQProperties(IQObject qobj, ExpectedQProperty... expectedProperties) throws Exception {
|
||||
|
||||
// this map is used to make sure that all expected attributes are found
|
||||
Map<String, ExpectedQProperty> qprops = new HashMap<String, QObjectTests.ExpectedQProperty>();
|
||||
for(ExpectedQProperty qprop : expectedProperties)
|
||||
if (qprops.containsKey(qprop.name))
|
||||
fail("duplicate properties in expected list " + qprop.name);
|
||||
else
|
||||
qprops.put(qprop.name, qprop);
|
||||
|
||||
for(IQProperty qprop : qobj.getProperties().locals()) {
|
||||
ExpectedQProperty expected = qprops.remove(qprop.getName());
|
||||
assertNotNull("unexpected or duplicate attribute " + qprop.getName(), expected);
|
||||
assertEquals("unexpected type for " + expected.name, expected.type, qprop.getType());
|
||||
assertEquals("unexpected type for " + expected.name, expected.name, qprop.getName());
|
||||
|
||||
// make sure that all attributes that were found were expected
|
||||
Set<Attribute> allAttrs = new HashSet<Attribute>(Arrays.asList(Attribute.values()));
|
||||
|
||||
for(int i = 0; i < expected.attributes.length; ++i) {
|
||||
Attribute attr = (Attribute)expected.attributes[i];
|
||||
|
||||
// make sure the test is valid -- search for each attribute at most once
|
||||
assertTrue(allAttrs.remove(attr));
|
||||
|
||||
if (!attr.hasValue)
|
||||
assertNotNull("missing " + attr.toString(), attr.valueIn(qprop));
|
||||
else if(i >= (expected.attributes.length - 1)
|
||||
|| expected.attributes[i + 1] instanceof Attribute)
|
||||
fail("INVALID TEST CASE: " + attr + " should have a value, but one was not provided" );
|
||||
else {
|
||||
Object exp = expected.attributes[++i];
|
||||
assertEquals(attr.toString(), exp, attr.valueIn(qprop));
|
||||
}
|
||||
}
|
||||
|
||||
// make sure there is no value for all other attributes
|
||||
for(Attribute attr : allAttrs)
|
||||
assertTrue("unexpectedly found value for " + attr, attr.valueIn(qprop) == null);
|
||||
}
|
||||
|
||||
// make sure that all expected properties were found
|
||||
StringBuilder missingAttrs = new StringBuilder();
|
||||
for(String propName : qprops.keySet()) {
|
||||
if (missingAttrs.length() > 0)
|
||||
missingAttrs.append(", ");
|
||||
missingAttrs.append(propName);
|
||||
}
|
||||
assertTrue("missing properties " + missingAttrs.toString(), missingAttrs.length() == 0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue