mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 09:46:02 +02:00
Bug 422841 QtIndex API for qmlRegisterType function calls
The Qt spec includes a special function that is used to introduce C++ types to a namespace that is accessible from QML. E.g., qmlRegisterType<Q>( "uri", 1, 0, "QMLType" ); This will create a QML type called QMLType. The type will include the signals, slots, and invokable that are defined in the C++ class Q. The type is accessible in QML using the given URI and the version is 1.0. More information is available at: http://qt-project.org/doc/qt-4.8/qdeclarativeengine.html This patch adds IQmlRegisteredType, a collection of which can be accessed from a new method in QtIndex. This also includes new test cases for this feature. Change-Id: I70c44d1d8d3a0594de44e692a16f7b26396e8464 Signed-off-by: Andrew Eidsness <eclipse@jfront.com> Reviewed-on: https://git.eclipse.org/r/20347 Tested-by: Hudson CI Reviewed-by: Doug Schaefer <dschaefer@qnx.com> IP-Clean: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
parent
0e196ca5f2
commit
78fc903d16
18 changed files with 877 additions and 36 deletions
|
@ -12,6 +12,7 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
||||||
|
@ -27,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
@ -34,6 +36,7 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
||||||
|
import org.eclipse.cdt.qt.core.QtPlugin;
|
||||||
import org.eclipse.cdt.qt.core.index.IQMethod;
|
import org.eclipse.cdt.qt.core.index.IQMethod;
|
||||||
import org.eclipse.cdt.qt.core.index.IQObject;
|
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
|
@ -76,6 +79,13 @@ public class ASTUtil {
|
||||||
public static String getFullyQualifiedName(IBinding binding) {
|
public static String getFullyQualifiedName(IBinding binding) {
|
||||||
if (binding == null)
|
if (binding == null)
|
||||||
return null;
|
return null;
|
||||||
|
if (binding instanceof ICPPBinding)
|
||||||
|
try {
|
||||||
|
return getFullyQualifiedName(((ICPPBinding) binding).getQualifiedName());
|
||||||
|
} catch(DOMException e) {
|
||||||
|
QtPlugin.log(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String ownerName = getFullyQualifiedName(binding.getOwner());
|
String ownerName = getFullyQualifiedName(binding.getOwner());
|
||||||
return (ownerName == null ? "" : ownerName) + "::" + binding.getName();
|
return (ownerName == null ? "" : ownerName) + "::" + binding.getName();
|
||||||
|
@ -86,11 +96,16 @@ public class ASTUtil {
|
||||||
* input array's elements.
|
* input array's elements.
|
||||||
*/
|
*/
|
||||||
public static String getFullyQualifiedName(String[] qualName) {
|
public static String getFullyQualifiedName(String[] qualName) {
|
||||||
String fullyQualifiedName = "";
|
boolean first = true;
|
||||||
for(int i = 0; i < qualName.length; ++i) {
|
StringBuilder str = new StringBuilder();
|
||||||
fullyQualifiedName += "::" + qualName[i];
|
for(String name : qualName) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
str.append("::");
|
||||||
|
str.append(name);
|
||||||
}
|
}
|
||||||
return fullyQualifiedName;
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This expression allows embedded line terminators (?s) for cases where the code looks like:
|
// NOTE: This expression allows embedded line terminators (?s) for cases where the code looks like:
|
||||||
|
|
|
@ -11,7 +11,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMProperty;
|
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMProperty;
|
||||||
|
@ -36,15 +35,8 @@ public class QObject implements IQObject {
|
||||||
private final List<IQEnum> enums;
|
private final List<IQEnum> enums;
|
||||||
private final Map<String, String> classInfos;
|
private final Map<String, String> classInfos;
|
||||||
|
|
||||||
/**
|
|
||||||
* QObjects are stored in the QtLinkage using their fully qualified name. The API
|
|
||||||
* for IQObject does not expect the leading ::, so they are stripped when the
|
|
||||||
* object is read from the PDOM.
|
|
||||||
*/
|
|
||||||
private static Pattern StripLeadingQual_Regex = Pattern.compile("^::(.*)$");
|
|
||||||
|
|
||||||
public QObject(QtIndexImpl qtIndex, CDTIndex cdtIndex, QtPDOMQObject pdomQObject) throws CoreException {
|
public QObject(QtIndexImpl qtIndex, CDTIndex cdtIndex, QtPDOMQObject pdomQObject) throws CoreException {
|
||||||
this.name = StripLeadingQual_Regex.matcher(pdomQObject.getName()).replaceAll("$1");
|
this.name = pdomQObject.getName();
|
||||||
this.pdomQObject = pdomQObject;
|
this.pdomQObject = pdomQObject;
|
||||||
|
|
||||||
List<IQMethod> baseSlots = new ArrayList<IQMethod>();
|
List<IQMethod> baseSlots = new ArrayList<IQMethod>();
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.internal.qt.core.index;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQmlRegistration;
|
||||||
|
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQmlUncreatableRegistration;
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQmlRegistered;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
public class QmlRegistered implements IQmlRegistered {
|
||||||
|
|
||||||
|
private final QtIndexImpl qtIndex;
|
||||||
|
private final IQmlRegistered.Kind kind;
|
||||||
|
private final String[] ownerName;
|
||||||
|
private final Long version;
|
||||||
|
private final String uri;
|
||||||
|
private final Long major;
|
||||||
|
private final Long minor;
|
||||||
|
private final String qmlName;
|
||||||
|
private final String reason;
|
||||||
|
private IQObject qObject;
|
||||||
|
|
||||||
|
public static QmlRegistered create(QtIndexImpl qtIndex, IBinding pdom) throws CoreException {
|
||||||
|
if (pdom instanceof QtPDOMQmlUncreatableRegistration)
|
||||||
|
return new QmlRegistered(qtIndex, (QtPDOMQmlUncreatableRegistration) pdom);
|
||||||
|
if (pdom instanceof QtPDOMQmlRegistration)
|
||||||
|
return new QmlRegistered(qtIndex, (QtPDOMQmlRegistration) pdom);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QmlRegistered(QtIndexImpl qtIndex, QtPDOMQmlRegistration pdom) throws CoreException {
|
||||||
|
this.qtIndex = qtIndex;
|
||||||
|
this.kind = IQmlRegistered.Kind.Type;
|
||||||
|
|
||||||
|
String qobjName = pdom.getQObjectName();
|
||||||
|
this.ownerName = qobjName == null ? null : qobjName.split("::");
|
||||||
|
|
||||||
|
this.version = pdom.getVersion();
|
||||||
|
this.uri = pdom.getUri();
|
||||||
|
this.major = pdom.getMajor();
|
||||||
|
this.minor = pdom.getMinor();
|
||||||
|
this.qmlName = pdom.getQmlName();
|
||||||
|
this.reason = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QmlRegistered(QtIndexImpl qtIndex, QtPDOMQmlUncreatableRegistration pdom) throws CoreException {
|
||||||
|
this.qtIndex = qtIndex;
|
||||||
|
this.kind = IQmlRegistered.Kind.Uncreatable;
|
||||||
|
|
||||||
|
String qobjName = pdom.getQObjectName();
|
||||||
|
this.ownerName = qobjName == null ? null : qobjName.split("::");
|
||||||
|
|
||||||
|
this.version = pdom.getVersion();
|
||||||
|
this.uri = pdom.getUri();
|
||||||
|
this.major = pdom.getMajor();
|
||||||
|
this.minor = pdom.getMinor();
|
||||||
|
this.qmlName = pdom.getQmlName();
|
||||||
|
this.reason = pdom.getReason();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IQmlRegistered.Kind getKind() {
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IQObject getQObject() {
|
||||||
|
if (qObject == null
|
||||||
|
&& ownerName != null)
|
||||||
|
qObject = qtIndex.findQObject(ownerName);
|
||||||
|
return qObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getURI() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getMajor() {
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getMinor() {
|
||||||
|
return minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getQmlName() {
|
||||||
|
return qmlName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,11 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.cdt.internal.qt.core.index;
|
package org.eclipse.cdt.internal.qt.core.index;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ILinkage;
|
import org.eclipse.cdt.core.dom.ILinkage;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
@ -15,8 +20,10 @@ import org.eclipse.cdt.core.index.IndexFilter;
|
||||||
import org.eclipse.cdt.internal.qt.core.ASTUtil;
|
import org.eclipse.cdt.internal.qt.core.ASTUtil;
|
||||||
import org.eclipse.cdt.internal.qt.core.pdom.AbstractQtPDOMClass;
|
import org.eclipse.cdt.internal.qt.core.pdom.AbstractQtPDOMClass;
|
||||||
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQObject;
|
import org.eclipse.cdt.internal.qt.core.pdom.QtPDOMQObject;
|
||||||
|
import org.eclipse.cdt.qt.core.QtKeywords;
|
||||||
import org.eclipse.cdt.qt.core.index.IQGadget;
|
import org.eclipse.cdt.qt.core.index.IQGadget;
|
||||||
import org.eclipse.cdt.qt.core.index.IQObject;
|
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQmlRegistered;
|
||||||
import org.eclipse.cdt.qt.core.index.QtIndex;
|
import org.eclipse.cdt.qt.core.index.QtIndex;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
@ -24,6 +31,11 @@ public class QtIndexImpl extends QtIndex {
|
||||||
|
|
||||||
private final CDTIndex cdtIndex;
|
private final CDTIndex cdtIndex;
|
||||||
|
|
||||||
|
private static final Pattern QmlTypeNameRegex
|
||||||
|
= Pattern.compile("^(?:"
|
||||||
|
+ QtKeywords.QML_REGISTER_TYPE + '|' + QtKeywords.QML_REGISTER_UNCREATABLE_TYPE
|
||||||
|
+ ")<.*>\0(.*)$");
|
||||||
|
|
||||||
private static final IndexFilter QtLinkageFilter = new IndexFilter() {
|
private static final IndexFilter QtLinkageFilter = new IndexFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptLinkage(ILinkage linkage) {
|
public boolean acceptLinkage(ILinkage linkage) {
|
||||||
|
@ -50,6 +62,11 @@ public class QtIndexImpl extends QtIndex {
|
||||||
return name == null ? null : cdtIndex.get(new QGadgetImplAccessor(name));
|
return name == null ? null : cdtIndex.get(new QGadgetImplAccessor(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IQmlRegistered> getQmlRegistered() {
|
||||||
|
return cdtIndex.get(new QMLRegisteredAccessor());
|
||||||
|
}
|
||||||
|
|
||||||
private class QObjectImplAccessor implements CDTIndex.Accessor<IQObject> {
|
private class QObjectImplAccessor implements CDTIndex.Accessor<IQObject> {
|
||||||
|
|
||||||
private final char[] name;
|
private final char[] name;
|
||||||
|
@ -92,4 +109,22 @@ public class QtIndexImpl extends QtIndex {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class QMLRegisteredAccessor implements CDTIndex.Accessor<Collection<IQmlRegistered>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IQmlRegistered> access(IIndex index) throws CoreException {
|
||||||
|
Collection<IQmlRegistered> types = null;
|
||||||
|
for(IIndexBinding binding : index.findBindings(QmlTypeNameRegex, false, QtLinkageFilter, null)) {
|
||||||
|
IQmlRegistered qml = QmlRegistered.create(QtIndexImpl.this, binding);
|
||||||
|
if (qml != null) {
|
||||||
|
if (types == null)
|
||||||
|
types = new ArrayList<IQmlRegistered>();
|
||||||
|
types.add(qml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return types == null ? Collections.<IQmlRegistered>emptyList() : types;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,9 @@ public class QObjectName extends AbstractQClassName {
|
||||||
|
|
||||||
public QObjectName(ICPPASTCompositeTypeSpecifier spec) {
|
public QObjectName(ICPPASTCompositeTypeSpecifier spec) {
|
||||||
super(spec);
|
super(spec);
|
||||||
fullyQualifiedName = ASTUtil.getFullyQualifiedName(spec.getName()).toCharArray();
|
|
||||||
|
String fqn = ASTUtil.getFullyQualifiedName(spec.getName());
|
||||||
|
fullyQualifiedName = fqn == null ? new char[0] : fqn.toCharArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.internal.qt.core.pdom;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IValue;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
||||||
|
import org.eclipse.cdt.internal.qt.core.ASTUtil;
|
||||||
|
import org.eclipse.cdt.qt.core.QtKeywords;
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQmlRegistered;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
public class QmlTypeRegistration extends ASTDelegatedName implements IQtASTName {
|
||||||
|
|
||||||
|
private final ICPPTemplateInstance functionInstanceBinding;
|
||||||
|
private final IASTFunctionCallExpression fnCall;
|
||||||
|
private final IQmlRegistered.Kind kind;
|
||||||
|
private char[] simpleID;
|
||||||
|
|
||||||
|
public QmlTypeRegistration(IASTName ast, ICPPTemplateInstance functionInstanceBinding, IASTFunctionCallExpression fnCall) {
|
||||||
|
super(ast);
|
||||||
|
this.functionInstanceBinding = functionInstanceBinding;
|
||||||
|
this.fnCall = fnCall;
|
||||||
|
|
||||||
|
if (QtKeywords.QML_REGISTER_UNCREATABLE_TYPE.equals(functionInstanceBinding.getName()))
|
||||||
|
this.kind = IQmlRegistered.Kind.Uncreatable;
|
||||||
|
else
|
||||||
|
this.kind = IQmlRegistered.Kind.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getSimpleID() {
|
||||||
|
if (simpleID == null) {
|
||||||
|
IASTInitializerClause[] args = fnCall.getArguments();
|
||||||
|
simpleID = (functionInstanceBinding.getName()
|
||||||
|
+ ASTTypeUtil.getArgumentListString(functionInstanceBinding.getTemplateArguments(), true)
|
||||||
|
+ "\0("
|
||||||
|
+ asStringForName(args, 0) + ','
|
||||||
|
+ asStringForName(args, 1) + ','
|
||||||
|
+ asStringForName(args, 2) + ','
|
||||||
|
+ asStringForName(args, 3) + ')'
|
||||||
|
).toCharArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return simpleID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QtPDOMBinding createPDOMBinding(QtPDOMLinkage linkage) throws CoreException {
|
||||||
|
switch(kind) {
|
||||||
|
case Type:
|
||||||
|
return new QtPDOMQmlRegistration(linkage, this, delegate);
|
||||||
|
case Uncreatable:
|
||||||
|
return new QtPDOMQmlUncreatableRegistration(linkage, this, delegate);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQObjectName() {
|
||||||
|
ICPPTemplateArgument[] args = functionInstanceBinding.getTemplateArguments();
|
||||||
|
if (args.length < 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IType type = args[0].getTypeValue();
|
||||||
|
return type instanceof ICPPBinding ? ASTUtil.getFullyQualifiedName((ICPPBinding) type) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVersion() {
|
||||||
|
ICPPTemplateArgument[] args = functionInstanceBinding.getTemplateArguments();
|
||||||
|
if (args.length < 2)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IValue val = args[1].getNonTypeValue();
|
||||||
|
return val == null ? null : val.numericalValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUri() {
|
||||||
|
return getArgAsStringOrNull(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMajor() {
|
||||||
|
return getArgAsLongOrNull(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMinor() {
|
||||||
|
return getArgAsLongOrNull(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQmlName() {
|
||||||
|
return getArgAsStringOrNull(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return getArgAsStringOrNull(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String asStringForName(IASTInitializerClause[] args, int index) {
|
||||||
|
String arg = args.length <= index ? null : asString(args[index]);
|
||||||
|
return arg == null ? "" : arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getArgAsStringOrNull(int index) {
|
||||||
|
IASTInitializerClause[] args = fnCall.getArguments();
|
||||||
|
if (args.length <= index)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return asString(args[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getArgAsLongOrNull(int index) {
|
||||||
|
IASTInitializerClause[] args = fnCall.getArguments();
|
||||||
|
if (args.length <= index)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String str = asString(args[index]);
|
||||||
|
if (str != null)
|
||||||
|
try {
|
||||||
|
return Long.parseLong(str);
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
// This is caused by invalid user code, do not log it
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String asString(IASTInitializerClause init) {
|
||||||
|
if (init instanceof IASTLiteralExpression) {
|
||||||
|
IASTLiteralExpression literal = (IASTLiteralExpression) init;
|
||||||
|
switch(literal.getKind()) {
|
||||||
|
case IASTLiteralExpression.lk_integer_constant:
|
||||||
|
return new String(literal.getValue());
|
||||||
|
case IASTLiteralExpression.lk_string_literal:
|
||||||
|
char[] value = literal.getValue();
|
||||||
|
return new String(value, 1, value.length - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
||||||
|
@ -33,10 +34,12 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
||||||
import org.eclipse.cdt.core.index.IIndexSymbols;
|
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.ICPPInternalBinding;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner.LocationMap;
|
import org.eclipse.cdt.internal.core.parser.scanner.LocationMap;
|
||||||
|
import org.eclipse.cdt.internal.qt.core.ASTUtil;
|
||||||
import org.eclipse.cdt.internal.qt.core.QtFunctionCall;
|
import org.eclipse.cdt.internal.qt.core.QtFunctionCall;
|
||||||
import org.eclipse.cdt.internal.qt.core.QtMethodReference;
|
import org.eclipse.cdt.internal.qt.core.QtMethodReference;
|
||||||
import org.eclipse.cdt.internal.qt.core.QtMethodUtil;
|
import org.eclipse.cdt.internal.qt.core.QtMethodUtil;
|
||||||
|
@ -124,7 +127,10 @@ public class QtASTVisitor extends ASTVisitor {
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTExpression expr) {
|
public int visit(IASTExpression expr) {
|
||||||
if (expr instanceof IASTFunctionCallExpression) {
|
if (expr instanceof IASTFunctionCallExpression) {
|
||||||
Collection<QtMethodReference> refs = QtFunctionCall.getReferences((IASTFunctionCallExpression) expr);
|
IASTFunctionCallExpression call = (IASTFunctionCallExpression) expr;
|
||||||
|
|
||||||
|
// See if this is a QObject::connect or disconnect function call.
|
||||||
|
Collection<QtMethodReference> refs = QtFunctionCall.getReferences(call);
|
||||||
if (refs != null)
|
if (refs != null)
|
||||||
for (IASTName ref : refs) {
|
for (IASTName ref : refs) {
|
||||||
IASTFileLocation nameLoc = ref.getFileLocation();
|
IASTFileLocation nameLoc = ref.getFileLocation();
|
||||||
|
@ -133,6 +139,27 @@ public class QtASTVisitor extends ASTVisitor {
|
||||||
symbols.add(owner, ref, null);
|
symbols.add(owner, ref, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See if this is a qmlRegisterType or qmlRegisterUncreatableType function call.
|
||||||
|
ICPPTemplateInstance templateFn = ASTUtil.resolveFunctionBinding(ICPPTemplateInstance.class, call);
|
||||||
|
if (QtKeywords.is_QmlType(templateFn)) {
|
||||||
|
IASTName fnName = null;
|
||||||
|
IASTExpression fnNameExpr = call.getFunctionNameExpression();
|
||||||
|
if (fnNameExpr instanceof IASTIdExpression) {
|
||||||
|
fnName = ((IASTIdExpression) fnNameExpr).getName();
|
||||||
|
}
|
||||||
|
IASTFileLocation nameLoc = call.getFileLocation();
|
||||||
|
if (nameLoc != null) {
|
||||||
|
QmlTypeRegistration qmlTypeReg = new QmlTypeRegistration(fnName, templateFn, call);
|
||||||
|
|
||||||
|
IASTPreprocessorIncludeStatement owner = nameLoc.getContextInclusionStatement();
|
||||||
|
symbols.add(owner, qmlTypeReg, null);
|
||||||
|
|
||||||
|
// the Qt data references the C++ function template instance specialization
|
||||||
|
if (fnName != null)
|
||||||
|
symbols.add(owner, new ASTNameReference(fnName), qmlTypeReg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.visit(expr);
|
return super.visit(expr);
|
||||||
|
|
|
@ -30,10 +30,6 @@ public abstract class QtPDOMBinding extends PDOMBinding {
|
||||||
this.offset = offsetInitializer;
|
this.offset = offsetInitializer;
|
||||||
offsetInitializer += sizeof;
|
offsetInitializer += sizeof;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRecord(long baseRec) {
|
|
||||||
return baseRec + offset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected QtPDOMBinding(QtPDOMLinkage linkage, long record) {
|
protected QtPDOMBinding(QtPDOMLinkage linkage, long record) {
|
||||||
|
@ -78,4 +74,49 @@ public abstract class QtPDOMBinding extends PDOMBinding {
|
||||||
|
|
||||||
return super.getAdapter(adapter);
|
return super.getAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Long from the given offset within this node's record. The permitted range of the Long
|
||||||
|
* is [Long.MIN_VALUE, Long.MAX_VALUE). Notice that Long.MAX_VALUE is excluded from the valid range.
|
||||||
|
*/
|
||||||
|
protected Long getLongOrNull(long offset) throws CoreException {
|
||||||
|
long val = getDB().getLong(record + offset);
|
||||||
|
return val == Long.MAX_VALUE ? null : Long.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the given Long into the database at the specified offset within this node's record. The permitted
|
||||||
|
* range for val is [Long.MIN_VALUE, Long.MAX_VALUE). Notice that Long.MAX_VALUE is excluded from
|
||||||
|
* the valid range.
|
||||||
|
* <p>
|
||||||
|
* The val parameter is allowed to be null. A value will be stored to the database so that later calls to
|
||||||
|
* {@link #getLongOrNull(long)} will return null;
|
||||||
|
*/
|
||||||
|
protected void putLongOrNull(long offset, Long val) throws CoreException {
|
||||||
|
getDB().putLong(record + offset, val == null ? Long.MAX_VALUE : val.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a String from the given offset within this node's record. This method will return null if the
|
||||||
|
* database does not contain an IString at the specified location.
|
||||||
|
*/
|
||||||
|
protected String getStringOrNull(long offset) throws CoreException {
|
||||||
|
long rec = getDB().getRecPtr(record + offset);
|
||||||
|
return rec == 0 ? null : getDB().getString(rec).getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the given String into the database at the specified offset within this node's record. Any IString
|
||||||
|
* that happens to already exist at the specified location will be deleted before the new value is stored.
|
||||||
|
* <p>
|
||||||
|
* The val parameter is allowed to be null. A value will be stored to the database so that later calls to
|
||||||
|
* {@link #getStringOrNull(long)} will return null;
|
||||||
|
*/
|
||||||
|
protected void putStringOrNull(long offset, String val) throws CoreException {
|
||||||
|
long rec = getDB().getRecPtr(record + offset);
|
||||||
|
if (rec != 0)
|
||||||
|
getDB().getString(rec).delete();
|
||||||
|
|
||||||
|
getDB().putRecPtr(record + offset, val == null ? 0 : getDB().newString(val).getRecord());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class QtPDOMLinkage extends PDOMLinkage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IBinding#getAdapter cannot create an instance of PDOMBinding because the Linkage is required. This
|
// IBinding#getAdapter cannot create an instance of PDOMBinding because the Linkage is required. This
|
||||||
// utility method uses #getAdapter to see if an instance has already been create. If not then a new
|
// utility method uses #getAdapter to see if an instance has already been created. If not then a new
|
||||||
// is created and stored in the AST binding.
|
// is created and stored in the AST binding.
|
||||||
@Override
|
@Override
|
||||||
public PDOMBinding adaptBinding(IBinding binding, boolean includeLocal) throws CoreException {
|
public PDOMBinding adaptBinding(IBinding binding, boolean includeLocal) throws CoreException {
|
||||||
|
|
|
@ -18,7 +18,9 @@ public enum QtPDOMNodeType {
|
||||||
QEnum,
|
QEnum,
|
||||||
QProperty,
|
QProperty,
|
||||||
QMethod,
|
QMethod,
|
||||||
QGadget;
|
QGadget,
|
||||||
|
QmlTypeRegistration,
|
||||||
|
QmlUncreatableRegistration;
|
||||||
|
|
||||||
public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal();
|
public final int Type = IIndexBindingConstants.LAST_CONSTANT + 1 + ordinal();
|
||||||
|
|
||||||
|
@ -32,7 +34,7 @@ public enum QtPDOMNodeType {
|
||||||
* This version can be reset when the PDOM's version changes because older Qt linkages will
|
* This version can be reset when the PDOM's version changes because older Qt linkages will
|
||||||
* be dropped (along with everything else in that PDOM).
|
* be dropped (along with everything else in that PDOM).
|
||||||
*/
|
*/
|
||||||
public static final int VERSION = 1;
|
public static final int VERSION = 2;
|
||||||
|
|
||||||
public static QtPDOMNodeType forType(int version, int type) {
|
public static QtPDOMNodeType forType(int version, int type) {
|
||||||
// Nothing has been deleted or replaced yet, so the version is ignored.
|
// Nothing has been deleted or replaced yet, so the version is ignored.
|
||||||
|
@ -60,6 +62,10 @@ public enum QtPDOMNodeType {
|
||||||
return new QtPDOMQMethod(linkage, record);
|
return new QtPDOMQMethod(linkage, record);
|
||||||
case QGadget:
|
case QGadget:
|
||||||
return new QtPDOMQGadget(linkage, record);
|
return new QtPDOMQGadget(linkage, record);
|
||||||
|
case QmlTypeRegistration:
|
||||||
|
return new QtPDOMQmlRegistration(linkage, record);
|
||||||
|
case QmlUncreatableRegistration:
|
||||||
|
return new QtPDOMQmlUncreatableRegistration(linkage, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.internal.qt.core.pdom;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
|
import org.eclipse.cdt.internal.core.pdom.db.Database;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
public class QtPDOMQmlRegistration extends QtPDOMBinding {
|
||||||
|
|
||||||
|
private static int offsetInitializer = QtPDOMBinding.Field.Last.offset;
|
||||||
|
protected static enum Field {
|
||||||
|
CppRecord(Database.PTR_SIZE),
|
||||||
|
QObjectName(Database.PTR_SIZE),
|
||||||
|
Version(8), // Database doesn't have a LONG_SIZE
|
||||||
|
Uri(Database.PTR_SIZE),
|
||||||
|
Major(8),
|
||||||
|
Minor(8),
|
||||||
|
QmlName(Database.PTR_SIZE),
|
||||||
|
Last(0);
|
||||||
|
|
||||||
|
public final int offset;
|
||||||
|
|
||||||
|
private Field(int sizeof) {
|
||||||
|
this.offset = offsetInitializer;
|
||||||
|
offsetInitializer += sizeof;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QtPDOMQmlRegistration(QtPDOMLinkage linkage, long record) {
|
||||||
|
super(linkage, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QtPDOMQmlRegistration(QtPDOMLinkage linkage, QmlTypeRegistration qmlTypeReg, IASTName cppName) throws CoreException {
|
||||||
|
super(linkage, null, qmlTypeReg);
|
||||||
|
|
||||||
|
putStringOrNull(Field.QObjectName.offset, qmlTypeReg.getQObjectName());
|
||||||
|
putLongOrNull(Field.Version.offset, qmlTypeReg.getVersion());
|
||||||
|
putStringOrNull(Field.Uri.offset, qmlTypeReg.getUri());
|
||||||
|
putLongOrNull(Field.Major.offset, qmlTypeReg.getMajor());
|
||||||
|
putLongOrNull(Field.Minor.offset, qmlTypeReg.getMinor());
|
||||||
|
putStringOrNull(Field.QmlName.offset, qmlTypeReg.getQmlName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getRecordSize() {
|
||||||
|
return Field.Last.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNodeType() {
|
||||||
|
return QtPDOMNodeType.QmlTypeRegistration.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQObjectName() throws CoreException {
|
||||||
|
return getStringOrNull(Field.QObjectName.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVersion() throws CoreException {
|
||||||
|
return getLongOrNull(Field.Version.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMajor() throws CoreException {
|
||||||
|
return getLongOrNull(Field.Major.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMinor() throws CoreException {
|
||||||
|
return getLongOrNull(Field.Minor.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUri() throws CoreException {
|
||||||
|
return getStringOrNull(Field.Uri.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQmlName() throws CoreException {
|
||||||
|
return getStringOrNull(Field.QmlName.offset);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.internal.qt.core.pdom;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
|
import org.eclipse.cdt.internal.core.pdom.db.Database;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
public class QtPDOMQmlUncreatableRegistration extends QtPDOMQmlRegistration {
|
||||||
|
|
||||||
|
private static int offsetInitializer = QtPDOMQmlRegistration.Field.Last.offset;
|
||||||
|
protected static enum Field {
|
||||||
|
Reason(Database.PTR_SIZE),
|
||||||
|
Last(0);
|
||||||
|
|
||||||
|
public final int offset;
|
||||||
|
|
||||||
|
private Field(int sizeof) {
|
||||||
|
this.offset = offsetInitializer;
|
||||||
|
offsetInitializer += sizeof;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QtPDOMQmlUncreatableRegistration(QtPDOMLinkage linkage, long record) {
|
||||||
|
super(linkage, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QtPDOMQmlUncreatableRegistration(QtPDOMLinkage linkage, QmlTypeRegistration qmlTypeReg, IASTName cppName) throws CoreException {
|
||||||
|
super(linkage, qmlTypeReg, cppName);
|
||||||
|
|
||||||
|
putStringOrNull(Field.Reason.offset, qmlTypeReg.getReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getRecordSize() {
|
||||||
|
return Field.Last.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNodeType() {
|
||||||
|
return QtPDOMNodeType.QmlUncreatableRegistration.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() throws CoreException {
|
||||||
|
return getStringOrNull(Field.Reason.offset);
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,6 +89,18 @@ public class QtKeywords {
|
||||||
&& DISCONNECT.equals(qualName[1]);
|
&& DISCONNECT.equals(qualName[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given binding will register a type with the QML type system and false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean is_QmlType(IBinding binding) {
|
||||||
|
String[] qualName = getFunctionQualifiedName(binding);
|
||||||
|
return qualName != null
|
||||||
|
&& qualName.length == 1
|
||||||
|
&& (QML_REGISTER_TYPE.equals(qualName[0])
|
||||||
|
|| QML_REGISTER_UNCREATABLE_TYPE.equals(qualName[0]));
|
||||||
|
}
|
||||||
|
|
||||||
private static String[] getFunctionQualifiedName(IBinding binding) {
|
private static String[] getFunctionQualifiedName(IBinding binding) {
|
||||||
// IBinding#getAdapter returns null when binding is an instance of
|
// IBinding#getAdapter returns null when binding is an instance of
|
||||||
// PDOMCPPMethod.
|
// PDOMCPPMethod.
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.qt.core.index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a specific QML type registration.
|
||||||
|
* <p>
|
||||||
|
* Qt allows types to be registered with QML by calling the qmlRegisterType function,
|
||||||
|
* e.g.,
|
||||||
|
* <pre>
|
||||||
|
* class Q : public QObject { Q_OBJECT };
|
||||||
|
* qmlRegisterType<Q>( "uri", 1, 0, "Q" );
|
||||||
|
* </pre>
|
||||||
|
* Registers Q in the QML system with the name "Q", in the library imported from "uri"
|
||||||
|
* having the version number 1.0.
|
||||||
|
*/
|
||||||
|
public interface IQmlRegistered {
|
||||||
|
/**
|
||||||
|
* Identifies the kind of qmlRegister* function that was used to register the
|
||||||
|
* type. Qt 4.8 only defines two kinds, but in 5.0 there several more.
|
||||||
|
* <p>
|
||||||
|
* If a type has been registered more than once, then there will be several
|
||||||
|
* entries for it in the collection returned by {@link QtIndex#getQmlRegistered()}.
|
||||||
|
*/
|
||||||
|
public enum Kind {
|
||||||
|
/**
|
||||||
|
* Indicates that the type has been registered with a function call to
|
||||||
|
* qmlRegisterType.
|
||||||
|
*/
|
||||||
|
Type,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the type has been registered with a function call to
|
||||||
|
* qmlRegisterUncreatableType.
|
||||||
|
*/
|
||||||
|
Uncreatable
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the kind of function that was used for this registration. In Qt 4.8,
|
||||||
|
* there are two variations of the qmlRegister* function; qmlRegisterType and
|
||||||
|
* qmlRegisterUncreatableType. In Qt 5.0 there are several more.
|
||||||
|
* <p>
|
||||||
|
* It is possible for the same type to be registered in different ways, although
|
||||||
|
* this generally indicates a problem in the client code.
|
||||||
|
*/
|
||||||
|
public IQmlRegistered.Kind getKind();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns QObject to which this registration applies. In the sample at {@link IQmlRegistered}
|
||||||
|
* this would return the IQObject for Q.
|
||||||
|
*/
|
||||||
|
public IQObject getQObject();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the specific revision of the IQObject that was registered. Returns null if no
|
||||||
|
* revision was specified.
|
||||||
|
* <p>
|
||||||
|
* E.g.,
|
||||||
|
* <code>
|
||||||
|
* class Q : public QObject
|
||||||
|
* {
|
||||||
|
* Q_OBJECT
|
||||||
|
* signals:
|
||||||
|
* Q_REVISION(2) void sig();
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* qmlRegisterType<Q>( "uri", 1, 0, "Q1" );
|
||||||
|
* qmlRegisterType<Q, 2>( "uri", 1, 0, "Q2" );
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* The QML type "Q2" would have access to the "sig" signal, while "Q1" would not.
|
||||||
|
*
|
||||||
|
* @see IQMethod#getRevision()
|
||||||
|
* @see IQProperty#getRevision()
|
||||||
|
*/
|
||||||
|
public Long getVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the literal value of the first argument to the function if it can be
|
||||||
|
* resolved and null otherwise.
|
||||||
|
*/
|
||||||
|
public String getURI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the literal value of the second argument to the function if it can be
|
||||||
|
* resolved and null otherwise.
|
||||||
|
*/
|
||||||
|
public Long getMajor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the literal value of the third argument to the function if it can be
|
||||||
|
* resolved and null otherwise.
|
||||||
|
*/
|
||||||
|
public Long getMinor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the literal value of the fourth argument to the function if it can be
|
||||||
|
* resolved and null otherwise.
|
||||||
|
*/
|
||||||
|
public String getQmlName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the literal value of the fifth argument to qmlRegisterUncreatableType if it
|
||||||
|
* can be resolved and null otherwise.
|
||||||
|
*/
|
||||||
|
public String getReason();
|
||||||
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.cdt.qt.core.index;
|
package org.eclipse.cdt.qt.core.index;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.eclipse.cdt.internal.qt.core.index.QtFactory;
|
import org.eclipse.cdt.internal.qt.core.index.QtFactory;
|
||||||
import org.eclipse.cdt.qt.core.QtPlugin;
|
import org.eclipse.cdt.qt.core.QtPlugin;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
|
@ -70,4 +72,13 @@ public abstract class QtIndex {
|
||||||
* the given name.
|
* the given name.
|
||||||
*/
|
*/
|
||||||
public abstract IQGadget findQGadget(String[] qualifiedName);
|
public abstract IQGadget findQGadget(String[] qualifiedName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find and return the types that have been registered with the Qt meta type system. This
|
||||||
|
* is the result of the function calls like:
|
||||||
|
* <pre>
|
||||||
|
* qmlRegisterType<Q>( "uri", 1, 2, "Qv1.2" );
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public abstract Collection<IQmlRegistered> getQmlRegistered();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ public class AllQtTests extends TestSuite {
|
||||||
QObjectTests.class,
|
QObjectTests.class,
|
||||||
QtContentAssistantTests.class,
|
QtContentAssistantTests.class,
|
||||||
QtIndexTests.class,
|
QtIndexTests.class,
|
||||||
QtRegressionTests.class);
|
QtRegressionTests.class,
|
||||||
|
QmlRegisteredTests.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014 QNX Software Systems and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*/
|
||||||
|
package org.eclipse.cdt.qt.tests;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQObject;
|
||||||
|
import org.eclipse.cdt.qt.core.index.IQmlRegistered;
|
||||||
|
import org.eclipse.cdt.qt.core.index.QtIndex;
|
||||||
|
|
||||||
|
public class QmlRegisteredTests extends BaseQtTestCase {
|
||||||
|
|
||||||
|
// #include "junit-QObject.hh"
|
||||||
|
// class B : public QObject
|
||||||
|
// {
|
||||||
|
// Q_OBJECT
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// class D : public B
|
||||||
|
// {
|
||||||
|
// Q_OBJECT
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// static void func()
|
||||||
|
// {
|
||||||
|
// qmlRegisterType<B>( "b-uri", 1, 2, "B" );
|
||||||
|
// qmlRegisterType<B>( "b-uri.34", 3, 4, "B34" );
|
||||||
|
//
|
||||||
|
// const char * uri = "d-uri";
|
||||||
|
// int maj = 2, min = 3;
|
||||||
|
// const char * qmlName = "D1";
|
||||||
|
// qmlRegisterType<D, 1>( uri, maj, min, qmlName );
|
||||||
|
// }
|
||||||
|
public void testQMLRegisterType() throws Exception {
|
||||||
|
loadComment("qmlregistertype.hh");
|
||||||
|
|
||||||
|
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||||
|
assertNotNull(qtIndex);
|
||||||
|
|
||||||
|
IQObject b_qobj = qtIndex.findQObject(new String[]{ "B" });
|
||||||
|
if (!isIndexOk("B", b_qobj))
|
||||||
|
return;
|
||||||
|
assertNotNull(b_qobj);
|
||||||
|
|
||||||
|
Collection<IQmlRegistered> qmlRegistereds = qtIndex.getQmlRegistered();
|
||||||
|
assertNotNull(qmlRegistereds);
|
||||||
|
assertEquals(3, qmlRegistereds.size());
|
||||||
|
|
||||||
|
for(IQmlRegistered qmlRegistered : qmlRegistereds) {
|
||||||
|
IQObject qobj = qmlRegistered.getQObject();
|
||||||
|
assertNotNull(qobj);
|
||||||
|
|
||||||
|
// all values of B should be fully resolved, except for Revision, which was not provided
|
||||||
|
if (qobj.getName().equals("B")) {
|
||||||
|
assertNull(qmlRegistered.getVersion());
|
||||||
|
String qmlName = qmlRegistered.getQmlName();
|
||||||
|
assertNotNull(qmlName);
|
||||||
|
if ("B".equals(qmlName)) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Type, qmlRegistered.getKind());
|
||||||
|
assertEquals("b-uri", qmlRegistered.getURI());
|
||||||
|
assertEquals(Long.valueOf(1), qmlRegistered.getMajor());
|
||||||
|
assertEquals(Long.valueOf(2), qmlRegistered.getMinor());
|
||||||
|
assertNull(qmlRegistered.getReason());
|
||||||
|
} else if ("B34".equals(qmlName)) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Type, qmlRegistered.getKind());
|
||||||
|
assertEquals("b-uri.34", qmlRegistered.getURI());
|
||||||
|
assertEquals(Long.valueOf(3), qmlRegistered.getMajor());
|
||||||
|
assertEquals(Long.valueOf(4), qmlRegistered.getMinor());
|
||||||
|
assertNull(qmlRegistered.getReason());
|
||||||
|
} else {
|
||||||
|
fail("unexpected uri for B " + qmlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the values for D are not expected to be resolved (yet), but it does have a Revision
|
||||||
|
} else if (qobj.getName().equals("D")) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Type, qmlRegistered.getKind());
|
||||||
|
assertEquals(Long.valueOf(1), qmlRegistered.getVersion());
|
||||||
|
assertNull(qmlRegistered.getURI());
|
||||||
|
assertNull(qmlRegistered.getMajor());
|
||||||
|
assertNull(qmlRegistered.getMinor());
|
||||||
|
assertNull(qmlRegistered.getQmlName());
|
||||||
|
assertNull(qmlRegistered.getReason());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fail("unexpected qmlRegistered " + qobj.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class T;
|
||||||
|
//
|
||||||
|
// static void func()
|
||||||
|
// {
|
||||||
|
// qmlRegisterType<T>( "t-uri", 3, 4, "qml-T" );
|
||||||
|
// }
|
||||||
|
public void testQMLRegisterFwdDecl() throws Exception {
|
||||||
|
loadComment("qmlregistertype.hh");
|
||||||
|
|
||||||
|
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||||
|
assertNotNull(qtIndex);
|
||||||
|
|
||||||
|
Collection<IQmlRegistered> qmlRegistereds = qtIndex.getQmlRegistered();
|
||||||
|
assertNotNull(qmlRegistereds);
|
||||||
|
assertEquals(1, qmlRegistereds.size());
|
||||||
|
|
||||||
|
IQmlRegistered qml = qmlRegistereds.iterator().next();
|
||||||
|
assertNotNull(qml);
|
||||||
|
assertEquals(IQmlRegistered.Kind.Type, qml.getKind());
|
||||||
|
assertEquals("t-uri", qml.getURI());
|
||||||
|
assertEquals(Long.valueOf(3), qml.getMajor());
|
||||||
|
assertEquals(Long.valueOf(4), qml.getMinor());
|
||||||
|
assertEquals("qml-T", qml.getQmlName());
|
||||||
|
assertNull(qml.getReason());
|
||||||
|
|
||||||
|
// The QObject has not been defined, so it cannot be found.
|
||||||
|
assertNull(qml.getQObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
// #include "junit-QObject.hh"
|
||||||
|
// class B : public QObject
|
||||||
|
// {
|
||||||
|
// Q_OBJECT
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// class D : public B
|
||||||
|
// {
|
||||||
|
// Q_OBJECT
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// static void func()
|
||||||
|
// {
|
||||||
|
// qmlRegisterUncreatableType<B>( "b-uri", 1, 2, "B", QString( "msg1" ) );
|
||||||
|
// qmlRegisterUncreatableType<B>( "b-uri.34", 3, 4, "B34", QString( "msg2" ) );
|
||||||
|
//
|
||||||
|
// const char * uri = "d-uri";
|
||||||
|
// int maj = 2, min = 3;
|
||||||
|
// const char * qmlName = "D1";
|
||||||
|
// const QString msg( "msg3" );
|
||||||
|
// qmlRegisterUncreatableType<D>( uri, maj, min, qmlName, msg );
|
||||||
|
// }
|
||||||
|
public void testQMLRegisterUncreatableType() throws Exception {
|
||||||
|
loadComment("qmlregistereduncreatabletype.hh");
|
||||||
|
|
||||||
|
QtIndex qtIndex = QtIndex.getIndex(fProject);
|
||||||
|
assertNotNull(qtIndex);
|
||||||
|
|
||||||
|
IQObject b_qobj = qtIndex.findQObject(new String[]{ "B" });
|
||||||
|
if (!isIndexOk("B", b_qobj))
|
||||||
|
return;
|
||||||
|
assertNotNull(b_qobj);
|
||||||
|
|
||||||
|
Collection<IQmlRegistered> qmlRegistereds = qtIndex.getQmlRegistered();
|
||||||
|
assertNotNull(qmlRegistereds);
|
||||||
|
assertEquals(3, qmlRegistereds.size());
|
||||||
|
|
||||||
|
for(IQmlRegistered qmlRegistered : qmlRegistereds) {
|
||||||
|
IQObject qobj = qmlRegistered.getQObject();
|
||||||
|
assertNotNull(qobj);
|
||||||
|
|
||||||
|
// all values of B should be fully resolved, except for Revision, which was not provided
|
||||||
|
if (qobj.getName().equals("B")) {
|
||||||
|
assertNull(qmlRegistered.getVersion());
|
||||||
|
String qmlName = qmlRegistered.getQmlName();
|
||||||
|
assertNotNull(qmlName);
|
||||||
|
if ("B".equals(qmlName)) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Uncreatable, qmlRegistered.getKind());
|
||||||
|
assertEquals("b-uri", qmlRegistered.getURI());
|
||||||
|
assertEquals(Long.valueOf(1), qmlRegistered.getMajor());
|
||||||
|
assertEquals(Long.valueOf(2), qmlRegistered.getMinor());
|
||||||
|
assertEquals(null/*"msg1"*/, qmlRegistered.getReason());
|
||||||
|
} else if ("B34".equals(qmlName)) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Uncreatable, qmlRegistered.getKind());
|
||||||
|
assertEquals("b-uri.34", qmlRegistered.getURI());
|
||||||
|
assertEquals(Long.valueOf(3), qmlRegistered.getMajor());
|
||||||
|
assertEquals(Long.valueOf(4), qmlRegistered.getMinor());
|
||||||
|
assertEquals(null/*"msg2"*/, qmlRegistered.getReason());
|
||||||
|
} else {
|
||||||
|
fail("unexpected uri for B " + qmlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the values for D are not expected to be resolved (yet), but it does have a Revision
|
||||||
|
} else if (qobj.getName().equals("D")) {
|
||||||
|
assertEquals(IQmlRegistered.Kind.Uncreatable, qmlRegistered.getKind());
|
||||||
|
assertNull(qmlRegistered.getVersion());
|
||||||
|
assertNull(qmlRegistered.getURI());
|
||||||
|
assertNull(qmlRegistered.getMajor());
|
||||||
|
assertNull(qmlRegistered.getMinor());
|
||||||
|
assertNull(qmlRegistered.getQmlName());
|
||||||
|
assertNull(qmlRegistered.getReason());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fail("unexpected qmlRegistered " + qobj.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
@ -133,18 +132,6 @@ public class QObjectConnectCompletion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean is_QObject_connect(ICEditorContentAssistInvocationContext context, IASTCompletionContext astContext, IASTName name) {
|
|
||||||
|
|
||||||
// Bug332201: Qt content assist should always be applied to the most specific part of
|
|
||||||
// the target name.
|
|
||||||
IBinding[] funcBindings = astContext.findBindings(name.getLastName(), !context.isContextInformationStyle());
|
|
||||||
for (IBinding funcBinding : funcBindings)
|
|
||||||
if (QtKeywords.is_QObject_connect(funcBinding))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator
|
// Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator
|
||||||
private static int indexOfClosingPeer(String code, char left, char right, int pos) {
|
private static int indexOfClosingPeer(String code, char left, char right, int pos) {
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue