2014-07-22 19:06:44 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-07-22 19:06:44 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:58:39 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-07-22 19:06:44 +02:00
|
|
|
**
|
2016-01-15 14:58:39 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-07-22 19:06:44 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "qmljsdialect.h"
|
2015-03-04 16:46:23 +01:00
|
|
|
#include "qmljsconstants.h"
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
2014-07-22 19:06:44 +02:00
|
|
|
|
|
|
|
|
namespace QmlJS {
|
|
|
|
|
|
|
|
|
|
bool Dialect::isQmlLikeLanguage() const
|
|
|
|
|
{
|
|
|
|
|
switch (m_dialect) {
|
|
|
|
|
case Dialect::Qml:
|
|
|
|
|
case Dialect::QmlQtQuick2:
|
2014-10-13 16:46:30 +02:00
|
|
|
case Dialect::QmlQtQuick2Ui:
|
2014-07-22 19:06:44 +02:00
|
|
|
case Dialect::QmlQbs:
|
|
|
|
|
case Dialect::QmlProject:
|
|
|
|
|
case Dialect::QmlTypeInfo:
|
|
|
|
|
case Dialect::AnyLanguage:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Dialect::isFullySupportedLanguage() const
|
|
|
|
|
{
|
|
|
|
|
switch (m_dialect) {
|
|
|
|
|
case Dialect::JavaScript:
|
|
|
|
|
case Dialect::Json:
|
|
|
|
|
case Dialect::Qml:
|
|
|
|
|
case Dialect::QmlQtQuick2:
|
2014-10-13 16:46:30 +02:00
|
|
|
case Dialect::QmlQtQuick2Ui:
|
2014-07-22 19:06:44 +02:00
|
|
|
return true;
|
|
|
|
|
case Dialect::NoLanguage:
|
|
|
|
|
case Dialect::AnyLanguage:
|
|
|
|
|
case Dialect::QmlQbs:
|
|
|
|
|
case Dialect::QmlProject:
|
|
|
|
|
case Dialect::QmlTypeInfo:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Dialect::isQmlLikeOrJsLanguage() const
|
|
|
|
|
{
|
|
|
|
|
switch (m_dialect) {
|
|
|
|
|
case Dialect::Qml:
|
|
|
|
|
case Dialect::QmlQtQuick2:
|
2014-10-13 16:46:30 +02:00
|
|
|
case Dialect::QmlQtQuick2Ui:
|
2014-07-22 19:06:44 +02:00
|
|
|
case Dialect::QmlQbs:
|
|
|
|
|
case Dialect::QmlProject:
|
|
|
|
|
case Dialect::QmlTypeInfo:
|
|
|
|
|
case Dialect::JavaScript:
|
|
|
|
|
case Dialect::AnyLanguage:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Dialect::toString() const
|
|
|
|
|
{
|
|
|
|
|
switch (m_dialect) {
|
|
|
|
|
case Dialect::JavaScript:
|
|
|
|
|
return QLatin1String("JavaScript");
|
|
|
|
|
case Dialect::Json:
|
|
|
|
|
return QLatin1String("Json");
|
|
|
|
|
case Dialect::Qml:
|
|
|
|
|
return QLatin1String("Qml");
|
|
|
|
|
case Dialect::QmlQtQuick2:
|
|
|
|
|
return QLatin1String("QmlQtQuick2");
|
2014-10-13 16:46:30 +02:00
|
|
|
case Dialect::QmlQtQuick2Ui:
|
|
|
|
|
return QLatin1String("QmlQtQuick2Ui");
|
2014-07-22 19:06:44 +02:00
|
|
|
case Dialect::NoLanguage:
|
|
|
|
|
return QLatin1String("NoLanguage");
|
|
|
|
|
case Dialect::AnyLanguage:
|
|
|
|
|
return QLatin1String("AnyLanguage");
|
|
|
|
|
case Dialect::QmlQbs:
|
|
|
|
|
return QLatin1String("QmlQbs");
|
|
|
|
|
case Dialect::QmlProject:
|
|
|
|
|
return QLatin1String("QmlProject");
|
|
|
|
|
case Dialect::QmlTypeInfo:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return QLatin1String("QmlTypeInfo");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Dialect::operator ==(const Dialect &o) const {
|
|
|
|
|
return m_dialect == o.m_dialect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Dialect::operator <(const Dialect &o) const {
|
|
|
|
|
return m_dialect < o.m_dialect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dialect Dialect::mergeLanguages(const Dialect &l1, const Dialect &l2)
|
|
|
|
|
{
|
|
|
|
|
if (l1 == Dialect::NoLanguage)
|
|
|
|
|
return l2;
|
|
|
|
|
if (l2 == Dialect::NoLanguage)
|
|
|
|
|
return l1;
|
|
|
|
|
QList<Dialect> ll1 = l1.companionLanguages();
|
|
|
|
|
QList<Dialect> ll2 = l2.companionLanguages();
|
|
|
|
|
bool i1 = ll1.contains(l2);
|
|
|
|
|
bool i2 = ll2.contains(l1);
|
|
|
|
|
if (i1 && i2) {
|
|
|
|
|
if (ll1.size() > ll2.size())
|
|
|
|
|
return l1;
|
|
|
|
|
if (ll2.size() > ll1.size())
|
|
|
|
|
return l2;
|
|
|
|
|
if (l1 < l2)
|
|
|
|
|
return l1;
|
|
|
|
|
return l2;
|
|
|
|
|
}
|
|
|
|
|
if (i1 && !i2)
|
|
|
|
|
return l1;
|
|
|
|
|
if (i2 && !i1)
|
|
|
|
|
return l2;
|
|
|
|
|
QList<Dialect> qmlLangs = Dialect(Qml).companionLanguages();
|
|
|
|
|
if (qmlLangs.contains(l1) && qmlLangs.contains(l2))
|
|
|
|
|
return Dialect::Qml;
|
|
|
|
|
return Dialect::AnyLanguage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Dialect::mergeLanguage(const Dialect &l2) {
|
|
|
|
|
*this = mergeLanguages(*this, l2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Dialect::restrictLanguage(const Dialect &l2)
|
|
|
|
|
{
|
|
|
|
|
if (*this == l2)
|
|
|
|
|
return true;
|
|
|
|
|
QList<Dialect> ll1 = companionLanguages();
|
|
|
|
|
QList<Dialect> ll2 = l2.companionLanguages();
|
|
|
|
|
bool i1 = ll1.contains(l2);
|
|
|
|
|
bool i2 = ll2.contains(*this);
|
|
|
|
|
if (i1 && i2) {
|
|
|
|
|
if (ll1.size() < ll2.size())
|
|
|
|
|
return true;
|
|
|
|
|
if (ll2.size() < ll1.size()) {
|
|
|
|
|
*this = l2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (m_dialect < l2.m_dialect)
|
|
|
|
|
return true;
|
|
|
|
|
*this = l2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (i1 && !i2) {
|
|
|
|
|
*this = l2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (i2 && !i1)
|
|
|
|
|
return true;
|
2014-10-13 16:46:30 +02:00
|
|
|
qDebug() << toString() << "restrictTo" << l2.toString() << "failed";
|
|
|
|
|
qDebug() << ll1 << ll2;
|
|
|
|
|
qDebug() << i1 << i2;
|
2014-07-22 19:06:44 +02:00
|
|
|
QList<Dialect> qmlLangs = Dialect(Qml).companionLanguages();
|
|
|
|
|
if (qmlLangs.contains(*this) && qmlLangs.contains(l2))
|
|
|
|
|
*this = Dialect::Qml;
|
|
|
|
|
*this = Dialect::AnyLanguage;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<Dialect> Dialect::companionLanguages() const
|
|
|
|
|
{
|
|
|
|
|
QList<Dialect> langs;
|
|
|
|
|
langs << *this;
|
|
|
|
|
switch (m_dialect) {
|
|
|
|
|
case Dialect::JavaScript:
|
|
|
|
|
case Dialect::Json:
|
|
|
|
|
case Dialect::QmlProject:
|
|
|
|
|
case Dialect::QmlTypeInfo:
|
|
|
|
|
break;
|
|
|
|
|
case Dialect::QmlQbs:
|
|
|
|
|
langs << Dialect::JavaScript;
|
|
|
|
|
break;
|
|
|
|
|
case Dialect::Qml:
|
2018-02-19 12:26:51 +01:00
|
|
|
langs << Dialect::QmlQtQuick2 << Dialect::QmlQtQuick2Ui << Dialect::JavaScript;
|
2014-07-22 19:06:44 +02:00
|
|
|
break;
|
2014-10-13 16:46:30 +02:00
|
|
|
case Dialect::QmlQtQuick2:
|
|
|
|
|
case Dialect::QmlQtQuick2Ui:
|
|
|
|
|
langs.clear();
|
|
|
|
|
langs << Dialect::QmlQtQuick2 << Dialect::QmlQtQuick2Ui << Dialect::Qml
|
|
|
|
|
<< Dialect::JavaScript;
|
|
|
|
|
break;
|
2014-07-22 19:06:44 +02:00
|
|
|
case Dialect::AnyLanguage:
|
|
|
|
|
langs << Dialect::JavaScript << Dialect::Json << Dialect::QmlProject << Dialect:: QmlQbs
|
2018-02-19 12:26:51 +01:00
|
|
|
<< Dialect::QmlTypeInfo << Dialect::QmlQtQuick2
|
2014-10-13 16:46:30 +02:00
|
|
|
<< Dialect::QmlQtQuick2Ui << Dialect::Qml;
|
2014-07-22 19:06:44 +02:00
|
|
|
break;
|
|
|
|
|
case Dialect::NoLanguage:
|
|
|
|
|
return QList<Dialect>(); // return at least itself?
|
|
|
|
|
}
|
|
|
|
|
if (*this != Dialect::AnyLanguage)
|
|
|
|
|
langs << Dialect::AnyLanguage;
|
|
|
|
|
return langs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint qHash(const Dialect &o)
|
|
|
|
|
{
|
|
|
|
|
return uint(o.dialect());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDebug operator << (QDebug &dbg, const Dialect &dialect)
|
|
|
|
|
{
|
|
|
|
|
dbg << dialect.toString();
|
|
|
|
|
return dbg;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
PathAndLanguage::PathAndLanguage(const Utils::FilePath &path, Dialect language)
|
2014-07-22 19:06:44 +02:00
|
|
|
: m_path(path), m_language(language)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
bool PathAndLanguage::operator ==(const PathAndLanguage &other) const
|
|
|
|
|
{
|
|
|
|
|
return path() == other.path() && language() == other.language();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PathAndLanguage::operator <(const PathAndLanguage &other) const
|
|
|
|
|
{
|
|
|
|
|
if (path() < other.path())
|
|
|
|
|
return true;
|
|
|
|
|
if (path() > other.path())
|
|
|
|
|
return false;
|
|
|
|
|
if (language() == other.language())
|
|
|
|
|
return false;
|
|
|
|
|
bool i1 = other.language().companionLanguages().contains(language());
|
|
|
|
|
bool i2 = language().companionLanguages().contains(other.language());
|
|
|
|
|
if (i1 && !i2)
|
|
|
|
|
return true;
|
|
|
|
|
if (i2 && !i1)
|
|
|
|
|
return false;
|
|
|
|
|
return language() < other.language();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDebug operator << (QDebug &dbg, const PathAndLanguage &pathAndLanguage)
|
|
|
|
|
{
|
|
|
|
|
dbg << "{ path:" << pathAndLanguage.path() << " language:" << pathAndLanguage.language().toString() << "}";
|
|
|
|
|
return dbg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PathsAndLanguages::maybeInsert(const PathAndLanguage &pathAndLanguage) {
|
|
|
|
|
for (int i = 0; i < m_list.size(); ++i) {
|
|
|
|
|
PathAndLanguage currentElement = m_list.at(i);
|
|
|
|
|
if (currentElement.path() == pathAndLanguage.path()) {
|
|
|
|
|
int j = i;
|
|
|
|
|
do {
|
2017-06-29 14:59:07 +02:00
|
|
|
if (pathAndLanguage.language() < currentElement.language())
|
2014-07-22 19:06:44 +02:00
|
|
|
break;
|
2017-06-29 14:59:07 +02:00
|
|
|
if (currentElement.language() == pathAndLanguage.language())
|
|
|
|
|
return false;
|
2014-07-22 19:06:44 +02:00
|
|
|
++j;
|
|
|
|
|
if (j == m_list.length())
|
|
|
|
|
break;
|
|
|
|
|
currentElement = m_list.at(j);
|
|
|
|
|
} while (currentElement.path() == pathAndLanguage.path());
|
|
|
|
|
m_list.insert(j, pathAndLanguage);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_list.append(pathAndLanguage);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 10:25:54 +01:00
|
|
|
void PathsAndLanguages::compact()
|
|
|
|
|
{
|
|
|
|
|
if (m_list.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2014-07-22 19:06:44 +02:00
|
|
|
int oldCompactionPlace = 0;
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath oldPath = m_list.first().path();
|
2014-07-22 19:06:44 +02:00
|
|
|
QList<PathAndLanguage> compactedList;
|
|
|
|
|
bool restrictFailed = false;
|
|
|
|
|
for (int i = 1; i < m_list.length(); ++i) {
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath newPath = m_list.at(i).path();
|
2014-07-22 19:06:44 +02:00
|
|
|
if (newPath == oldPath) {
|
|
|
|
|
int newCompactionPlace = i - 1;
|
|
|
|
|
compactedList << m_list.mid(oldCompactionPlace, newCompactionPlace - oldCompactionPlace);
|
|
|
|
|
LanguageMerger merger;
|
|
|
|
|
merger.merge(m_list.at(i - 1).language());
|
|
|
|
|
do {
|
2014-07-31 09:43:02 +02:00
|
|
|
merger.merge(m_list.at(i).language());
|
2014-07-22 19:06:44 +02:00
|
|
|
if (++i == m_list.length())
|
|
|
|
|
break;
|
|
|
|
|
newPath = m_list.at(i).path();
|
|
|
|
|
} while (newPath == oldPath);
|
|
|
|
|
oldCompactionPlace = i;
|
|
|
|
|
compactedList << PathAndLanguage(oldPath, merger.mergedLanguage());
|
|
|
|
|
if (merger.restrictFailed())
|
|
|
|
|
restrictFailed = true;
|
|
|
|
|
}
|
|
|
|
|
oldPath = newPath;
|
|
|
|
|
}
|
|
|
|
|
if (oldCompactionPlace == 0)
|
|
|
|
|
return;
|
2014-07-31 10:22:37 +02:00
|
|
|
compactedList << m_list.mid(oldCompactionPlace);
|
2014-07-22 19:06:44 +02:00
|
|
|
if (restrictFailed)
|
|
|
|
|
qCWarning(qmljsLog) << "failed to restrict PathAndLanguages " << m_list;
|
|
|
|
|
m_list = compactedList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LanguageMerger::merge(Dialect l)
|
|
|
|
|
{
|
|
|
|
|
bool restrictSuccedeed = m_specificLanguage.restrictLanguage(l);
|
|
|
|
|
m_specificLanguage.mergeLanguage(m_minimalSpecificLanguage);
|
|
|
|
|
if (!restrictSuccedeed) {
|
|
|
|
|
m_minimalSpecificLanguage = m_specificLanguage;
|
|
|
|
|
m_restrictFailed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace QmlJS
|