Skip to content
Snippets Groups Projects
Commit ba3e68fc authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Try to get the type of the qualified name id under cursor

parent 4b97bf17
No related branches found
No related tags found
No related merge requests found
......@@ -42,8 +42,7 @@ using namespace QmlJS::AST;
Document::Document(const QString &fileName)
: _engine(0)
, _pool(0)
, _uiProgram(0)
, _jsProgram(0)
, _ast(0)
, _fileName(fileName)
, _parsedCorrectly(false)
{
......@@ -74,20 +73,17 @@ Document::Ptr Document::create(const QString &fileName)
AST::UiProgram *Document::qmlProgram() const
{
return _uiProgram;
return cast<UiProgram *>(_ast);
}
AST::Program *Document::jsProgram() const
{
return _jsProgram;
return cast<Program *>(_ast);
}
AST::Node *Document::ast() const
{
Q_ASSERT(!_uiProgram || !_jsProgram);
if (_uiProgram)
return _uiProgram;
return _jsProgram;
return _ast;
}
QList<DiagnosticMessage> Document::diagnosticMessages() const
......@@ -109,8 +105,7 @@ bool Document::parseQml()
{
Q_ASSERT(! _engine);
Q_ASSERT(! _pool);
Q_ASSERT(! _uiProgram);
Q_ASSERT(! _jsProgram);
Q_ASSERT(! _ast);
_engine = new Engine();
_pool = new NodePool(_fileName, _engine);
......@@ -122,11 +117,11 @@ bool Document::parseQml()
lexer.setCode(_source, /*line = */ 1);
_parsedCorrectly = parser.parse();
_uiProgram = parser.ast();
_ast = parser.ast();
_diagnosticMessages = parser.diagnosticMessages();
if (_uiProgram) {
for (QmlJS::AST::UiObjectMemberList *iter = _uiProgram->members; iter; iter = iter->next)
if (qmlProgram()) {
for (QmlJS::AST::UiObjectMemberList *iter = qmlProgram()->members; iter; iter = iter->next)
if (iter->member)
_symbols.append(new SymbolFromFile(_fileName, iter->member));
......@@ -143,8 +138,7 @@ bool Document::parseJavaScript()
{
Q_ASSERT(! _engine);
Q_ASSERT(! _pool);
Q_ASSERT(! _uiProgram);
Q_ASSERT(! _jsProgram);
Q_ASSERT(! _ast);
_engine = new Engine();
_pool = new NodePool(_fileName, _engine);
......@@ -156,7 +150,31 @@ bool Document::parseJavaScript()
lexer.setCode(_source, /*line = */ 1);
_parsedCorrectly = parser.parseProgram();
_jsProgram = cast<Program*>(parser.rootNode());
_ast = cast<Program*>(parser.rootNode());
_diagnosticMessages = parser.diagnosticMessages();
return _parsedCorrectly;
}
bool Document::parseExpression()
{
Q_ASSERT(! _engine);
Q_ASSERT(! _pool);
Q_ASSERT(! _ast);
_engine = new Engine();
_pool = new NodePool(_fileName, _engine);
_ids.clear();
Lexer lexer(_engine);
Parser parser(_engine);
lexer.setCode(_source, /*line = */ 1);
_parsedCorrectly = parser.parseExpression();
_ast = parser.rootNode();
if (_ast)
_ast = _ast->expressionCast();
_diagnosticMessages = parser.diagnosticMessages();
return _parsedCorrectly;
......
......@@ -67,6 +67,7 @@ public:
bool parseQml();
bool parseJavaScript();
bool parseExpression();
bool isParsedCorrectly() const
{ return _parsedCorrectly; }
......@@ -84,8 +85,7 @@ public:
private:
QmlJS::Engine *_engine;
QmlJS::NodePool *_pool;
QmlJS::AST::UiProgram *_uiProgram;
QmlJS::AST::Program *_jsProgram;
QmlJS::AST::Node *_ast;
QList<QmlJS::DiagnosticMessage> _diagnosticMessages;
QString _fileName;
QString _path;
......
......@@ -50,6 +50,7 @@
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace QmlJS;
// Temporary workaround until we have proper icons for QML completion items
......@@ -83,6 +84,7 @@ static QIcon iconForColor(const QColor &color)
return pix;
}
namespace {
class Evaluate: public QmlJS::AST::Visitor
{
......@@ -181,6 +183,46 @@ protected:
};
class EnumerateProperties
{
QSet<const Interpreter::ObjectValue *> _processed;
QHash<QString, const Interpreter::Value *> _properties;
public:
QHash<QString, const Interpreter::Value *> operator()(const Interpreter::Value *value)
{
_processed.clear();
_properties.clear();
enumerateProperties(value);
return _properties;
}
private:
void enumerateProperties(const Interpreter::Value *value)
{
if (! value)
return;
else if (const Interpreter::ObjectValue *object = value->asObjectValue()) {
enumerateProperties(object);
}
}
void enumerateProperties(const Interpreter::ObjectValue *object)
{
if (! object || _processed.contains(object))
return;
_processed.insert(object);
enumerateProperties(object->prototype());
for (Interpreter::ObjectValue::MemberIterator it = object->firstMember(); it != object->lastMember(); ++it) {
_properties.insert(it.key(), it.value());
}
}
};
} // end of anonymous namespace
QmlCodeCompletion::QmlCodeCompletion(QmlModelManagerInterface *modelManager, QmlJS::TypeSystem *typeSystem, QObject *parent)
: TextEditor::ICompletionCollector(parent),
m_modelManager(modelManager),
......@@ -248,32 +290,33 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
const QIcon typeIcon = iconForColor(Qt::yellow);
foreach (QmlJS::Document::Ptr doc, snapshot) {
const QFileInfo fileInfo(doc->fileName());
if (fileInfo.suffix() != QLatin1String("qml"))
continue;
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME includ `imported' components
continue;
const QString typeName = fileInfo.baseName();
if (typeName.isEmpty())
continue;
if (typeName.at(0).isUpper()) {
TextEditor::CompletionItem item(this);
item.text = typeName;
item.icon = typeIcon;
m_completions.append(item);
}
}
QChar previousChar;
if (m_startPosition > 0)
previousChar = editor->characterAt(m_startPosition - 1);
if (previousChar.isSpace() || previousChar.isNull()) {
// ### FIXME
// Add the visible components to the completion box.
foreach (QmlJS::Document::Ptr doc, snapshot) {
const QFileInfo fileInfo(doc->fileName());
if (fileInfo.suffix() != QLatin1String("qml"))
continue;
else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME includ `imported' components
continue;
const QString typeName = fileInfo.baseName();
if (typeName.isEmpty())
continue;
if (typeName.at(0).isUpper()) {
TextEditor::CompletionItem item(this);
item.text = typeName;
item.icon = typeIcon;
m_completions.append(item);
}
}
// Add the visible IDs to the completion box
const QIcon idIcon = iconForColor(Qt::darkGray);
QStringList ids = qmlDocument->ids().keys();
foreach (const QString &id, ids) {
......@@ -287,54 +330,53 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
}
}
#if 0
// FIXME: this completion strategy is not going to work when the document was never parsed correctly.
if (qmlDocument->qmlProgram() != 0) {
const QIcon otherIcon = iconForColor(Qt::darkCyan);
if (previousChar == QLatin1Char('.')) {
const int endOfExpression = m_startPosition - 1;
int startOfExpression = endOfExpression - 2;
// qDebug() << "*** program:" << program;
QmlExpressionUnderCursor expressionUnderCursor;
QTextCursor cursor(edit->document());
cursor.setPosition(pos);
expressionUnderCursor(cursor, qmlDocument);
while (startOfExpression >= 0) {
const QChar ch = editor->characterAt(startOfExpression);
QmlLookupContext context(expressionUnderCursor.expressionScopes(), qmlDocument, m_modelManager->snapshot(), m_typeSystem);
QmlResolveExpression resolver(context);
if (ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.'))
--startOfExpression;
else
break;
}
++startOfExpression;
QmlJS::AST::Node *expr = expressionUnderCursor.expressionNode();
const QString expression = m_editor->textAt(startOfExpression, endOfExpression - startOfExpression);
//qDebug() << "expression:" << expression;
QmlJS::Interpreter::Engine engine;
Evaluate evaluate(&engine);
if (const QmlJS::Interpreter::Value *value = evaluate(expr)) {
if (const QmlJS::Interpreter::ObjectValue *object = value->asObjectValue()) {
for (QmlJS::Interpreter::ObjectValue::MemberIterator it = object->firstMember(); it != object->lastMember(); ++it) {
TextEditor::CompletionItem item(this);
item.text = it.key();
item.icon = otherIcon;
m_completions.append(item);
}
return pos;
}
}
QmlJS::Document::Ptr exprDoc = QmlJS::Document::create(QLatin1String("<expression>"));
exprDoc->setSource(expression);
exprDoc->parseExpression();
if (exprDoc->ast()) {
Interpreter::Engine interp;
Evaluate evaluate(&interp);
const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->ast()));
//qDebug() << "type:" << interp.typeId(value);
// qDebug()<<"*** expression under cursor:"<<expressionUnderCursor.expressionNode();
const QList<QmlJS::Symbol*> symbols = resolver.visibleSymbols(expressionUnderCursor.expressionNode());
// qDebug()<<"***"<<symbols.size()<<"visible symbols";
const QIcon symbolIcon = iconForColor(Qt::darkCyan);
foreach (QmlJS::Symbol *symbol, symbols) {
if (symbol->isIdSymbol())
continue; // nothing to do here.
EnumerateProperties enumerateProperties;
QHashIterator<QString, const Interpreter::Value *> it(enumerateProperties(value));
while (it.hasNext()) {
it.next();
const QString word = symbol->name();
if (! word.isEmpty()) {
TextEditor::CompletionItem item(this);
item.text = word;
item.icon = otherIcon;
item.text = it.key();
item.icon = symbolIcon;
m_completions.append(item);
}
}
if (! m_completions.isEmpty())
return m_startPosition;
return -1;
}
#endif
if (previousChar.isNull()
|| previousChar.isSpace()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment