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:
Fawzi Mohamed
2014-07-16 16:34:30 +02:00
parent 176096d112
commit f9d9dedab5

View File

@@ -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;