From 21c90bcc989cc18ba926cf4dbfbc9d2fce78dd63 Mon Sep 17 00:00:00 2001
From: Topi Reinio <topi.reinio@digia.com>
Date: Fri, 17 Apr 2015 14:57:21 +0200
Subject: [PATCH] qdoc: Sanitize anchors in URLs for functions

When QDoc constructs the full path to a documentation node, it
must construct a clean anchor reference. Intra-page links use
a different code path, so the links e.g. from Member Functions
list to their detailed descriptions always work, but using the
link command to link to functions with certain characters (such
as 'operator==') failed because the node name was used as-is and
not sanitized ('operator-eq-eq').

This change moves HtmlGenerator::cleanRef() static function to
its parent class, Generator, and takes it into use in
Generator::fullDocumentLocation().

Change-Id: Ic939ffa3ae0f4495ef2a30eff0d4a1de65ea3e8f
Task-number: QTBUG-45629
Reviewed-by: Martin Smith <martin.smith@digia.com>
---
 src/tools/qdoc/generator.cpp     | 57 ++++++++++++++++++++++++++++++--
 src/tools/qdoc/generator.h       |  1 +
 src/tools/qdoc/htmlgenerator.cpp | 57 ++------------------------------
 src/tools/qdoc/htmlgenerator.h   |  1 -
 4 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
index 2ff4df9bd78..d22ec507f69 100644
--- a/src/tools/qdoc/generator.cpp
+++ b/src/tools/qdoc/generator.cpp
@@ -419,6 +419,59 @@ QString Generator::fileName(const Node* node) const
     return name;
 }
 
+QString Generator::cleanRef(const QString& ref)
+{
+    QString clean;
+
+    if (ref.isEmpty())
+        return clean;
+
+    clean.reserve(ref.size() + 20);
+    const QChar c = ref[0];
+    const uint u = c.unicode();
+
+    if ((u >= 'a' && u <= 'z') ||
+            (u >= 'A' && u <= 'Z') ||
+            (u >= '0' && u <= '9')) {
+        clean += c;
+    } else if (u == '~') {
+        clean += "dtor.";
+    } else if (u == '_') {
+        clean += "underscore.";
+    } else {
+        clean += QLatin1Char('A');
+    }
+
+    for (int i = 1; i < (int) ref.length(); i++) {
+        const QChar c = ref[i];
+        const uint u = c.unicode();
+        if ((u >= 'a' && u <= 'z') ||
+                (u >= 'A' && u <= 'Z') ||
+                (u >= '0' && u <= '9') || u == '-' ||
+                u == '_' || u == ':' || u == '.') {
+            clean += c;
+        } else if (c.isSpace()) {
+            clean += QLatin1Char('-');
+        } else if (u == '!') {
+            clean += "-not";
+        } else if (u == '&') {
+            clean += "-and";
+        } else if (u == '<') {
+            clean += "-lt";
+        } else if (u == '=') {
+            clean += "-eq";
+        } else if (u == '>') {
+            clean += "-gt";
+        } else if (u == '#') {
+            clean += QLatin1Char('#');
+        } else {
+            clean += QLatin1Char('-');
+            clean += QString::number((int)u, 16);
+        }
+    }
+    return clean;
+}
+
 QMap<QString, QString>& Generator::formattingLeftMap()
 {
     return fmtLeftMaps[format()];
@@ -521,10 +574,10 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
             return fullDocumentLocation(functionNode->associatedProperty());
 
         else if (functionNode->overloadNumber() > 1)
-            anchorRef = QLatin1Char('#') + functionNode->name()
+            anchorRef = QLatin1Char('#') + cleanRef(functionNode->name())
                     + QLatin1Char('-') + QString::number(functionNode->overloadNumber());
         else
-            anchorRef = QLatin1Char('#') + functionNode->name();
+            anchorRef = QLatin1Char('#') + cleanRef(functionNode->name());
         break;
     }
     /*
diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h
index 6d0de8df44d..9a1672dac44 100644
--- a/src/tools/qdoc/generator.h
+++ b/src/tools/qdoc/generator.h
@@ -103,6 +103,7 @@ public:
     static bool useOutputSubdirs() { return useOutputSubdirs_; }
     static void setQmlTypeContext(QmlTypeNode* t) { qmlTypeContext_ = t; }
     static QmlTypeNode* qmlTypeContext() { return qmlTypeContext_; }
+    static QString cleanRef(const QString& ref);
 
 protected:
     virtual void beginSubPage(const InnerNode* node, const QString& fileName);
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index f0a23ac65ed..710ce08abbb 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -3355,7 +3355,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N
             out() << section.pluralMember;
         }
         out() << " inherited from <a href=\"" << fileName((*p).first)
-              << '#' << HtmlGenerator::cleanRef(section.name.toLower()) << "\">"
+              << '#' << Generator::cleanRef(section.name.toLower()) << "\">"
               << protectEnc((*p).first->plainFullName(relative))
               << "</a></li>\n";
         ++p;
@@ -3610,62 +3610,9 @@ void HtmlGenerator::generateLink(const Atom* atom, CodeMarker* marker)
     }
 }
 
-QString HtmlGenerator::cleanRef(const QString& ref)
-{
-    QString clean;
-
-    if (ref.isEmpty())
-        return clean;
-
-    clean.reserve(ref.size() + 20);
-    const QChar c = ref[0];
-    const uint u = c.unicode();
-
-    if ((u >= 'a' && u <= 'z') ||
-            (u >= 'A' && u <= 'Z') ||
-            (u >= '0' && u <= '9')) {
-        clean += c;
-    } else if (u == '~') {
-        clean += "dtor.";
-    } else if (u == '_') {
-        clean += "underscore.";
-    } else {
-        clean += QLatin1Char('A');
-    }
-
-    for (int i = 1; i < (int) ref.length(); i++) {
-        const QChar c = ref[i];
-        const uint u = c.unicode();
-        if ((u >= 'a' && u <= 'z') ||
-                (u >= 'A' && u <= 'Z') ||
-                (u >= '0' && u <= '9') || u == '-' ||
-                u == '_' || u == ':' || u == '.') {
-            clean += c;
-        } else if (c.isSpace()) {
-            clean += QLatin1Char('-');
-        } else if (u == '!') {
-            clean += "-not";
-        } else if (u == '&') {
-            clean += "-and";
-        } else if (u == '<') {
-            clean += "-lt";
-        } else if (u == '=') {
-            clean += "-eq";
-        } else if (u == '>') {
-            clean += "-gt";
-        } else if (u == '#') {
-            clean += QLatin1Char('#');
-        } else {
-            clean += QLatin1Char('-');
-            clean += QString::number((int)u, 16);
-        }
-    }
-    return clean;
-}
-
 QString HtmlGenerator::registerRef(const QString& ref)
 {
-    QString clean = HtmlGenerator::cleanRef(ref);
+    QString clean = Generator::cleanRef(ref);
 
     for (;;) {
         QString& prevRef = refMap[clean.toLower()];
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index efd38ea1045..4a2e158252b 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -85,7 +85,6 @@ public:
 
     QString protectEnc(const QString &string);
     static QString protect(const QString &string, const QString &encoding = "ISO-8859-1");
-    static QString cleanRef(const QString& ref);
     static QString sinceTitle(int i) { return sinceTitles[i]; }
 
 protected:
-- 
GitLab