PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/kdevelop-php-1.3.1/completion/implementationitem.cpp

#
C++ | 260 lines | 183 code | 36 blank | 41 comment | 46 complexity | fc4d9cb3018ed132d82a8ee32409c668 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * KDevelop Php Code Completion Support
  3. *
  4. * Copyright 2009 Milian Wolff <mail@milianw.de>
  5. * Basec on Cpp ImplementationHelperItem
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Library General Public License as
  9. * published by the Free Software Foundation; either version 2 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public
  18. * License along with this program; if not, write to the
  19. * Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. */
  22. #include "implementationitem.h"
  23. #include "helpers.h"
  24. #include <language/duchain/duchain.h>
  25. #include <language/duchain/duchainlock.h>
  26. #include <language/duchain/declaration.h>
  27. #include <language/duchain/types/functiontype.h>
  28. #include <language/codecompletion/codecompletionmodel.h>
  29. #include "declarations/classmethoddeclaration.h"
  30. #include <ktexteditor/document.h>
  31. #include <kicon.h>
  32. #include <klocalizedstring.h>
  33. #include <KTextEditor/View>
  34. #include <language/duchain/duchainutils.h>
  35. #include <language/duchain/classdeclaration.h>
  36. #include <language/duchain/types/integraltype.h>
  37. using namespace KDevelop;
  38. namespace Php
  39. {
  40. #define RETURN_CACHED_ICON(name) {static QIcon icon(KIcon(name).pixmap(QSize(16, 16))); return icon;}
  41. QVariant ImplementationItem::data(const QModelIndex& index, int role, const CodeCompletionModel* model) const
  42. {
  43. QVariant ret = NormalDeclarationCompletionItem::data(index, role, model);
  44. switch (role) {
  45. case Qt::DecorationRole:
  46. if (index.column() == KTextEditor::CodeCompletionModel::Icon) {
  47. switch (m_type) {
  48. case Override:
  49. RETURN_CACHED_ICON("CTparents");
  50. case Implement:
  51. RETURN_CACHED_ICON("CTsuppliers");
  52. }
  53. }
  54. break;
  55. case Qt::DisplayRole:
  56. if (index.column() == KTextEditor::CodeCompletionModel::Prefix) {
  57. QString prefix;
  58. switch (m_type) {
  59. case Override:
  60. prefix = i18n("Override");
  61. break;
  62. case Implement:
  63. prefix = i18n("Implement");
  64. break;
  65. }
  66. ret = prefix + ' ' + ret.toString();
  67. }
  68. //TODO column == Name - required?
  69. break;
  70. case KTextEditor::CodeCompletionModel::ItemSelected: {
  71. DUChainReadLocker lock(DUChain::lock());
  72. if (declaration().data()) {
  73. QualifiedIdentifier parentScope = declaration()->context()->scopeIdentifier(true);
  74. return i18n("From %1", parentScope.toString());
  75. }
  76. }
  77. break;
  78. case KTextEditor::CodeCompletionModel::InheritanceDepth:
  79. return QVariant(0);
  80. default:
  81. //pass
  82. break;
  83. }
  84. return ret;
  85. }
  86. void ImplementationItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word)
  87. {
  88. DUChainReadLocker lock(DUChain::lock());
  89. QString replText;
  90. if (m_declaration) {
  91. //TODO:respect custom code styles
  92. // get existing modifiers so we can respect the user's choice of public/protected and final
  93. QStringList modifiers = getMethodTokens(document->text(KTextEditor::Range(KTextEditor::Cursor::start(), word.start())));
  94. // get range to replace
  95. KTextEditor::Range replaceRange(word);
  96. if (!modifiers.isEmpty()) {
  97. // TODO: is there no easy API to map QString Index to a KTextEditor::Cursor ?!
  98. QString methodText = document->text(KTextEditor::Range(KTextEditor::Cursor::start(), word.start()));
  99. methodText = methodText.left(methodText.lastIndexOf(modifiers.last(), -1, Qt::CaseInsensitive));
  100. replaceRange.start() = KTextEditor::Cursor(methodText.count('\n'), methodText.length() - methodText.lastIndexOf('\n') - 1);
  101. }
  102. // get indendation
  103. QString indendation;
  104. {
  105. QString currentLine = document->line(replaceRange.start().line());
  106. indendation = getIndendation(currentLine);
  107. if ( !currentLine.isEmpty() && currentLine != indendation ) {
  108. // since theres some non-whitespace in this line, skip to the enxt one
  109. replText += '\n' + indendation;
  110. }
  111. if (indendation.isEmpty()) {
  112. // use a minimal indendation
  113. // TODO: respect code style
  114. indendation = " ";
  115. replText += indendation;
  116. }
  117. }
  118. #if 0
  119. //Disabled, because not everyone writes phpdoc for every function
  120. //TODO: move to a phpdoc helper
  121. // build phpdoc comment
  122. {
  123. QualifiedIdentifier parentClassIdentifier;
  124. if (DUContext* pctx = m_declaration->context()) {
  125. parentClassIdentifier = pctx->localScopeIdentifier();
  126. } else {
  127. kDebug() << "completion item for implementation has no parent context!";
  128. }
  129. replText += "/**\n" + indendation + " * ";
  130. // insert old comment:
  131. const QString indentationWithExtra = "\n" + indendation + " *";
  132. replText += m_declaration->comment().replace('\n', indentationWithExtra.toAscii().constData());
  133. replText += "\n" + indendation + " * @overload " + m_declaration->internalContext()->scopeIdentifier(true).toString();
  134. replText += "\n" + indendation + " **/\n" + indendation;
  135. }
  136. #endif
  137. // write function signature
  138. // copy existing modifiers
  139. if (!modifiers.isEmpty()) {
  140. // the tokens are in a bad order and there's no reverse method or similar, so we can't simply join the tokens
  141. QStringList::const_iterator i = modifiers.constEnd() - 1;
  142. while (true) {
  143. replText += (*i) + ' ';
  144. if (i == modifiers.constBegin()) {
  145. break;
  146. } else {
  147. --i;
  148. }
  149. }
  150. }
  151. QString functionName;
  152. bool isConstructorOrDestructor = false;
  153. bool isInterface = false;
  154. if (ClassMethodDeclaration* method = dynamic_cast<ClassMethodDeclaration*>(m_declaration.data())) {
  155. // NOTE: it should _never_ be private - but that's the completionmodel / context / worker's job
  156. if (!modifiers.contains("public") && !modifiers.contains("protected")) {
  157. if (method->accessPolicy() == Declaration::Protected) {
  158. replText += "protected ";
  159. } else {
  160. replText += "public ";
  161. }
  162. }
  163. if (!modifiers.contains("static") && method->isStatic()) {
  164. replText += "static ";
  165. }
  166. functionName = method->prettyName().str();
  167. isConstructorOrDestructor = method->isConstructor() || method->isDestructor();
  168. if (method->context() && method->context()->owner()) {
  169. ClassDeclaration* classDec = dynamic_cast<ClassDeclaration*>(method->context()->owner());
  170. if (classDec) {
  171. isInterface = (classDec->classType() == ClassDeclarationData::Interface);
  172. }
  173. }
  174. } else {
  175. kDebug() << "completion item for implementation was not a classfunction declaration!";
  176. functionName = m_declaration->identifier().toString();
  177. }
  178. if (!modifiers.contains("function")) {
  179. replText += "function ";
  180. }
  181. replText += functionName;
  182. {
  183. // get argument list
  184. QString arguments;
  185. createArgumentList(*this, arguments, 0, true);
  186. replText += arguments;
  187. }
  188. QString arguments;
  189. QVector<Declaration*> parameters;
  190. if (DUChainUtils::getArgumentContext(m_declaration.data()))
  191. parameters = DUChainUtils::getArgumentContext(m_declaration.data())->localDeclarations();
  192. arguments = '(';
  193. bool first = true;
  194. foreach(Declaration* dec, parameters) {
  195. if (first)
  196. first = false;
  197. else
  198. arguments += ", ";
  199. arguments += '$' + dec->identifier().toString();
  200. }
  201. arguments += ')';
  202. bool voidReturnType = false;
  203. if (FunctionType::Ptr::dynamicCast(m_declaration->abstractType())) {
  204. AbstractType::Ptr retType = FunctionType::Ptr::staticCast(m_declaration->abstractType())->returnType();
  205. if (retType->equals(new IntegralType(IntegralType::TypeVoid))) {
  206. voidReturnType = true;
  207. }
  208. }
  209. replText += QString("\n%1{\n%1 ").arg(indendation);
  210. if (isInterface) {
  211. } else if (!isConstructorOrDestructor && !voidReturnType) {
  212. replText += QString("$ret = parent::%2%3;\n%1 return $ret;").arg(indendation).arg(functionName).arg(arguments);
  213. } else {
  214. replText += QString("parent::%1%2;").arg(functionName).arg(arguments);
  215. }
  216. replText += QString("\n%1}\n%1")
  217. .arg(indendation);
  218. //TODO: properly place the cursor inside the {} part
  219. document->replaceText(replaceRange, replText);
  220. } else {
  221. kDebug() << "Declaration disappeared";
  222. }
  223. }
  224. }