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