From 3d6f7de90929971a25fcab12ad569b6bf6db92de Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Tue, 3 Mar 2009 13:46:37 +0100 Subject: [PATCH] Context-sensitive highlighting. --- src/libs/cplusplus/pp-engine.cpp | 2 +- src/plugins/cppeditor/cppeditor.cpp | 66 ++++++++++++++++++++++- src/plugins/cpptools/cppmodelmanager.cpp | 35 ++++++++---- src/shared/cplusplus/CheckDeclaration.cpp | 65 +++++++++++++++++----- src/shared/cplusplus/CheckSpecifier.cpp | 13 ++++- src/shared/cplusplus/Symbol.cpp | 18 ++++--- src/shared/cplusplus/Symbol.h | 1 + 7 files changed, 166 insertions(+), 34 deletions(-) diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index f90c02b9080..43e07619ddf 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -54,6 +54,7 @@ #include <QtDebug> #include <algorithm> +#include <cctype> namespace CPlusPlus { @@ -694,7 +695,6 @@ void Preprocessor::preprocess(const QByteArray &fileName, const QByteArray &sour else if (_dot->whitespace) { TokenIterator begin = _tokens.constBegin(); - Q_ASSERT(begin != first); const unsigned endOfPreviousToken = (_dot - 1)->end(); const unsigned beginOfToken = _dot->begin(); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index b8c260fd04b..1ca1c9f72d9 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -392,12 +392,67 @@ void CPPEditor::updateMethodBoxIndex() lastIndex = index; } + QList<QTextEdit::ExtraSelection> selections; + if (lastIndex.isValid()) { bool blocked = m_methodCombo->blockSignals(true); m_methodCombo->setCurrentIndex(lastIndex.row()); updateMethodBoxToolTip(); (void) m_methodCombo->blockSignals(blocked); } + +#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER + Snapshot snapshot = m_modelManager->snapshot(); + Document::Ptr thisDocument = snapshot.value(file()->fileName()); + if (! thisDocument) + return; + + if (Symbol *symbol = thisDocument->findSymbolAt(line, column)) { + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::EndOfWord); + + ExpressionUnderCursor expressionUnderCursor; + + const QString expression = expressionUnderCursor(tc); + //qDebug() << "expression:" << expression; + + TypeOfExpression typeOfExpression; + typeOfExpression.setSnapshot(m_modelManager->snapshot()); + + const QList<TypeOfExpression::Result> results = + typeOfExpression(expression, thisDocument, symbol, TypeOfExpression::Preprocess); + + LookupContext context = typeOfExpression.lookupContext(); + + foreach (const TypeOfExpression::Result &result, results) { + FullySpecifiedType ty = result.first; + Symbol *symbol = result.second; + + if (file()->fileName() != symbol->fileName()) + continue; + + if (symbol) { + int column = symbol->column(); + + if (column != 0) + --column; + + QTextCursor c(document()->findBlockByNumber(symbol->line() - 1)); + c.setPosition(c.position() + column); + c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + + QTextEdit::ExtraSelection sel; + sel.cursor = c; + sel.format.setBackground(Qt::darkYellow); + + selections.append(sel); + //break; + } + } + } + + setExtraSelections(CodeSemanticsSelection, selections); +#endif // QTCREATOR_WITH_ADVANCED_HIGHLIGHTER } void CPPEditor::updateMethodBoxToolTip() @@ -893,5 +948,14 @@ TextEditor::ITextEditor *CPPEditor::openCppEditorAt(const QString &fileName, bool CPPEditor::openEditorAt(Symbol *s) { const QString fileName = QString::fromUtf8(s->fileName(), s->fileNameLength()); - return openCppEditorAt(fileName, s->line(), s->column()); + +#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER + unsigned column = s->column(); + if (column) + --column; +#else + unsigned column = 0; +#endif + + return openCppEditorAt(fileName, s->line(), column); } diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index b4db1925358..175f6a4b7e9 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -815,14 +815,17 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); warningFormat.setUnderlineColor(Qt::darkYellow); - QSet<int> lines; + QSet<QPair<unsigned, unsigned> > lines; foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) { if (m.fileName() != fileName) continue; - else if (lines.contains(m.line())) + + const QPair<unsigned, unsigned> coordinates = qMakePair(m.line(), m.column()); + + if (lines.contains(coordinates)) continue; - lines.insert(m.line()); + lines.insert(coordinates); QTextEdit::ExtraSelection sel; if (m.isWarning()) @@ -831,14 +834,28 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) sel.format = errorFormat; QTextCursor c(ed->document()->findBlockByNumber(m.line() - 1)); - const QString text = c.block().text(); - for (int i = 0; i < text.size(); ++i) { - if (! text.at(i).isSpace()) { - c.setPosition(c.position() + i); - break; + + // ### check for generated tokens. + + int column = m.column(); + + if (column > c.block().length()) { + column = 0; + + const QString text = c.block().text(); + for (int i = 0; i < text.size(); ++i) { + if (! text.at(i).isSpace()) { + ++column; + break; + } } } - c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + + if (column != 0) + --column; + + c.setPosition(c.position() + column); + c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); sel.cursor = c; selections.append(sel); } diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp index cc924ed4642..06b85f8c5b1 100644 --- a/src/shared/cplusplus/CheckDeclaration.cpp +++ b/src/shared/cplusplus/CheckDeclaration.cpp @@ -134,10 +134,15 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) if (! ast->declarators && ast->decl_specifier_seq && ! ast->decl_specifier_seq->next) { if (ElaboratedTypeSpecifierAST *elab_type_spec = ast->decl_specifier_seq->asElaboratedTypeSpecifier()) { + + unsigned sourceLocation = elab_type_spec->firstToken(); + + if (elab_type_spec->name) + sourceLocation = elab_type_spec->name->firstToken(); + Name *name = semantic()->check(elab_type_spec->name, _scope); ForwardClassDeclaration *symbol = - control()->newForwardClassDeclaration(elab_type_spec->firstToken(), - name); + control()->newForwardClassDeclaration(sourceLocation, name); if (_templateParameters) { symbol->setTemplateParameters(_templateParameters); @@ -155,8 +160,15 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) FullySpecifiedType declTy = semantic()->check(it->declarator, qualTy, _scope, &name); + unsigned location = 0; + if (it->declarator) + location = it->declarator->firstToken(); + else + location = ast->firstToken(); + Function *fun = 0; if (declTy && 0 != (fun = declTy->asFunctionType())) { + fun->setSourceLocation(location); fun->setScope(_scope); fun->setName(name); fun->setMethodKey(semantic()->currentMethodKey()); @@ -166,12 +178,6 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) "expected a function declaration"); } - unsigned location = 0; - if (it->declarator) - location = it->declarator->firstToken(); - else - location = ast->firstToken(); - Declaration *symbol = control()->newDeclaration(location, name); symbol->setType(control()->integerType(IntegerType::Int)); symbol->setType(declTy); @@ -246,6 +252,8 @@ bool CheckDeclaration::visit(FunctionDefinitionAST *ast) } Function *fun = funTy->asFunctionType(); + if (ast->declarator) + fun->setSourceLocation(ast->declarator->firstToken()); fun->setName(name); fun->setTemplateParameters(_templateParameters); fun->setVisibility(semantic()->currentVisibility()); @@ -305,7 +313,13 @@ bool CheckDeclaration::visit(NamespaceAST *ast) { Identifier *id = identifier(ast->identifier_token); Name *namespaceName = control()->nameId(id); - Namespace *ns = control()->newNamespace(ast->firstToken(), namespaceName); + + unsigned sourceLocation = ast->firstToken(); + + if (ast->identifier_token) + sourceLocation = ast->identifier_token; + + Namespace *ns = control()->newNamespace(sourceLocation, namespaceName); ast->symbol = ns; _scope->enterSymbol(ns); semantic()->check(ast->linkage_body, ns->members()); // ### we'll do the merge later. @@ -325,12 +339,17 @@ bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *) bool CheckDeclaration::visit(ParameterDeclarationAST *ast) { + unsigned sourceLocation = 0; + + if (ast->declarator) + sourceLocation = ast->declarator->firstToken(); + Name *argName = 0; FullySpecifiedType ty = semantic()->check(ast->type_specifier, _scope); FullySpecifiedType argTy = semantic()->check(ast->declarator, ty.qualifiedType(), _scope, &argName); FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope); - Argument *arg = control()->newArgument(ast->firstToken(), argName); + Argument *arg = control()->newArgument(sourceLocation, argName); ast->symbol = arg; if (ast->expression) arg->setInitializer(true); @@ -354,8 +373,12 @@ bool CheckDeclaration::visit(TemplateDeclarationAST *ast) bool CheckDeclaration::visit(TypenameTypeParameterAST *ast) { + unsigned sourceLocation = ast->firstToken(); + if (ast->name) + sourceLocation = ast->name->firstToken(); + Name *name = semantic()->check(ast->name, _scope); - Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type + Argument *arg = control()->newArgument(sourceLocation, name); // ### new template type ast->symbol = arg; _scope->enterSymbol(arg); return false; @@ -363,8 +386,12 @@ bool CheckDeclaration::visit(TypenameTypeParameterAST *ast) bool CheckDeclaration::visit(TemplateTypeParameterAST *ast) { + unsigned sourceLocation = ast->firstToken(); + if (ast->name) + sourceLocation = ast->name->firstToken(); + Name *name = semantic()->check(ast->name, _scope); - Argument *arg = control()->newArgument(ast->firstToken(), name); // ### new template type + Argument *arg = control()->newArgument(sourceLocation, name); // ### new template type ast->symbol = arg; _scope->enterSymbol(arg); return false; @@ -373,7 +400,12 @@ bool CheckDeclaration::visit(TemplateTypeParameterAST *ast) bool CheckDeclaration::visit(UsingAST *ast) { Name *name = semantic()->check(ast->name, _scope); - UsingDeclaration *u = control()->newUsingDeclaration(ast->firstToken(), name); + + unsigned sourceLocation = ast->firstToken(); + if (ast->name) + sourceLocation = ast->name->firstToken(); + + UsingDeclaration *u = control()->newUsingDeclaration(sourceLocation, name); ast->symbol = u; _scope->enterSymbol(u); return false; @@ -382,7 +414,12 @@ bool CheckDeclaration::visit(UsingAST *ast) bool CheckDeclaration::visit(UsingDirectiveAST *ast) { Name *name = semantic()->check(ast->name, _scope); - UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name); + + unsigned sourceLocation = ast->firstToken(); + if (ast->name) + sourceLocation = ast->name->firstToken(); + + UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(sourceLocation, name); ast->symbol = u; _scope->enterSymbol(u); diff --git a/src/shared/cplusplus/CheckSpecifier.cpp b/src/shared/cplusplus/CheckSpecifier.cpp index cd26423cfd6..e79f6aa0ba6 100644 --- a/src/shared/cplusplus/CheckSpecifier.cpp +++ b/src/shared/cplusplus/CheckSpecifier.cpp @@ -296,8 +296,13 @@ bool CheckSpecifier::visit(SimpleSpecifierAST *ast) bool CheckSpecifier::visit(ClassSpecifierAST *ast) { + unsigned sourceLocation = ast->firstToken(); + + if (ast->name) + sourceLocation = ast->name->firstToken(); + Name *className = semantic()->check(ast->name, _scope); - Class *klass = control()->newClass(ast->firstToken(), className); + Class *klass = control()->newClass(sourceLocation, className); ast->symbol = klass; unsigned classKey = tokenKind(ast->classkey_token); if (classKey == T_CLASS) @@ -358,8 +363,12 @@ bool CheckSpecifier::visit(ElaboratedTypeSpecifierAST *ast) bool CheckSpecifier::visit(EnumSpecifierAST *ast) { + unsigned sourceLocation = ast->firstToken(); + if (ast->name) + sourceLocation = ast->name->firstToken(); + Name *name = semantic()->check(ast->name, _scope); - Enum *e = control()->newEnum(ast->firstToken(), name); + Enum *e = control()->newEnum(sourceLocation, name); e->setVisibility(semantic()->currentVisibility()); _scope->enterSymbol(e); _fullySpecifiedType.setType(e); diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp index f8e25f4fbf7..da677aa3b21 100644 --- a/src/shared/cplusplus/Symbol.cpp +++ b/src/shared/cplusplus/Symbol.cpp @@ -166,9 +166,7 @@ Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name * _index(0), _next(0) { - if (sourceLocation) - _sourceOffset = translationUnit->tokenAt(sourceLocation).offset; - + setSourceLocation(sourceLocation); setName(name); } @@ -202,6 +200,16 @@ unsigned Symbol::sourceLocation() const unsigned Symbol::sourceOffset() const { return _sourceOffset; } +void Symbol::setSourceLocation(unsigned sourceLocation) +{ + _sourceLocation = sourceLocation; + + if (_sourceLocation) + _sourceOffset = translationUnit()->tokenAt(sourceLocation).offset; + else + _sourceOffset = 0; +} + unsigned Symbol::line() const { unsigned line = 0, column = 0; @@ -212,14 +220,10 @@ unsigned Symbol::line() const unsigned Symbol::column() const { -#ifdef CPLUSPLUS_WITH_COLUMNS unsigned line = 0, column = 0; StringLiteral *fileId = 0; translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId); return column; -#else - return 0; -#endif } StringLiteral *Symbol::fileId() const diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h index dc846bd3396..ea49529e74d 100644 --- a/src/shared/cplusplus/Symbol.h +++ b/src/shared/cplusplus/Symbol.h @@ -234,6 +234,7 @@ public: Name *identity() const; void setScope(Scope *scope); // ### make me private + void setSourceLocation(unsigned sourceLocation); // ### make me private void visitSymbol(SymbolVisitor *visitor); static void visitSymbol(Symbol *symbol, SymbolVisitor *visitor); -- GitLab