forked from qt-creator/qt-creator
qmldesigner: fix reparenting to Layout
Using strings for everything creates issues, the whole thing should be cleaned up in master. cleverCompare is asymmetric, one side has the code model, but the other is a string. To keep it like that wherever we detect that the string is becoming too strange (normally for copied prototypes) we fall back to the cpp name if available whenever the import does not match the origin. Then cleverCompare can successfully compare the strings. Task-number:QTCREATORBUG-11905 Change-Id: I857f81b57d8ddd43263ce0e3bb085600ff6e8a43 Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
This commit is contained in:
@@ -122,6 +122,157 @@ static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPt
|
||||
return type;
|
||||
}
|
||||
|
||||
static QString qualifiedTypeNameForContext(const ObjectValue *objectValue,
|
||||
const ViewerContext &vContext,
|
||||
const ImportDependencies &dep)
|
||||
{
|
||||
QString cppName;
|
||||
QStringList packages;
|
||||
if (const CppComponentValue *cppComponent = value_cast<CppComponentValue>(objectValue)) {
|
||||
QString className = cppComponent->className();
|
||||
foreach (const LanguageUtils::FakeMetaObject::Export &e, cppComponent->metaObject()->exports()) {
|
||||
if (e.type == className)
|
||||
packages << e.package;
|
||||
if (e.package == QmlJS::CppQmlTypes::cppPackage)
|
||||
cppName = e.type;
|
||||
}
|
||||
if (packages.size() == 1 && packages.at(0) == QmlJS::CppQmlTypes::cppPackage)
|
||||
return packages.at(0) + QLatin1Char('.') + className;
|
||||
}
|
||||
// try to recover a "global context name"
|
||||
QStringList possibleLibraries;
|
||||
QStringList possibleQrcFiles;
|
||||
QStringList possibleFiles;
|
||||
bool hasQtQuick = false;
|
||||
do {
|
||||
if (objectValue->originId().isEmpty())
|
||||
break;
|
||||
CoreImport cImport = dep.coreImport(objectValue->originId());
|
||||
if (!cImport.valid())
|
||||
break;
|
||||
foreach (const Export &e, cImport.possibleExports) {
|
||||
if (e.pathRequired.isEmpty() || vContext.paths.contains(e.pathRequired)) {
|
||||
switch (e.exportName.type) {
|
||||
case ImportType::Library:
|
||||
{
|
||||
QString typeName = objectValue->className();
|
||||
if (!e.typeName.isEmpty() && e.typeName != Export::LibraryTypeName) {
|
||||
typeName = e.typeName;
|
||||
if (typeName != objectValue->className())
|
||||
qCWarning(qmljsLog) << "Outdated classname " << objectValue->className()
|
||||
<< " vs " << typeName
|
||||
<< " for " << e.exportName.toString();
|
||||
}
|
||||
if (packages.isEmpty() || packages.contains(e.exportName.libPath())) {
|
||||
if (e.exportName.splitPath.value(0) == QLatin1String("QtQuick"))
|
||||
hasQtQuick = true;
|
||||
possibleLibraries.append(e.exportName.libPath() + '.' + typeName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ImportType::File:
|
||||
{
|
||||
// remove the search path prefix.
|
||||
// this means that the same relative path wrt. different import paths will clash
|
||||
QString filePath = e.exportName.path();
|
||||
foreach (const QString &path, vContext.paths) {
|
||||
if (filePath.startsWith(path) && filePath.size() > path.size()
|
||||
&& filePath.at(path.size()) == QLatin1Char('/'))
|
||||
{
|
||||
filePath = filePath.mid(path.size() + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (filePath.startsWith(QLatin1Char('/')))
|
||||
filePath = filePath.mid(1);
|
||||
QFileInfo fileInfo(filePath);
|
||||
QStringList splitName = fileInfo.path().split(QLatin1Char('/'));
|
||||
QString typeName = fileInfo.baseName();
|
||||
if (!e.typeName.isEmpty()) {
|
||||
if (e.typeName != fileInfo.baseName())
|
||||
qCWarning(qmljsLog) << "type renaming in file import " << e.typeName
|
||||
<< " for " << e.exportName.path();
|
||||
typeName = e.typeName;
|
||||
}
|
||||
if (typeName != objectValue->className())
|
||||
qCWarning(qmljsLog) << "Outdated classname " << objectValue->className()
|
||||
<< " vs " << typeName
|
||||
<< " for " << e.exportName.toString();
|
||||
splitName.append(typeName);
|
||||
possibleFiles.append(splitName.join(QLatin1Char('.')));
|
||||
break;
|
||||
}
|
||||
case ImportType::QrcFile:
|
||||
{
|
||||
QString filePath = e.exportName.path();
|
||||
if (filePath.startsWith(QLatin1Char('/')))
|
||||
filePath = filePath.mid(1);
|
||||
QFileInfo fileInfo(filePath);
|
||||
QStringList splitName = fileInfo.path().split(QLatin1Char('/'));
|
||||
QString typeName = fileInfo.baseName();
|
||||
if (!e.typeName.isEmpty()) {
|
||||
if (e.typeName != fileInfo.baseName())
|
||||
qCWarning(qmljsLog) << "type renaming in file import " << e.typeName
|
||||
<< " for " << e.exportName.path();
|
||||
typeName = e.typeName;
|
||||
}
|
||||
if (typeName != objectValue->className())
|
||||
qCWarning(qmljsLog) << "Outdated classname " << objectValue->className()
|
||||
<< " vs " << typeName
|
||||
<< " for " << e.exportName.toString();
|
||||
splitName.append(typeName);
|
||||
possibleQrcFiles.append(splitName.join(QLatin1Char('.')));
|
||||
break;
|
||||
}
|
||||
case ImportType::Invalid:
|
||||
case ImportType::UnknownFile:
|
||||
break;
|
||||
case ImportType::Directory:
|
||||
case ImportType::ImplicitDirectory:
|
||||
case ImportType::QrcDirectory:
|
||||
qCWarning(qmljsLog) << "unexpected import type in export "
|
||||
<< e.exportName.toString() << " of coreExport "
|
||||
<< objectValue->originId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto optimalName = [] (const QStringList &list) -> QString {
|
||||
QString res = list.at(0);
|
||||
for (int i = 1; i < list.size(); ++i) {
|
||||
const QString &nameNow = list.at(i);
|
||||
if (nameNow.size() < res.size()
|
||||
|| (nameNow.size() == res.size() && nameNow < res))
|
||||
res = nameNow;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
if (!possibleLibraries.isEmpty()) {
|
||||
if (hasQtQuick) {
|
||||
foreach (const QString &libImport, possibleLibraries)
|
||||
if (!libImport.startsWith(QLatin1String("QtQuick")))
|
||||
possibleLibraries.removeAll(libImport);
|
||||
}
|
||||
return optimalName(possibleLibraries);
|
||||
}
|
||||
if (!possibleQrcFiles.isEmpty())
|
||||
return optimalName(possibleQrcFiles);
|
||||
if (!possibleFiles.isEmpty())
|
||||
return optimalName(possibleFiles);
|
||||
} while (false);
|
||||
if (!cppName.isEmpty())
|
||||
return QmlJS::CppQmlTypes::cppPackage + QLatin1Char('.') + cppName;
|
||||
if (const CppComponentValue *cppComponent = value_cast<CppComponentValue>(objectValue)) {
|
||||
if (cppComponent->moduleName().isEmpty())
|
||||
return cppComponent->className();
|
||||
else
|
||||
return cppComponent->moduleName() + QLatin1Char('.') + cppComponent->className();
|
||||
} else {
|
||||
return objectValue->className();
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyMemberProcessor : public MemberProcessor
|
||||
{
|
||||
public:
|
||||
@@ -144,8 +295,10 @@ public:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) {
|
||||
TypeName qualifiedTypeName = cppComponentValue->moduleName().isEmpty() ? cppComponentValue->className().toUtf8() : cppComponentValue->moduleName().toUtf8() + '.' + cppComponentValue->className().toUtf8();
|
||||
TypeName qualifiedTypeName = qualifiedTypeNameForContext(cppComponentValue,
|
||||
m_context->vContext(), *m_context->snapshot().importDependencies()).toUtf8();
|
||||
m_properties.append(qMakePair(propertyName, qualifiedTypeName));
|
||||
} else {
|
||||
TypeId typeId;
|
||||
|
Reference in New Issue
Block a user