From 4c2daa90ce558c3b4287edc97127471486a411d9 Mon Sep 17 00:00:00 2001
From: Nikolai Kosjar <nikolai.kosjar@digia.com>
Date: Fri, 29 Nov 2013 11:25:47 +0100
Subject: [PATCH] C++: Fix highlighting for lines with predefined macros

This adds definitions for the macros __FILE__, __LINE__, __DATE__ and
__TIME__ on demand.

As a side effect, this also introduces highlighting for the uses of
these macros.

Task-number: QTCREATORBUG-8036
Change-Id: Ib7546c7d45d2eecbc50c7883fc684e3497154405
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
Reviewed-by: hjk <hjk121@nokiamail.com>
---
 src/libs/cplusplus/Macro.h                    |  7 +++
 src/libs/cplusplus/pp-engine.cpp              | 18 ++++---
 src/plugins/cppeditor/cppeditor.cpp           |  6 ++-
 .../cppeditor/cppfollowsymbolundercursor.cpp  | 10 ++--
 src/plugins/cpptools/cppfindreferences.cpp    |  2 +
 .../cpphighlightingsupportinternal.cpp        |  3 ++
 .../checksymbols/tst_checksymbols.cpp         | 51 +++++++++++++++++++
 .../preprocessor/tst_preprocessor.cpp         |  6 ++-
 8 files changed, 88 insertions(+), 15 deletions(-)

diff --git a/src/libs/cplusplus/Macro.h b/src/libs/cplusplus/Macro.h
index a3d83b1f00d..1c340dba650 100644
--- a/src/libs/cplusplus/Macro.h
+++ b/src/libs/cplusplus/Macro.h
@@ -137,6 +137,12 @@ public:
     void setVariadic(bool isVariadic)
     { f._variadic = isVariadic; }
 
+    bool isPredefined() const
+    { return f._predefined; }
+
+    void setPredefined(bool isPredefined)
+    { f._predefined = isPredefined; }
+
     QString toString() const;
     QString toStringWithLineBreaks() const;
 
@@ -151,6 +157,7 @@ private:
         unsigned _hidden: 1;
         unsigned _functionLike: 1;
         unsigned _variadic: 1;
+        unsigned _predefined: 1;
     };
 
     QByteArray _name;
diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 05a7a083d38..4bbb229734b 100644
--- a/src/libs/cplusplus/pp-engine.cpp
+++ b/src/libs/cplusplus/pp-engine.cpp
@@ -917,23 +917,21 @@ bool Preprocessor::handleIdentifier(PPToken *tk)
             && macroNameRef[0] == '_'
             && macroNameRef[1] == '_') {
         PPToken newTk;
+        QByteArray txt;
         if (macroNameRef == ppLine) {
-            QByteArray txt = QByteArray::number(tk->lineno);
+            txt = QByteArray::number(tk->lineno);
             newTk = generateToken(T_STRING_LITERAL, txt.constData(), txt.size(), tk->lineno, false);
         } else if (macroNameRef == ppFile) {
-            QByteArray txt;
             txt.append('"');
             txt.append(m_env->currentFileUtf8);
             txt.append('"');
             newTk = generateToken(T_STRING_LITERAL, txt.constData(), txt.size(), tk->lineno, false);
         } else if (macroNameRef == ppDate) {
-            QByteArray txt;
             txt.append('"');
             txt.append(QDate::currentDate().toString().toUtf8());
             txt.append('"');
             newTk = generateToken(T_STRING_LITERAL, txt.constData(), txt.size(), tk->lineno, false);
         } else if (macroNameRef == ppTime) {
-            QByteArray txt;
             txt.append('"');
             txt.append(QTime::currentTime().toString().toUtf8());
             txt.append('"');
@@ -941,10 +939,14 @@ bool Preprocessor::handleIdentifier(PPToken *tk)
         }
 
         if (newTk.hasSource()) {
-            newTk.f.newline = tk->newline();
-            newTk.f.whitespace = tk->whitespace();
-            *tk = newTk;
-            return false;
+            Macro macro;
+            macro.setName(macroNameRef.toByteArray());
+            macro.setFileName(m_env->currentFile);
+            macro.setPredefined(true);
+            macro.setDefinition(txt, QVector<PPToken>() << newTk);
+            m_env->bind(macro);
+            if (m_client)
+                m_client->macroAdded(macro);
         }
     }
 
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 63d5bc2e5b7..740269efedb 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -797,10 +797,12 @@ const Macro *CPPEditorWidget::findCanonicalMacro(const QTextCursor &cursor, Docu
     if (const Macro *macro = doc->findMacroDefinitionAt(line)) {
         QTextCursor macroCursor = cursor;
         const QByteArray name = identifierUnderCursor(&macroCursor).toLatin1();
-        if (macro->name() == name)
+        if (macro->name() == name && !macro->isPredefined())
             return macro;
     } else if (const Document::MacroUse *use = doc->findMacroUseAt(cursor.position())) {
-        return &use->macro();
+        const Macro &macro = use->macro();
+        if (!macro.isPredefined())
+            return &macro;
     }
 
     return 0;
diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
index 19a5a3a5e59..050ba6ef8fb 100644
--- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
@@ -592,10 +592,12 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
             m_widget->showPreProcessorWidget();
         } else if (fileName != CppModelManagerInterface::configurationFileName()) {
             const Macro &macro = use->macro();
-            link.targetFileName = macro.fileName();
-            link.targetLine = macro.line();
-            link.linkTextStart = use->begin();
-            link.linkTextEnd = use->end();
+            if (!macro.isPredefined()) {
+                link.targetFileName = macro.fileName();
+                link.targetLine = macro.line();
+                link.linkTextStart = use->begin();
+                link.linkTextEnd = use->end();
+            }
         }
         return link;
     }
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index a1e9625e85d..17bc85f97da 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -558,6 +558,8 @@ restart_search:
         usages.clear();
         foreach (const Document::MacroUse &use, doc->macroUses()) {
             const Macro &useMacro = use.macro();
+            if (useMacro.isPredefined())
+                continue;
 
             if (useMacro.fileName() == macro.fileName()) { // Check if this is a match, but possibly against an outdated document.
                 if (source.isEmpty())
diff --git a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp b/src/plugins/cpptools/cpphighlightingsupportinternal.cpp
index 3009d45c169..d2a14170e46 100644
--- a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp
+++ b/src/plugins/cpptools/cpphighlightingsupportinternal.cpp
@@ -58,6 +58,9 @@ QFuture<TextEditor::HighlightingResult> CppHighlightingSupportInternal::highligh
 
     // Get macro definitions
     foreach (const CPlusPlus::Macro& macro, doc->definedMacros()) {
+        if (macro.isPredefined())
+            continue; // No "real" definition location
+
         int line, column;
         editor()->convertPosition(macro.offset(), &line, &column);
         ++column; //Highlighting starts at (column-1) --> compensate here
diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp
index 26ece497a03..9afbd315732 100644
--- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp
+++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp
@@ -175,6 +175,8 @@ private slots:
     void test_checksymbols_VirtualMethodUse();
     void test_checksymbols_LabelUse();
     void test_checksymbols_MacroUse();
+    void test_checksymbols_Macros__FILE__LINE__DATE__TIME__1();
+    void test_checksymbols_Macros__FILE__LINE__DATE__TIME__2();
     void test_checksymbols_FunctionUse();
     void test_checksymbols_PseudoKeywordUse();
     void test_checksymbols_StaticUse();
@@ -326,6 +328,55 @@ void tst_CheckSymbols::test_checksymbols_MacroUse()
     TestData::check(source, expectedUses, macroUses);
 }
 
+void tst_CheckSymbols::test_checksymbols_Macros__FILE__LINE__DATE__TIME__1()
+{
+    const QByteArray source =
+        "#define FILE_DATE_TIME __FILE__  \" / \"  __DATE__  \" / \"  __TIME__\n"
+        "#define LINE_NUMBER 0 + __LINE__\n"
+        "\n"
+        "void f()\n"
+        "{\n"
+        "    class Printer;\n"
+        "    Printer::printText(FILE_DATE_TIME); Printer::printInteger(LINE_NUMBER); Printer::nl();\n"
+        "    return;\n"
+        "}\n";
+    const QList<Use> expectedUses = QList<Use>()
+        << Use(4, 6, 1, CppHighlightingSupport::FunctionUse)
+        << Use(6, 11, 7, CppHighlightingSupport::TypeUse)
+        << Use(6, 11, 7, CppHighlightingSupport::TypeUse)
+        << Use(7, 5, 7, CppHighlightingSupport::TypeUse)
+        << Use(7, 41, 7, CppHighlightingSupport::TypeUse)
+        << Use(7, 77, 7, CppHighlightingSupport::TypeUse)
+           ;
+
+    TestData::check(source, expectedUses);
+}
+
+void tst_CheckSymbols::test_checksymbols_Macros__FILE__LINE__DATE__TIME__2()
+{
+    const QByteArray source =
+        "void f()\n"
+        "{\n"
+        "    class Printer;\n"
+        "    Printer::printInteger(__LINE__); Printer::printText(__FILE__); Printer::nl();\n"
+        "    Printer::printText(__DATE__); Printer::printText(__TIME__); Printer::nl();\n"
+        "    return;\n"
+        "}\n";
+    const QList<Use> expectedUses = QList<Use>()
+        << Use(1, 6, 1, CppHighlightingSupport::FunctionUse)
+        << Use(3, 11, 7, CppHighlightingSupport::TypeUse)
+        << Use(3, 11, 7, CppHighlightingSupport::TypeUse)
+        << Use(4, 5, 7, CppHighlightingSupport::TypeUse)
+        << Use(4, 38, 7, CppHighlightingSupport::TypeUse)
+        << Use(4, 68, 7, CppHighlightingSupport::TypeUse)
+        << Use(5, 5, 7, CppHighlightingSupport::TypeUse)
+        << Use(5, 35, 7, CppHighlightingSupport::TypeUse)
+        << Use(5, 65, 7, CppHighlightingSupport::TypeUse)
+           ;
+
+    TestData::check(source, expectedUses);
+}
+
 void tst_CheckSymbols::test_checksymbols_FunctionUse()
 {
     const QByteArray source =
diff --git a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp
index 2594bc692f6..489722d6759 100644
--- a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp
+++ b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp
@@ -796,7 +796,11 @@ void tst_Preprocessor::builtin__FILE__()
                            ));
     const QByteArray result____ =
             "# 1 \"some-file.c\"\n"
-            "const char *f = \"some-file.c\"\n";
+            "const char *f =\n"
+            "# expansion begin 16,8 ~1\n"
+            "\"some-file.c\"\n"
+            "# expansion end\n"
+            "# 2 \"some-file.c\"\n";
 
     QCOMPARE(preprocessed, result____);
 }
-- 
GitLab