From 4c5ff047f0a1831d1247ca73d889b283d01fd3fb Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Fri, 20 Feb 2009 11:52:27 +0100
Subject: [PATCH] Initial support for doxygen comments.

---
 src/libs/cplusplus/SimpleLexer.cpp         |    5 +
 src/libs/cplusplus/SimpleLexer.h           |    1 +
 src/plugins/cppeditor/cppdoxygen.cpp       | 1512 ++++++++++++++++++++
 src/plugins/cppeditor/cppdoxygen.h         |  160 +++
 src/plugins/cppeditor/cppeditor.pro        |    8 +-
 src/plugins/cppeditor/cpphighlighter.cpp   |   58 +-
 src/plugins/cppeditor/cpphighlighter.h     |    4 +
 src/plugins/cpptools/cppcodecompletion.cpp |    2 +-
 src/plugins/cpptools/cpptools.pro          |   36 +-
 src/shared/cplusplus/Lexer.cpp             |   42 +-
 src/shared/cplusplus/Lexer.h               |    5 +-
 src/shared/cplusplus/Token.cpp             |    2 +-
 src/shared/cplusplus/Token.h               |    4 +
 13 files changed, 1803 insertions(+), 36 deletions(-)
 create mode 100644 src/plugins/cppeditor/cppdoxygen.cpp
 create mode 100644 src/plugins/cppeditor/cppdoxygen.h

diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp
index 5efa1f02d8c..85ad6e645de 100644
--- a/src/libs/cplusplus/SimpleLexer.cpp
+++ b/src/libs/cplusplus/SimpleLexer.cpp
@@ -54,6 +54,11 @@ bool SimpleToken::isKeyword() const
     return _kind >= T_FIRST_KEYWORD && _kind < T_FIRST_QT_KEYWORD;
 }
 
+bool SimpleToken::isComment() const
+{
+    return _kind == T_COMMENT || _kind == T_DOXY_COMMENT;
+}
+
 SimpleLexer::SimpleLexer()
     : _lastState(0),
       _skipComments(false),
diff --git a/src/libs/cplusplus/SimpleLexer.h b/src/libs/cplusplus/SimpleLexer.h
index ed48e9360bf..cbcb4e1f6bb 100644
--- a/src/libs/cplusplus/SimpleLexer.h
+++ b/src/libs/cplusplus/SimpleLexer.h
@@ -69,6 +69,7 @@ public:
     bool isLiteral() const;
     bool isOperator() const;
     bool isKeyword() const;
+    bool isComment() const;
 
 public:
     int _kind;
