/tools/qdoc3/qmlcodemarker.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 302 lines · 187 code · 41 blank · 74 comment · 37 complexity · 9c999f3d616fc3ca7cd061d1068984d5 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the tools applications of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. /*
  42. qmlcodemarker.cpp
  43. */
  44. #include "declarativeparser/qdeclarativejsast_p.h"
  45. #include "declarativeparser/qdeclarativejsastfwd_p.h"
  46. #include "declarativeparser/qdeclarativejsengine_p.h"
  47. #include "declarativeparser/qdeclarativejslexer_p.h"
  48. #include "declarativeparser/qdeclarativejsnodepool_p.h"
  49. #include "declarativeparser/qdeclarativejsparser_p.h"
  50. #include "atom.h"
  51. #include "node.h"
  52. #include "qmlcodemarker.h"
  53. #include "qmlmarkupvisitor.h"
  54. #include "text.h"
  55. #include "tree.h"
  56. QT_BEGIN_NAMESPACE
  57. QmlCodeMarker::QmlCodeMarker()
  58. {
  59. }
  60. QmlCodeMarker::~QmlCodeMarker()
  61. {
  62. }
  63. /*!
  64. Returns true if the \a code is recognized by the parser.
  65. */
  66. bool QmlCodeMarker::recognizeCode(const QString &code)
  67. {
  68. QDeclarativeJS::Engine engine;
  69. QDeclarativeJS::Lexer lexer(&engine);
  70. QDeclarativeJS::Parser parser(&engine);
  71. QDeclarativeJS::NodePool m_nodePool("<QmlCodeMarker::recognizeCode>", &engine);
  72. QString newCode = code;
  73. extractPragmas(newCode);
  74. lexer.setCode(newCode, 1);
  75. return parser.parse();
  76. }
  77. /*!
  78. Returns true if \a ext is any of a list of file extensions
  79. for the QML language.
  80. */
  81. bool QmlCodeMarker::recognizeExtension(const QString &ext)
  82. {
  83. return ext == "qml";
  84. }
  85. /*!
  86. Returns true if the \a language is recognized. Only "QML" is
  87. recognized by this marker.
  88. */
  89. bool QmlCodeMarker::recognizeLanguage(const QString &language)
  90. {
  91. return language == "QML";
  92. }
  93. /*!
  94. Returns the type of atom used to represent QML code in the documentation.
  95. */
  96. Atom::Type QmlCodeMarker::atomType() const
  97. {
  98. return Atom::Qml;
  99. }
  100. /*!
  101. Returns the name of the \a node. Method names include are returned with a
  102. trailing set of parentheses.
  103. */
  104. QString QmlCodeMarker::plainName(const Node *node)
  105. {
  106. QString name = node->name();
  107. if (node->type() == Node::QmlMethod)
  108. name += "()";
  109. return name;
  110. }
  111. QString QmlCodeMarker::plainFullName(const Node *node, const Node *relative)
  112. {
  113. if (node->name().isEmpty()) {
  114. return "global";
  115. }
  116. else {
  117. QString fullName;
  118. while (node) {
  119. fullName.prepend(plainName(node));
  120. if (node->parent() == relative || node->parent()->name().isEmpty())
  121. break;
  122. fullName.prepend("::");
  123. node = node->parent();
  124. }
  125. return fullName;
  126. }
  127. }
  128. QString QmlCodeMarker::markedUpCode(const QString &code,
  129. const Node *relative,
  130. const Location &location)
  131. {
  132. return addMarkUp(code, relative, location);
  133. }
  134. QString QmlCodeMarker::markedUpName(const Node *node)
  135. {
  136. QString name = linkTag(node, taggedNode(node));
  137. if (node->type() == Node::QmlMethod)
  138. name += "()";
  139. return name;
  140. }
  141. QString QmlCodeMarker::markedUpFullName(const Node *node, const Node *relative)
  142. {
  143. if (node->name().isEmpty()) {
  144. return "global";
  145. }
  146. else {
  147. QString fullName;
  148. for (;;) {
  149. fullName.prepend(markedUpName(node));
  150. if (node->parent() == relative || node->parent()->name().isEmpty())
  151. break;
  152. fullName.prepend("<@op>::</@op>");
  153. node = node->parent();
  154. }
  155. return fullName;
  156. }
  157. }
  158. QString QmlCodeMarker::markedUpIncludes(const QStringList& includes)
  159. {
  160. QString code;
  161. QStringList::ConstIterator inc = includes.begin();
  162. while (inc != includes.end()) {
  163. code += "import " + *inc + "\n";
  164. ++inc;
  165. }
  166. Location location;
  167. return addMarkUp(code, 0, location);
  168. }
  169. QString QmlCodeMarker::functionBeginRegExp(const QString& funcName)
  170. {
  171. return "^" + QRegExp::escape("function " + funcName) + "$";
  172. }
  173. QString QmlCodeMarker::functionEndRegExp(const QString& /* funcName */)
  174. {
  175. return "^\\}$";
  176. }
  177. QString QmlCodeMarker::addMarkUp(const QString &code,
  178. const Node * /* relative */,
  179. const Location &location)
  180. {
  181. QDeclarativeJS::Engine engine;
  182. QDeclarativeJS::Lexer lexer(&engine);
  183. QString newCode = code;
  184. QList<QDeclarativeJS::AST::SourceLocation> pragmas = extractPragmas(newCode);
  185. lexer.setCode(newCode, 1);
  186. QDeclarativeJS::Parser parser(&engine);
  187. QDeclarativeJS::NodePool m_nodePool("<QmlCodeMarker::addMarkUp>", &engine);
  188. QString output;
  189. if (parser.parse()) {
  190. QDeclarativeJS::AST::UiProgram *ast = parser.ast();
  191. // Pass the unmodified code to the visitor so that pragmas and other
  192. // unhandled source text can be output.
  193. QmlMarkupVisitor visitor(code, pragmas, &engine);
  194. QDeclarativeJS::AST::Node::accept(ast, &visitor);
  195. output = visitor.markedUpCode();
  196. } else {
  197. location.warning(tr("Unable to parse QML: \"%1\" at line %2, column %3").arg(
  198. parser.errorMessage()).arg(parser.errorLineNumber()).arg(
  199. parser.errorColumnNumber()));
  200. output = protect(code);
  201. }
  202. return output;
  203. }
  204. /*
  205. Copied and pasted from src/declarative/qml/qdeclarativescriptparser.cpp.
  206. */
  207. static void replaceWithSpace(QString &str, int idx, int n)
  208. {
  209. QChar *data = str.data() + idx;
  210. const QChar space(QLatin1Char(' '));
  211. for (int ii = 0; ii < n; ++ii)
  212. *data++ = space;
  213. }
  214. /*
  215. Copied and pasted from src/declarative/qml/qdeclarativescriptparser.cpp then
  216. modified to return a list of removed pragmas.
  217. Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
  218. are:
  219. library
  220. */
  221. QList<QDeclarativeJS::AST::SourceLocation> QmlCodeMarker::extractPragmas(QString &script)
  222. {
  223. const QString pragma(QLatin1String("pragma"));
  224. const QString library(QLatin1String("library"));
  225. QList<QDeclarativeJS::AST::SourceLocation> removed;
  226. QDeclarativeJS::Lexer l(0);
  227. l.setCode(script, 0);
  228. int token = l.lex();
  229. while (true) {
  230. if (token != QDeclarativeJSGrammar::T_DOT)
  231. return removed;
  232. int startOffset = l.tokenOffset();
  233. int startLine = l.currentLineNo();
  234. int startColumn = l.currentColumnNo();
  235. token = l.lex();
  236. if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
  237. l.currentLineNo() != startLine ||
  238. script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
  239. return removed;
  240. token = l.lex();
  241. if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
  242. l.currentLineNo() != startLine)
  243. return removed;
  244. QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
  245. int endOffset = l.tokenLength() + l.tokenOffset();
  246. token = l.lex();
  247. if (l.currentLineNo() == startLine)
  248. return removed;
  249. if (pragmaValue == QLatin1String("library")) {
  250. replaceWithSpace(script, startOffset, endOffset - startOffset);
  251. removed.append(
  252. QDeclarativeJS::AST::SourceLocation(
  253. startOffset, endOffset - startOffset,
  254. startLine, startColumn));
  255. } else
  256. return removed;
  257. }
  258. return removed;
  259. }
  260. QT_END_NAMESPACE