diff --git a/src/plugins/cppeditor/cppdoxygen.cpp b/src/plugins/cppeditor/cppdoxygen.cpp
new file mode 100644
index 00000000000..21ea204d832
--- /dev/null
+++ b/src/plugins/cppeditor/cppdoxygen.cpp
@@ -0,0 +1,1512 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file.  Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include <QString>
+#include "cppdoxygen.h"
+
+using namespace CppEditor::Internal;
+
+/*
+
+~
+@
+$
+\
+#
+f[
+f]
+f$
+
+*/
+static inline int classify1(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    return T_DOXY_A;
+  }
+  else if (s[0].unicode() == 'b') {
+    return T_DOXY_B;
+  }
+  else if (s[0].unicode() == 'c') {
+    return T_DOXY_C;
+  }
+  else if (s[0].unicode() == 'e') {
+    return T_DOXY_E;
+  }
+  else if (s[0].unicode() == 'n') {
+    return T_DOXY_N;
+  }
+  else if (s[0].unicode() == 'p') {
+    return T_DOXY_P;
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify2(const QChar *s) {
+  if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'm') {
+      return T_DOXY_EM;
+    }
+  }
+  else if (s[0].unicode() == 'f') {
+    if (s[1].unicode() == 'n') {
+      return T_DOXY_FN;
+    }
+  }
+  else if (s[0].unicode() == 'i') {
+    if (s[1].unicode() == 'f') {
+      return T_DOXY_IF;
+    }
+  }
+  else if (s[0].unicode() == 'l') {
+    if (s[1].unicode() == 'i') {
+      return T_DOXY_LI;
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'a') {
+      return T_DOXY_SA;
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify3(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    if (s[1].unicode() == 'r') {
+      if (s[2].unicode() == 'g') {
+        return T_DOXY_ARG;
+      }
+    }
+  }
+  else if (s[0].unicode() == 'b') {
+    if (s[1].unicode() == 'u') {
+      if (s[2].unicode() == 'g') {
+        return T_DOXY_BUG;
+      }
+    }
+  }
+  else if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'f') {
+        return T_DOXY_DEF;
+      }
+    }
+    else if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 't') {
+        return T_DOXY_DOT;
+      }
+    }
+  }
+  else if (s[0].unicode() == 'p') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'r') {
+        return T_DOXY_PAR;
+      }
+    }
+    else if (s[1].unicode() == 'r') {
+      if (s[2].unicode() == 'e') {
+        return T_DOXY_PRE;
+      }
+    }
+  }
+  else if (s[0].unicode() == 'r') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'f') {
+        return T_DOXY_REF;
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'e') {
+        return T_DOXY_SEE;
+      }
+    }
+  }
+  else if (s[0].unicode() == 'v') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'r') {
+        return T_DOXY_VAR;
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify4(const QChar *s) {
+  if (s[0].unicode() == 'c') {
+    if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_CODE;
+        }
+      }
+      else if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 'd') {
+          return T_DOXY_COND;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_DATE;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'l') {
+      if (s[2].unicode() == 's') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_ELSE;
+        }
+      }
+    }
+    else if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'u') {
+        if (s[3].unicode() == 'm') {
+          return T_DOXY_ENUM;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'f') {
+    if (s[1].unicode() == 'i') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_FILE;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'l') {
+    if (s[1].unicode() == 'i') {
+      if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_LINE;
+        }
+        else if (s[3].unicode() == 'k') {
+          return T_DOXY_LINK;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'n') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'm') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_NAME;
+        }
+      }
+    }
+    else if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_NOTE;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'o') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'y') {
+          return T_DOXY_ONLY;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'p') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'g') {
+        if (s[3].unicode() == 'e') {
+          return T_DOXY_PAGE;
+        }
+      }
+    }
+    else if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 's') {
+        if (s[3].unicode() == 't') {
+          return T_DOXY_POST;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'k') {
+      if (s[2].unicode() == 'i') {
+        if (s[3].unicode() == 'p') {
+          return T_DOXY_SKIP;
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 't') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 's') {
+        if (s[3].unicode() == 't') {
+          return T_DOXY_TEST;
+        }
+      }
+    }
+    else if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'o') {
+          return T_DOXY_TODO;
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify5(const QChar *s) {
+  if (s[0].unicode() == 'b') {
+    if (s[1].unicode() == 'r') {
+      if (s[2].unicode() == 'i') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'f') {
+            return T_DOXY_BRIEF;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'c') {
+    if (s[1].unicode() == 'l') {
+      if (s[2].unicode() == 'a') {
+        if (s[3].unicode() == 's') {
+          if (s[4].unicode() == 's') {
+            return T_DOXY_CLASS;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'i') {
+          if (s[4].unicode() == 'f') {
+            return T_DOXY_ENDIF;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'i') {
+    if (s[1].unicode() == 'f') {
+      if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 't') {
+            return T_DOXY_IFNOT;
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'm') {
+      if (s[2].unicode() == 'a') {
+        if (s[3].unicode() == 'g') {
+          if (s[4].unicode() == 'e') {
+            return T_DOXY_IMAGE;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'p') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 'm') {
+            return T_DOXY_PARAM;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'h') {
+      if (s[2].unicode() == 'o') {
+        if (s[3].unicode() == 'r') {
+          if (s[4].unicode() == 't') {
+            return T_DOXY_SHORT;
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'i') {
+      if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 'c') {
+          if (s[4].unicode() == 'e') {
+            return T_DOXY_SINCE;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 't') {
+    if (s[1].unicode() == 'h') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 'w') {
+            return T_DOXY_THROW;
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'u') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'i') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 'n') {
+            return T_DOXY_UNION;
+          }
+        }
+      }
+      else if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'i') {
+          if (s[4].unicode() == 'l') {
+            return T_DOXY_UNTIL;
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify6(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 'h') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'r') {
+              return T_DOXY_ANCHOR;
+            }
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'u') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'h') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'r') {
+              return T_DOXY_AUTHOR;
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'l') {
+      if (s[2].unicode() == 's') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'f') {
+              return T_DOXY_ELSEIF;
+            }
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'd') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 't') {
+              return T_DOXY_ENDDOT;
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'r') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'u') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'n') {
+              return T_DOXY_RETURN;
+            }
+          }
+        }
+        else if (s[3].unicode() == 'v') {
+          if (s[4].unicode() == 'a') {
+            if (s[5].unicode() == 'l') {
+              return T_DOXY_RETVAL;
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 't') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'u') {
+          if (s[4].unicode() == 'c') {
+            if (s[5].unicode() == 't') {
+              return T_DOXY_STRUCT;
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 't') {
+    if (s[1].unicode() == 'h') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 'w') {
+            if (s[5].unicode() == 's') {
+              return T_DOXY_THROWS;
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify7(const QChar *s) {
+  if (s[0].unicode() == 'c') {
+    if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 'p') {
+        if (s[3].unicode() == 'y') {
+          if (s[4].unicode() == 'd') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'c') {
+                return T_DOXY_COPYDOC;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'f') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'l') {
+              if (s[6].unicode() == 'e') {
+                return T_DOXY_DOTFILE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'c') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'd') {
+              if (s[6].unicode() == 'e') {
+                return T_DOXY_ENDCODE;
+              }
+            }
+            else if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'd') {
+                return T_DOXY_ENDCOND;
+              }
+            }
+          }
+        }
+        else if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'k') {
+                return T_DOXY_ENDLINK;
+              }
+            }
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'x') {
+      if (s[2].unicode() == 'a') {
+        if (s[3].unicode() == 'm') {
+          if (s[4].unicode() == 'p') {
+            if (s[5].unicode() == 'l') {
+              if (s[6].unicode() == 'e') {
+                return T_DOXY_EXAMPLE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'i') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'u') {
+            if (s[5].unicode() == 'd') {
+              if (s[6].unicode() == 'e') {
+                return T_DOXY_INCLUDE;
+              }
+            }
+          }
+        }
+      }
+      else if (s[2].unicode() == 'g') {
+        if (s[3].unicode() == 'r') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'u') {
+              if (s[6].unicode() == 'p') {
+                return T_DOXY_INGROUP;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'm') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 'n') {
+            if (s[5].unicode() == 'l') {
+              if (s[6].unicode() == 'y') {
+                return T_DOXY_MANONLY;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'p') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 'k') {
+          if (s[4].unicode() == 'a') {
+            if (s[5].unicode() == 'g') {
+              if (s[6].unicode() == 'e') {
+                return T_DOXY_PACKAGE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'r') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 't') {
+            if (s[5].unicode() == 'e') {
+              if (s[6].unicode() == 's') {
+                return T_DOXY_RELATES;
+              }
+            }
+          }
+        }
+      }
+      else if (s[2].unicode() == 'm') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'k') {
+              if (s[6].unicode() == 's') {
+                return T_DOXY_REMARKS;
+              }
+            }
+          }
+        }
+      }
+      else if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'u') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 's') {
+                return T_DOXY_RETURNS;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 't') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'n') {
+                return T_DOXY_SECTION;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 't') {
+    if (s[1].unicode() == 'y') {
+      if (s[2].unicode() == 'p') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'd') {
+            if (s[5].unicode() == 'e') {
+              if (s[6].unicode() == 'f') {
+                return T_DOXY_TYPEDEF;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'v') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 's') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'n') {
+                return T_DOXY_VERSION;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'w') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'n') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'g') {
+                return T_DOXY_WARNING;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'x') {
+    if (s[1].unicode() == 'm') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'o') {
+          if (s[4].unicode() == 'n') {
+            if (s[5].unicode() == 'l') {
+              if (s[6].unicode() == 'y') {
+                return T_DOXY_XMLONLY;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify8(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    if (s[1].unicode() == 'd') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'i') {
+          if (s[4].unicode() == 'n') {
+            if (s[5].unicode() == 'd') {
+              if (s[6].unicode() == 'e') {
+                if (s[7].unicode() == 'x') {
+                  return T_DOXY_ADDINDEX;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'f') {
+        if (s[3].unicode() == 'g') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'u') {
+                if (s[7].unicode() == 'p') {
+                  return T_DOXY_DEFGROUP;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'h') {
+    if (s[1].unicode() == 't') {
+      if (s[2].unicode() == 'm') {
+        if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'l') {
+                if (s[7].unicode() == 'y') {
+                  return T_DOXY_HTMLONLY;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'i') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'l') {
+                  return T_DOXY_INTERNAL;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'm') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'i') {
+        if (s[3].unicode() == 'n') {
+          if (s[4].unicode() == 'p') {
+            if (s[5].unicode() == 'a') {
+              if (s[6].unicode() == 'g') {
+                if (s[7].unicode() == 'e') {
+                  return T_DOXY_MAINPAGE;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'o') {
+    if (s[1].unicode() == 'v') {
+      if (s[2].unicode() == 'e') {
+        if (s[3].unicode() == 'r') {
+          if (s[4].unicode() == 'l') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'd') {
+                  return T_DOXY_OVERLOAD;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'k') {
+      if (s[2].unicode() == 'i') {
+        if (s[3].unicode() == 'p') {
+          if (s[4].unicode() == 'l') {
+            if (s[5].unicode() == 'i') {
+              if (s[6].unicode() == 'n') {
+                if (s[7].unicode() == 'e') {
+                  return T_DOXY_SKIPLINE;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'v') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'b') {
+          if (s[4].unicode() == 'a') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 'm') {
+                  return T_DOXY_VERBATIM;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'x') {
+    if (s[1].unicode() == 'r') {
+      if (s[2].unicode() == 'e') {
+        if (s[3].unicode() == 'f') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'e') {
+                if (s[7].unicode() == 'm') {
+                  return T_DOXY_XREFITEM;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify9(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    if (s[1].unicode() == 't') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'n') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'n') {
+                    return T_DOXY_ATTENTION;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'c') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'g') {
+            if (s[5].unicode() == 'r') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'p') {
+                  if (s[8].unicode() == 'h') {
+                    return T_DOXY_CALLGRAPH;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'x') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'p') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'n') {
+                    return T_DOXY_EXCEPTION;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'i') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'f') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'c') {
+                  if (s[8].unicode() == 'e') {
+                    return T_DOXY_INTERFACE;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      else if (s[2].unicode() == 'v') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 'r') {
+            if (s[5].unicode() == 'i') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'n') {
+                  if (s[8].unicode() == 't') {
+                    return T_DOXY_INVARIANT;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'l') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 't') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'x') {
+            if (s[5].unicode() == 'o') {
+              if (s[6].unicode() == 'n') {
+                if (s[7].unicode() == 'l') {
+                  if (s[8].unicode() == 'y') {
+                    return T_DOXY_LATEXONLY;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'n') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'm') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 's') {
+            if (s[5].unicode() == 'p') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'c') {
+                  if (s[8].unicode() == 'e') {
+                    return T_DOXY_NAMESPACE;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'p') {
+    if (s[1].unicode() == 'a') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 'g') {
+            if (s[5].unicode() == 'r') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 'p') {
+                  if (s[8].unicode() == 'h') {
+                    return T_DOXY_PARAGRAPH;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'w') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'a') {
+        if (s[3].unicode() == 'k') {
+          if (s[4].unicode() == 'g') {
+            if (s[5].unicode() == 'r') {
+              if (s[6].unicode() == 'o') {
+                if (s[7].unicode() == 'u') {
+                  if (s[8].unicode() == 'p') {
+                    return T_DOXY_WEAKGROUP;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify10(const QChar *s) {
+  if (s[0].unicode() == 'a') {
+    if (s[1].unicode() == 'd') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 't') {
+          if (s[4].unicode() == 'o') {
+            if (s[5].unicode() == 'g') {
+              if (s[6].unicode() == 'r') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'u') {
+                    if (s[9].unicode() == 'p') {
+                      return T_DOXY_ADDTOGROUP;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'p') {
+        if (s[3].unicode() == 'r') {
+          if (s[4].unicode() == 'e') {
+            if (s[5].unicode() == 'c') {
+              if (s[6].unicode() == 'a') {
+                if (s[7].unicode() == 't') {
+                  if (s[8].unicode() == 'e') {
+                    if (s[9].unicode() == 'd') {
+                      return T_DOXY_DEPRECATED;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'm') {
+          if (s[4].unicode() == 'a') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'o') {
+                if (s[7].unicode() == 'n') {
+                  if (s[8].unicode() == 'l') {
+                    if (s[9].unicode() == 'y') {
+                      return T_DOXY_ENDMANONLY;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+        else if (s[3].unicode() == 'x') {
+          if (s[4].unicode() == 'm') {
+            if (s[5].unicode() == 'l') {
+              if (s[6].unicode() == 'o') {
+                if (s[7].unicode() == 'n') {
+                  if (s[8].unicode() == 'l') {
+                    if (s[9].unicode() == 'y') {
+                      return T_DOXY_ENDXMLONLY;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    else if (s[1].unicode() == 'x') {
+      if (s[2].unicode() == 'c') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'p') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'n') {
+                    if (s[9].unicode() == 's') {
+                      return T_DOXY_EXCEPTIONS;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'u') {
+      if (s[2].unicode() == 'b') {
+        if (s[3].unicode() == 's') {
+          if (s[4].unicode() == 'e') {
+            if (s[5].unicode() == 'c') {
+              if (s[6].unicode() == 't') {
+                if (s[7].unicode() == 'i') {
+                  if (s[8].unicode() == 'o') {
+                    if (s[9].unicode() == 'n') {
+                      return T_DOXY_SUBSECTION;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify11(const QChar *s) {
+  if (s[0].unicode() == 'd') {
+    if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 'n') {
+        if (s[3].unicode() == 't') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'c') {
+                if (s[7].unicode() == 'l') {
+                  if (s[8].unicode() == 'u') {
+                    if (s[9].unicode() == 'd') {
+                      if (s[10].unicode() == 'e') {
+                        return T_DOXY_DONTINCLUDE;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'h') {
+          if (s[4].unicode() == 't') {
+            if (s[5].unicode() == 'm') {
+              if (s[6].unicode() == 'l') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'n') {
+                    if (s[9].unicode() == 'l') {
+                      if (s[10].unicode() == 'y') {
+                        return T_DOXY_ENDHTMLONLY;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+        else if (s[3].unicode() == 'v') {
+          if (s[4].unicode() == 'e') {
+            if (s[5].unicode() == 'r') {
+              if (s[6].unicode() == 'b') {
+                if (s[7].unicode() == 'a') {
+                  if (s[8].unicode() == 't') {
+                    if (s[9].unicode() == 'i') {
+                      if (s[10].unicode() == 'm') {
+                        return T_DOXY_ENDVERBATIM;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'h') {
+    if (s[1].unicode() == 't') {
+      if (s[2].unicode() == 'm') {
+        if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'c') {
+                if (s[7].unicode() == 'l') {
+                  if (s[8].unicode() == 'u') {
+                    if (s[9].unicode() == 'd') {
+                      if (s[10].unicode() == 'e') {
+                        return T_DOXY_HTMLINCLUDE;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'r') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'l') {
+        if (s[3].unicode() == 'a') {
+          if (s[4].unicode() == 't') {
+            if (s[5].unicode() == 'e') {
+              if (s[6].unicode() == 's') {
+                if (s[7].unicode() == 'a') {
+                  if (s[8].unicode() == 'l') {
+                    if (s[9].unicode() == 's') {
+                      if (s[10].unicode() == 'o') {
+                        return T_DOXY_RELATESALSO;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 'v') {
+    if (s[1].unicode() == 'e') {
+      if (s[2].unicode() == 'r') {
+        if (s[3].unicode() == 'b') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'c') {
+                if (s[7].unicode() == 'l') {
+                  if (s[8].unicode() == 'u') {
+                    if (s[9].unicode() == 'd') {
+                      if (s[10].unicode() == 'e') {
+                        return T_DOXY_VERBINCLUDE;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify12(const QChar *s) {
+  if (s[0].unicode() == 'e') {
+    if (s[1].unicode() == 'n') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'l') {
+          if (s[4].unicode() == 'a') {
+            if (s[5].unicode() == 't') {
+              if (s[6].unicode() == 'e') {
+                if (s[7].unicode() == 'x') {
+                  if (s[8].unicode() == 'o') {
+                    if (s[9].unicode() == 'n') {
+                      if (s[10].unicode() == 'l') {
+                        if (s[11].unicode() == 'y') {
+                          return T_DOXY_ENDLATEXONLY;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify13(const QChar *s) {
+  if (s[0].unicode() == 'n') {
+    if (s[1].unicode() == 'o') {
+      if (s[2].unicode() == 's') {
+        if (s[3].unicode() == 'u') {
+          if (s[4].unicode() == 'b') {
+            if (s[5].unicode() == 'g') {
+              if (s[6].unicode() == 'r') {
+                if (s[7].unicode() == 'o') {
+                  if (s[8].unicode() == 'u') {
+                    if (s[9].unicode() == 'p') {
+                      if (s[10].unicode() == 'i') {
+                        if (s[11].unicode() == 'n') {
+                          if (s[12].unicode() == 'g') {
+                            return T_DOXY_NOSUBGROUPING;
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'u') {
+      if (s[2].unicode() == 'b') {
+        if (s[3].unicode() == 's') {
+          if (s[4].unicode() == 'u') {
+            if (s[5].unicode() == 'b') {
+              if (s[6].unicode() == 's') {
+                if (s[7].unicode() == 'e') {
+                  if (s[8].unicode() == 'c') {
+                    if (s[9].unicode() == 't') {
+                      if (s[10].unicode() == 'i') {
+                        if (s[11].unicode() == 'o') {
+                          if (s[12].unicode() == 'n') {
+                            return T_DOXY_SUBSUBSECTION;
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+static inline int classify15(const QChar *s) {
+  if (s[0].unicode() == 'h') {
+    if (s[1].unicode() == 'i') {
+      if (s[2].unicode() == 'd') {
+        if (s[3].unicode() == 'e') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 't') {
+                  if (s[8].unicode() == 'i') {
+                    if (s[9].unicode() == 'a') {
+                      if (s[10].unicode() == 'l') {
+                        if (s[11].unicode() == 'i') {
+                          if (s[12].unicode() == 'z') {
+                            if (s[13].unicode() == 'e') {
+                              if (s[14].unicode() == 'r') {
+                                return T_DOXY_HIDEINITIALIZER;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  else if (s[0].unicode() == 's') {
+    if (s[1].unicode() == 'h') {
+      if (s[2].unicode() == 'o') {
+        if (s[3].unicode() == 'w') {
+          if (s[4].unicode() == 'i') {
+            if (s[5].unicode() == 'n') {
+              if (s[6].unicode() == 'i') {
+                if (s[7].unicode() == 't') {
+                  if (s[8].unicode() == 'i') {
+                    if (s[9].unicode() == 'a') {
+                      if (s[10].unicode() == 'l') {
+                        if (s[11].unicode() == 'i') {
+                          if (s[12].unicode() == 'z') {
+                            if (s[13].unicode() == 'e') {
+                              if (s[14].unicode() == 'r') {
+                                return T_DOXY_SHOWINITIALIZER;
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return T_DOXY_IDENTIFIER;
+}
+
+int CppEditor::Internal::classifyDoxygen(const QChar *s, int n) {
+  switch (n) {
+    case 1: return classify1(s);
+    case 2: return classify2(s);
+    case 3: return classify3(s);
+    case 4: return classify4(s);
+    case 5: return classify5(s);
+    case 6: return classify6(s);
+    case 7: return classify7(s);
+    case 8: return classify8(s);
+    case 9: return classify9(s);
+    case 10: return classify10(s);
+    case 11: return classify11(s);
+    case 12: return classify12(s);
+    case 13: return classify13(s);
+    case 15: return classify15(s);
+    default: return T_DOXY_IDENTIFIER;
+  } // switch
+}
+
diff --git a/src/plugins/cppeditor/cppdoxygen.h b/src/plugins/cppeditor/cppdoxygen.h
new file mode 100644
index 00000000000..61c8e9da0cc
--- /dev/null
+++ b/src/plugins/cppeditor/cppdoxygen.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file.  Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception
+** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+namespace CppEditor {
+namespace Internal {
+
+enum DoxygenReservedWord {
+  T_DOXY_IDENTIFIER = 0,
+
+  T_DOXY_ARG,
+  T_DOXY_ATTENTION,
+  T_DOXY_AUTHOR,
+  T_DOXY_CALLGRAPH,
+  T_DOXY_CODE,
+  T_DOXY_DOT,
+  T_DOXY_ELSE,
+  T_DOXY_ENDCODE,
+  T_DOXY_ENDCOND,
+  T_DOXY_ENDDOT,
+  T_DOXY_ENDHTMLONLY,
+  T_DOXY_ENDIF,
+  T_DOXY_ENDLATEXONLY,
+  T_DOXY_ENDLINK,
+  T_DOXY_ENDMANONLY,
+  T_DOXY_ENDVERBATIM,
+  T_DOXY_ENDXMLONLY,
+  T_DOXY_HIDEINITIALIZER,
+  T_DOXY_HTMLONLY,
+  T_DOXY_INTERFACE,
+  T_DOXY_INTERNAL,
+  T_DOXY_INVARIANT,
+  T_DOXY_LATEXONLY,
+  T_DOXY_LI,
+  T_DOXY_MANONLY,
+  T_DOXY_N,
+  T_DOXY_NOSUBGROUPING,
+  T_DOXY_NOTE,
+  T_DOXY_ONLY,
+  T_DOXY_POST,
+  T_DOXY_PRE,
+  T_DOXY_REMARKS,
+  T_DOXY_RETURN,
+  T_DOXY_RETURNS,
+  T_DOXY_SA,
+  T_DOXY_SEE,
+  T_DOXY_SHOWINITIALIZER,
+  T_DOXY_SINCE,
+  T_DOXY_TEST,
+  T_DOXY_TODO,
+  T_DOXY_VERBATIM,
+  T_DOXY_WARNING,
+  T_DOXY_XMLONLY,
+
+  T_DOXY_A,
+  T_DOXY_ADDTOGROUP,
+  T_DOXY_ANCHOR,
+  T_DOXY_B,
+  T_DOXY_C,
+  T_DOXY_CLASS,
+  T_DOXY_COND,
+  T_DOXY_COPYDOC,
+  T_DOXY_DEF,
+  T_DOXY_DONTINCLUDE,
+  T_DOXY_DOTFILE,
+  T_DOXY_E,
+  T_DOXY_ELSEIF,
+  T_DOXY_EM,
+  T_DOXY_ENUM,
+  T_DOXY_EXAMPLE,
+  T_DOXY_EXCEPTION,
+  T_DOXY_EXCEPTIONS,
+  T_DOXY_FILE,
+  T_DOXY_HTMLINCLUDE,
+  T_DOXY_IF,
+  T_DOXY_IFNOT,
+  T_DOXY_INCLUDE,
+  T_DOXY_LINK,
+  T_DOXY_NAMESPACE,
+  T_DOXY_P,
+  T_DOXY_PACKAGE,
+  T_DOXY_REF,
+  T_DOXY_RELATES,
+  T_DOXY_RELATESALSO,
+  T_DOXY_RETVAL,
+  T_DOXY_THROW,
+  T_DOXY_THROWS,
+  T_DOXY_VERBINCLUDE,
+  T_DOXY_VERSION,
+  T_DOXY_XREFITEM,
+
+  T_DOXY_PARAM,
+
+  T_DOXY_IMAGE,
+
+  T_DOXY_DEFGROUP,
+  T_DOXY_PAGE,
+  T_DOXY_PARAGRAPH,
+  T_DOXY_SECTION,
+  T_DOXY_STRUCT,
+  T_DOXY_SUBSECTION,
+  T_DOXY_SUBSUBSECTION,
+  T_DOXY_UNION,
+  T_DOXY_WEAKGROUP,
+
+  T_DOXY_ADDINDEX,
+  T_DOXY_BRIEF,
+  T_DOXY_BUG,
+  T_DOXY_DATE,
+  T_DOXY_DEPRECATED,
+  T_DOXY_FN,
+  T_DOXY_INGROUP,
+  T_DOXY_LINE,
+  T_DOXY_MAINPAGE,
+  T_DOXY_NAME,
+  T_DOXY_OVERLOAD,
+  T_DOXY_PAR,
+  T_DOXY_SHORT,
+  T_DOXY_SKIP,
+  T_DOXY_SKIPLINE,
+  T_DOXY_TYPEDEF,
+  T_DOXY_UNTIL,
+  T_DOXY_VAR,
+
+};
+
+int classifyDoxygen(const QChar *s, int n);
+
+
+} // namespace Internal
+} // namespace CppEditor::Internal
+
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 2d28c6c8b86..3d4abf71679 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -15,12 +15,16 @@ HEADERS += cppplugin.h \
     cppeditorconstants.h \
     cppeditorenums.h \
     cppeditor_global.h \
-    cppclasswizard.h
+    cppclasswizard.h \
+    cppdoxygen.h
+
 SOURCES += cppplugin.cpp \
     cppeditoractionhandler.cpp \
     cppeditor.cpp \
     cpphighlighter.cpp \
     cpphoverhandler.cpp \
     cppfilewizard.cpp \
-    cppclasswizard.cpp
+    cppclasswizard.cpp \
+    cppdoxygen.cpp
+
 RESOURCES += cppeditor.qrc
diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp
index 511cb56c8b3..447f442d2b3 100644
--- a/src/plugins/cppeditor/cpphighlighter.cpp
+++ b/src/plugins/cppeditor/cpphighlighter.cpp
@@ -32,6 +32,7 @@
 ***************************************************************************/
 
 #include "cpphighlighter.h"
+#include "cppdoxygen.h"
 
 #include <Token.h>
 #include <cplusplus/SimpleLexer.h>
@@ -115,23 +116,35 @@ void CppHighlighter::highlightBlock(const QString &text)
         }
 
         bool highlightCurrentWordAsPreprocessor = highlightAsPreprocessor;
+
         if (highlightAsPreprocessor)
             highlightAsPreprocessor = false;
 
         if (i == 0 && tk.is(T_POUND)) {
             setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
             highlightAsPreprocessor = true;
+
         } else if (highlightCurrentWordAsPreprocessor &&
                    (tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(tk.text()))
             setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
+
         else if (tk.is(T_INT_LITERAL) || tk.is(T_FLOAT_LITERAL))
             setFormat(tk.position(), tk.length(), m_formats[CppNumberFormat]);
+
         else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))
             setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
+
         else if (tk.is(T_WIDE_STRING_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL))
             setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
-        else if (tk.is(T_COMMENT)) {
-            setFormat(tk.position(), tk.length(), m_formats[CppCommentFormat]);
+
+        else if (tk.isComment()) {
+
+            if (tk.is(T_COMMENT))
+                setFormat(tk.position(), tk.length(), m_formats[CppCommentFormat]);
+
+            else // a doxygen comment
+                highlightDoxygenComment(text, tk.position(), tk.length());
+
             // we need to insert a close comment parenthesis, if
             //  - the line starts in a C Comment (initalState != 0)
             //  - the first token of the line is a T_COMMENT (i == 0 && tk.is(T_COMMENT))
@@ -145,12 +158,16 @@ void CppHighlighter::highlightBlock(const QString &text)
                 // clear the initial state.
                 initialState = 0;
             }
+
         } else if (tk.isKeyword() || isQtKeyword(tk.text()))
             setFormat(tk.position(), tk.length(), m_formats[CppKeywordFormat]);
+
         else if (tk.isOperator())
             setFormat(tk.position(), tk.length(), m_formats[CppOperatorFormat]);
+
         else if (i == 0 && tokens.size() > 1 && tk.is(T_IDENTIFIER) && tokens.at(1).is(T_COLON))
             setFormat(tk.position(), tk.length(), m_formats[CppLabelFormat]);
+
         else if (tk.is(T_IDENTIFIER))
             highlightWord(tk.text(), tk.position(), tk.length());
     }
@@ -304,3 +321,40 @@ void CppHighlighter::highlightWord(QStringRef word, int position, int length)
         setFormat(position, length, m_formats[CppTypeFormat]);
     }
 }
+
+void CppHighlighter::highlightDoxygenComment(const QString &text, int position,
+                                             int length)
+{
+    int initial = position;
+    int i = position;
+
+    const QChar *uc = text.unicode();
+    const QChar *it = uc + position;
+
+    QTextCharFormat format = m_formats[CppCommentFormat];
+    QTextCharFormat kwFormat = format;
+    kwFormat.setFontWeight(QFont::Bold);
+    kwFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+
+    while (! it->isNull()) {
+        if (it->unicode() == QLatin1Char('\\') ||
+            it->unicode() == QLatin1Char('@')) {
+            ++it;
+
+            const QChar *start = it;
+            while (it->isLetterOrNumber() || it->unicode() == '_')
+                ++it;
+
+            int k = classifyDoxygen(start, it - start);
+            if (k != T_DOXY_IDENTIFIER) {
+                setFormat(initial, start - uc - initial, format);
+                setFormat(start - uc - 1, it - start + 1, kwFormat);
+                initial = it - uc;
+            }
+        } else
+            ++it;
+    }
+
+    setFormat(initial, it - uc - initial, format);
+}
+
diff --git a/src/plugins/cppeditor/cpphighlighter.h b/src/plugins/cppeditor/cpphighlighter.h
index 3c74460e653..90ed58957f6 100644
--- a/src/plugins/cppeditor/cpphighlighter.h
+++ b/src/plugins/cppeditor/cpphighlighter.h
@@ -61,6 +61,10 @@ public:
 
 private:
     void highlightWord(QStringRef word, int position, int length);
+
+    void highlightDoxygenComment(const QString &text, int position,
+                                 int length);
+
     bool isPPKeyword(const QStringRef &text) const;
     bool isQtKeyword(const QStringRef &text) const;
 
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index ccdb01d6489..2a1e13ae3f1 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -404,7 +404,7 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
         tc.setPosition(pos);
         static CPlusPlus::TokenUnderCursor tokenUnderCursor;
         const SimpleToken tk = tokenUnderCursor(tc);
-        if (tk.is(T_COMMENT) || tk.isLiteral()) {
+        if (tk.isComment() || tk.isLiteral()) {
             if (kind)
                 *kind = T_EOF_SYMBOL;
             return pos;
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
index 04c79d471dd..f8259c9031c 100644
--- a/src/plugins/cpptools/cpptools.pro
+++ b/src/plugins/cpptools/cpptools.pro
@@ -8,27 +8,27 @@ include(cpptools_dependencies.pri)
 DEFINES += QT_NO_CAST_TO_ASCII
 INCLUDEPATH += .
 DEFINES += CPPTOOLS_LIBRARY
-HEADERS += cpptools_global.h \
-    cppquickopenfilter.h \
+HEADERS += completionsettingspage.h \
     cppclassesfilter.h \
-    searchsymbols.h \
+    cppcodecompletion.h \
     cppfunctionsfilter.h \
-    completionsettingspage.h
-SOURCES += cppquickopenfilter.cpp \
-    cpptoolseditorsupport.cpp \
-    cppclassesfilter.cpp \
-    searchsymbols.cpp \
-    cppfunctionsfilter.cpp \
-    completionsettingspage.cpp
-
-# Input
-SOURCES += cpptoolsplugin.cpp \
-    cppmodelmanager.cpp \
-    cppcodecompletion.cpp
-HEADERS += cpptoolsplugin.h \
     cppmodelmanager.h \
-    cppcodecompletion.h \
     cppmodelmanagerinterface.h \
+    cppquickopenfilter.h \
+    cpptools_global.h \
+    cpptoolsconstants.h \
     cpptoolseditorsupport.h \
-    cpptoolsconstants.h
+    cpptoolsplugin.h \
+    searchsymbols.h
+
+SOURCES += completionsettingspage.cpp \
+    cppclassesfilter.cpp \
+    cppcodecompletion.cpp \
+    cppfunctionsfilter.cpp \
+    cppmodelmanager.cpp \
+    cppquickopenfilter.cpp \
+    cpptoolseditorsupport.cpp \
+    cpptoolsplugin.cpp \
+    searchsymbols.cpp
+
 FORMS += completionsettingspage.ui
diff --git a/src/shared/cplusplus/Lexer.cpp b/src/shared/cplusplus/Lexer.cpp
index 73c12524d79..4d0b2b6e800 100644
--- a/src/shared/cplusplus/Lexer.cpp
+++ b/src/shared/cplusplus/Lexer.cpp
@@ -60,7 +60,7 @@ CPLUSPLUS_BEGIN_NAMESPACE
 
 Lexer::Lexer(TranslationUnit *unit)
     : _translationUnit(unit),
-      _state(Lexer::DefaultState),
+      _state(State_Default),
       _flags(0),
       _currentLine(1)
 {
@@ -71,7 +71,7 @@ Lexer::Lexer(TranslationUnit *unit)
 
 Lexer::Lexer(const char *firstChar, const char *lastChar)
     : _translationUnit(0),
-      _state(Lexer::DefaultState),
+      _state(State_Default),
       _flags(0),
       _currentLine(1)
 {
@@ -196,7 +196,7 @@ void Lexer::scan_helper(Token *tok)
     _tokenStart = _currentChar;
     tok->offset = _currentChar - _firstChar;
 
-    if (_state == MultiLineCommentState) {
+    if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) {
         if (! _yychar) {
             tok->kind = T_EOF_SYMBOL;
             return;
@@ -209,7 +209,7 @@ void Lexer::scan_helper(Token *tok)
                 yyinp();
                 if (_yychar == '/') {
                     yyinp();
-                    _state = DefaultState;
+                    _state = State_Default;
                     break;
                 }
             }
@@ -218,7 +218,11 @@ void Lexer::scan_helper(Token *tok)
         if (! _scanCommentTokens)
             goto _Lagain;
 
-        tok->kind = T_COMMENT;
+        else if (_state == State_MultiLineComment)
+            tok->kind = T_COMMENT;
+
+        else
+            tok->kind = T_DOXY_COMMENT;
         return; // done
     }
 
@@ -402,14 +406,30 @@ void Lexer::scan_helper(Token *tok)
 
     case '/':
         if (_yychar == '/') {
-            do {
+            yyinp();
+
+            bool doxy = false;
+
+            if (_yychar == '/' || _yychar == '!') {
+                yyinp();
+
+                if (_yychar != '\n' && std::isspace(_yychar))
+                    doxy = true;
+            }
+
+            while (_yychar && _yychar != '\n')
                 yyinp();
-            } while (_yychar && _yychar != '\n');
+
             if (! _scanCommentTokens)
                 goto _Lagain;
-            tok->kind = T_COMMENT;
+
+            tok->kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
+
         } else if (_yychar == '*') {
             yyinp();
+
+            const bool doxy = _yychar == '*' || _yychar == '!';
+
             while (_yychar) {
                 if (_yychar != '*') {
                     yyinp();
@@ -423,11 +443,13 @@ void Lexer::scan_helper(Token *tok)
             if (_yychar)
                 yyinp();
             else
-                _state = MultiLineCommentState;
+                _state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment;
 
             if (! _scanCommentTokens)
                 goto _Lagain;
-            tok->kind = T_COMMENT;
+
+            tok->kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
+
         } else if (_yychar == '=') {
             yyinp();
             tok->kind = T_SLASH_EQUAL;
diff --git a/src/shared/cplusplus/Lexer.h b/src/shared/cplusplus/Lexer.h
index 4cb62493db8..fb9c80ef98b 100644
--- a/src/shared/cplusplus/Lexer.h
+++ b/src/shared/cplusplus/Lexer.h
@@ -66,8 +66,9 @@ class CPLUSPLUS_EXPORT Lexer
 
 public:
     enum State {
-        DefaultState,
-        MultiLineCommentState
+        State_Default,
+        State_MultiLineComment,
+        State_MultiLineDoxyComment
     };
 
     Lexer(TranslationUnit *unit);
diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp
index eb672958cd6..e47a1573d9b 100644
--- a/src/shared/cplusplus/Token.cpp
+++ b/src/shared/cplusplus/Token.cpp
@@ -58,7 +58,7 @@ CPLUSPLUS_BEGIN_NAMESPACE
 static const char *token_names[] = {
     (""), ("<error>"),
 
-    ("<comment>"),
+    ("<comment>"), ("<doxy comment>"),
 
     ("<identifier>"), ("<int literal>"), ("<float literal>"), ("<char literal>"),
     ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),
diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h
index f48654aa773..55cacf7379a 100644
--- a/src/shared/cplusplus/Token.h
+++ b/src/shared/cplusplus/Token.h
@@ -64,6 +64,7 @@ enum Kind {
     T_ERROR,
 
     T_COMMENT,
+    T_DOXY_COMMENT,
     T_IDENTIFIER,
 
     T_FIRST_LITERAL,
@@ -297,6 +298,9 @@ public:
     inline bool isKeyword() const
     { return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; }
 
+    inline bool isComment() const
+    { return kind == T_COMMENT || kind == T_DOXY_COMMENT; }
+
     inline bool isObjCAtKeyword() const
     { return kind >= T_FIRST_OBJC_AT_KEYWORD && kind < T_LAST_OBJC_AT_KEYWORD; }
 
-- 
GitLab