diff --git a/CMakeLists.txt b/CMakeLists.txt index fa2e5032..95d20924 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,23 +2,39 @@ PROJECT(kdevpython) # write the plugin version to a file set(KDEVPYTHON_VERSION_MAJOR 1) -set(KDEVPYTHON_VERSION_MINOR 7) -set(KDEVPYTHON_VERSION_PATCH 60) +set(KDEVPYTHON_VERSION_MINOR 90) +set(KDEVPYTHON_VERSION_PATCH 90) + # KDevplatform dependency version set( KDEVPLATFORM_VERSION "${KDEVPYTHON_VERSION_MAJOR}.${KDEVPYTHON_VERSION_MINOR}.${KDEVPYTHON_VERSION_PATCH}" ) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${kdevpython_SOURCE_DIR}/cmake/) +find_package(ECM 0.0.9 REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${kdevpython_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH}) -cmake_minimum_required(VERSION 2.8.9) +set(REQUIRED QT_VERSION 5.2.0) -find_package(KDE4 REQUIRED) -find_package(KDevPlatform ${KDEVPLATFORM_VERSION} REQUIRED) +cmake_minimum_required(VERSION 2.8.12) + +include(CMakePackageConfigHelpers) +include(ECMAddTests) +include(ECMOptionalAddSubdirectory) +include(ECMSetupVersion) + +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDECompilerSettings) # find the system python 3 interpreter, only used for determining search paths. +# must be called before find_package(KF5) because it searchs for python too, but finds python2 find_package(PythonInterp 3.0 REQUIRED) configure_file( "${kdevpython_SOURCE_DIR}/kdevpythonversion.h.cmake" "${kdevpython_BINARY_DIR}/kdevpythonversion.h" @ONLY ) +find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Widgets Test WebKitWidgets) +find_package(KF5 REQUIRED I18n NewStuff ItemModels ThreadWeaver KDELibs4Support TextEditor KCMUtils) +find_package(KDevPlatform ${KDEVPLATFORM_VERSION} REQUIRED) +find_package(KDevelop REQUIRED) + enable_testing() @@ -29,23 +45,16 @@ endif ( NOT WIN32 ) # then, build the plugin include_directories( ${KDEVPLATFORM_INCLUDE_DIR} - ${KDE4_INCLUDES} - ${KDE4_INCLUDE_DIR}/threadweaver + +# ${KDE4_INCLUDE_DIR}/threadweaver ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/duchain ${CMAKE_CURRENT_SOURCE_DIR}/parser ${CMAKE_CURRENT_BINARY_DIR}/parser - ${KDEVPGQT_INCLUDE_DIR} + ${KDEVELOP_INCLUDE_DIR} ) - -add_definitions( -DKDE_DEFAULT_DEBUG_AREA=9011 ) - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -endif() - include_directories( ${CMAKE_CURRENT_BINARY_DIR}/parser ) @@ -62,33 +71,37 @@ add_subdirectory(checks) set(kdevpythonlanguagesupport_PART_SRCS codegen/correctionfilegenerator.cpp codegen/refactoring.cpp + codegen/codegendebug.cpp pythonlanguagesupport.cpp pythonparsejob.cpp pythonhighlighting.cpp + pythondebug.cpp checks/basiccheck.cpp checks/controlflowgraphbuilder.cpp checks/dataaccessvisitor.cpp ) -kde4_add_ui_files(kdevpythonlanguagesupport_PART_SRCS codegen/correctionwidget.ui) +ki18n_wrap_ui(kdevpythonlanguagesupport_PART_SRCS codegen/correctionwidget.ui) -kde4_add_plugin(kdevpythonlanguagesupport ${kdevpythonlanguagesupport_PART_SRCS}) +add_library(kdevpythonlanguagesupport MODULE ${kdevpythonlanguagesupport_PART_SRCS}) target_link_libraries(kdevpythonlanguagesupport - ${KDE4_KDEUI_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDE4_THREADWEAVER_LIBRARIES} - ${KDE4_KTEXTEDITOR_LIBS} - kdev4pythoncompletion - kdev4pythonparser - kdev4pythonduchain + KDev::Interfaces + KDev::Language + KDev::Util + KF5::ThreadWeaver + KF5::TextEditor + KF5::KDELibs4Support + kdevpythoncompletion + kdevpythonparser + kdevpythonduchain ) install(TARGETS kdevpythonlanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) -install(FILES kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +configure_file(kdevpythonsupport.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdevpythonsupport.desktop) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kdevpythonsupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) install(DIRECTORY documentation_files DESTINATION ${DATA_INSTALL_DIR}/kdevpythonsupport) install(DIRECTORY correction_files DESTINATION ${DATA_INSTALL_DIR}/kdevpythonsupport) diff --git a/DESIGN b/DESIGN index a86130dc..957138d5 100644 --- a/DESIGN +++ b/DESIGN @@ -20,23 +20,7 @@ It should be obvious from the large amount of examples what those rules look lik This class returns a CodeAst, which is then passed back to the parse job, which then calls the DUChain classes to analyze the tree. If an error occurs, parsing is aborted and the error is reported to the user. -As the standard python AST library obfuscates some ranges (like, in foo.bar.baz, all of foo, bar and baz are -said to start at column 0, while we need to know bar starts at 4 and baz at 8), we had no choice than to fork -the python parser and make those changes ourselves. The python source code can be found in the python-src -directory. The patches which were applied to the parser are in the patches/ subdirectory in git patch format; -those can be used if we want to switch the python version one day (from python 2.7 to 3.x, for example). The DUChain Library ------------------- -This library builds a Definition-Use-Chain from the AST, which is then used to -support code completion, syntax highlighting and other language features in -KDevelop. The design of the DUChain is described at: -http://api.kde.org/4.x-api/kdevplatform-apidocs/language/html/duchain-design.html - -The following language elements create a new Context: -- a class definition -- a function definition -- a compound statement, that includes for, while, if, with statements <- this has been removed, -as those do not really create a new context in the python language (i.e. variable declarations -inside such "contexts" still exist outside, unlike C++) - +See http://api.kde.org/4.x-api/kdevplatform-apidocs/language/html/duchain-design.html \ No newline at end of file diff --git a/INSTALL b/INSTALL index 489a7ddb..2b1585f4 100644 --- a/INSTALL +++ b/INSTALL @@ -6,13 +6,6 @@ make install If you run into crashes, please rebuild with the -DCMAKE_BUILD_TYPE=debug flag passed to cmake and report a bug with the backtrace attached. -IMPORTANT: If you're using Arch Linux: Arch breaks the standard of having "python" point to a python2 implementation. This breaks stuff. -So if you're using arch, either make "python" call some python2 interpreter instead of python3 while compiling (only while compiling, doesn't matter afterwards) -or edit the file python-src/Parser/asdl_c.py and change the first line to point to your python2 implementation, so usually replace -#! /usr/bin/env python -with -#! /usr/bin/env python2 - Running test suite: To enable test building, run cmake .. -DKDE4_BUILD_TESTS=true diff --git a/README.packagers b/README.packagers index af01c73d..a2d8fc04 100644 --- a/README.packagers +++ b/README.packagers @@ -29,3 +29,12 @@ It MUST be packaged together with the program, as it contains runtime data which is necessary for the program to work correctly (such as representations of python's built-in data types, which are then read by the parser etc.). + +Licensing notes +--------------- +The following files are not copyrighted: +Everything in duchain/tests/data/ +Everything in documentation_files/ +Everything in correction_files/ +Everything in app_templates/ +example_ast.py diff --git a/TODO b/TODO deleted file mode 100644 index 85fbe08c..00000000 --- a/TODO +++ /dev/null @@ -1,15 +0,0 @@ -- Support "from ... import *" -- fix function argument calltip (currently implemented incorrectly) -- write debugger interface -- use PYTHONPATH for searching includes -- add C module template -- add a lot of error reporting -- support unsure types in autocompletion / highlighting - - -A note from David Nolden(one of the authors of C++ Language support): -[2007-09-04 23:38] apaku: Btw. I have thought a bit about python code-completion. I think to make it really good, you need the following: -[2007-09-04 23:38] 1. An expression-parser, that is able to determine the type of any python expression (maybe could be integrated in type-builder) -[2007-09-04 23:39] 2. A specialized PythonDeclaration class that can hold an arbitrarily sized list of types -[2007-09-04 23:39] 3. Whenever assigning something to a value, evaluate that somethings type, and add it to the declarations type-list -[2007-09-04 23:40] However expression-parsing was a lot of work for c++, I don't know how much it would be for python diff --git a/checks/basiccheck.cpp b/checks/basiccheck.cpp index 6ec4a47a..dbc47787 100644 --- a/checks/basiccheck.cpp +++ b/checks/basiccheck.cpp @@ -26,8 +26,6 @@ #include #include -#include - using namespace KDevelop; QString BasicCheck::name() const diff --git a/checks/controlflowgraphbuilder.h b/checks/controlflowgraphbuilder.h index 1edcb52d..1a93e08c 100644 --- a/checks/controlflowgraphbuilder.h +++ b/checks/controlflowgraphbuilder.h @@ -28,6 +28,7 @@ #include #include +#include namespace Python { diff --git a/checks/dataaccessvisitor.cpp b/checks/dataaccessvisitor.cpp index 73129b89..7cffecc4 100644 --- a/checks/dataaccessvisitor.cpp +++ b/checks/dataaccessvisitor.cpp @@ -37,7 +37,7 @@ DataAccessVisitor::Access DataAccessVisitor::transformFlag(ExpressionAst::Contex if ( context == ExpressionAst::AugStore || context == ExpressionAst::Store ) { return DataAccess::Write; } - if ( context == ExpressionAst::ExpressionAst::Parameter ) { + if ( context == ExpressionAst::Parameter ) { // TODO return DataAccess::Read; } diff --git a/checks/dataaccessvisitor.h b/checks/dataaccessvisitor.h index d8aaa5f4..d309832d 100644 --- a/checks/dataaccessvisitor.h +++ b/checks/dataaccessvisitor.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace Python { diff --git a/codecompletion/CMakeLists.txt b/codecompletion/CMakeLists.txt index 8a569da2..644bc43a 100644 --- a/codecompletion/CMakeLists.txt +++ b/codecompletion/CMakeLists.txt @@ -8,6 +8,7 @@ set(completion_SRCS model.cpp worker.cpp helpers.cpp + codecompletiondebug.cpp items/missingincludeitem.cpp items/declaration.cpp @@ -18,22 +19,26 @@ set(completion_SRCS items/replacementvariable.cpp ) -kde4_add_library(kdev4pythoncompletion SHARED ${completion_SRCS}) +add_library(kdevpythoncompletion SHARED ${completion_SRCS}) -add_dependencies(kdev4pythoncompletion - kdev4pythonparser - kdev4pythonduchain +generate_export_header(kdevpythoncompletion EXPORT_MACRO_NAME KDEVPYTHONCOMPLETION_EXPORT + EXPORT_FILE_NAME pythoncompletionexport.h ) -target_link_libraries(kdev4pythoncompletion LINK_PRIVATE - ${KDE4_KDECORE_LIBS} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - kdev4pythonduchain - kdev4pythonparser +add_dependencies(kdevpythoncompletion + kdevpythonparser + kdevpythonduchain ) -install(TARGETS kdev4pythoncompletion DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) +target_link_libraries(kdevpythoncompletion LINK_PRIVATE + KF5::KDELibs4Support + KDev::Language + KDev::Interfaces + KDev::Project + kdevpythonduchain + kdevpythonparser +) + +install(TARGETS kdevpythoncompletion DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(tests) diff --git a/codecompletion/codecompletiondebug.cpp b/codecompletion/codecompletiondebug.cpp new file mode 100644 index 00000000..3f089c18 --- /dev/null +++ b/codecompletion/codecompletiondebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "codecompletiondebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON_CODECOMPLETION, "kdev.python.codecompletion") + + diff --git a/codecompletion/codecompletiondebug.h b/codecompletion/codecompletiondebug.h new file mode 100644 index 00000000..e3a78893 --- /dev/null +++ b/codecompletion/codecompletiondebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CODECOMPLETIONDEBUG_H +#define CODECOMPLETIONDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON_CODECOMPLETION) + +#endif + diff --git a/codecompletion/context.cpp b/codecompletion/context.cpp index 7d942065..532abe83 100644 --- a/codecompletion/context.cpp +++ b/codecompletion/context.cpp @@ -51,10 +51,12 @@ #include #include -#include #include #include +#include +#include "codecompletiondebug.h" + using namespace KTextEditor; using namespace KDevelop; @@ -75,7 +77,7 @@ std::unique_ptr visitorForString(QString str, DUContext* cont { ENSURE_CHAIN_NOT_LOCKED AstBuilder builder; - CodeAst::Ptr tmpAst = builder.parse(KUrl(), str); + CodeAst::Ptr tmpAst = builder.parse({}, str); if ( ! tmpAst ) { return std::unique_ptr(nullptr); } @@ -107,7 +109,7 @@ QList< CompletionTreeElementPointer > PythonCodeCompletionContext::ungroupedElem static QList setOmitParentheses(QList items) { for ( auto current: items ) { - if ( auto func = KSharedPtr::dynamicCast(current) ) { + if ( auto func = dynamic_cast(current.data()) ) { func->setDoNotCall(true); } } @@ -144,8 +146,8 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::functionCallI auto v = visitorForString(m_guessTypeOfExpression, m_duContext.data()); DUChainReadLocker lock; if ( ! v || ! v->lastDeclaration() ) { - kWarning() << "Did not receive a function declaration from expression visitor! Not offering call tips."; - kWarning() << "Tried: " << m_guessTypeOfExpression; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "Did not receive a function declaration from expression visitor! Not offering call tips."; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "Tried: " << m_guessTypeOfExpression; return resultingItems; } functionCalled = Helper::functionDeclarationForCalledDeclaration(v->lastDeclaration()).first.data(); @@ -158,7 +160,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::functionCallI auto calltipItems = declarationListToItemList(calltips); foreach ( CompletionTreeItemPointer current, calltipItems ) { - kDebug() << "Adding calltip item, at argument:" << m_alreadyGivenParametersCount+1; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Adding calltip item, at argument:" << m_alreadyGivenParametersCount+1; FunctionDeclarationCompletionItem* item = static_cast(current.data()); item->setAtArgument(m_alreadyGivenParametersCount + 1); item->setDepth(depth()); @@ -175,7 +177,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::functionCallI if ( DUContext* args = DUChainUtils::getArgumentContext(functionCalled) ) { int normalParameters = args->localDeclarations().count() - functionCalled->defaultParametersSize(); if ( normalParameters > m_alreadyGivenParametersCount ) { - kDebug() << "Not at default arguments yet"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Not at default arguments yet"; return resultingItems; } for ( unsigned int i = 0; i < functionCalled->defaultParametersSize(); i++ ) { @@ -184,7 +186,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::functionCallI paramName + "=", i18n("specify default parameter"), KeywordItem::ImportantItem)); } - kDebug() << "adding " << functionCalled->defaultParametersSize() << "default args"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "adding " << functionCalled->defaultParametersSize() << "default args"; } return resultingItems; @@ -196,7 +198,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::defineItems() ItemList resultingItems; // Find all base classes of the current class context if ( m_duContext->type() != DUContext::Class ) { - kWarning() << "current context is not a class context, not offering define completion"; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "current context is not a class context, not offering define completion"; return resultingItems; } ClassDeclaration* klass = dynamic_cast(m_duContext->owner()); @@ -232,12 +234,14 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::defineItems() existingIdentifiers << identifier; QStringList argumentNames; DUContext* argumentsContext = DUChainUtils::getArgumentContext(funcDecl); - foreach ( Declaration* argument, argumentsContext->localDeclarations() ) { - argumentNames << argument->identifier().toString(); + if ( argumentsContext ) { + foreach ( Declaration* argument, argumentsContext->localDeclarations() ) { + argumentNames << argument->identifier().toString(); + } + resultingItems << CompletionTreeItemPointer(new ImplementFunctionCompletionItem( + funcDecl->identifier().toString(), argumentNames, m_indent) + ); } - resultingItems << CompletionTreeItemPointer(new ImplementFunctionCompletionItem( - funcDecl->identifier().toString(), argumentNames, m_indent) - ); } } isOwnContext = false; @@ -247,13 +251,13 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::defineItems() PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::raiseItems() { - kDebug() << "Finding items for raise statement"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Finding items for raise statement"; DUChainReadLocker lock; ItemList resultingItems; ReferencedTopDUContext ctx = Helper::getDocumentationFileContext(); QList< Declaration* > declarations = ctx->findDeclarations(QualifiedIdentifier("BaseException")); if ( declarations.isEmpty() || ! declarations.first()->abstractType() ) { - kDebug() << "No valid exception classes found, aborting"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "No valid exception classes found, aborting"; return resultingItems; } Declaration* base = declarations.first(); @@ -286,7 +290,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::importFileIte { DUChainReadLocker lock; ItemList resultingItems; - kDebug() << "Preparing to do autocompletion for import..."; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Preparing to do autocompletion for import..."; m_maxFolderScanDepth = 1; resultingItems << includeItemsForSubmodule(""); return resultingItems; @@ -296,7 +300,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::inheritanceIt { ItemList resultingItems; DUChainReadLocker lock; - kDebug() << "InheritanceCompletion"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "InheritanceCompletion"; QList declarations; if ( ! m_guessTypeOfExpression.isEmpty() ) { // The class completion is a member access @@ -336,15 +340,15 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::memberAccessI DUChainReadLocker lock; if ( v ) { if ( v->lastType() ) { - kDebug() << v->lastType()->toString(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << v->lastType()->toString(); resultingItems << getCompletionItemsForType(v->lastType()); } else { - kWarning() << "Did not receive a type from expression visitor! Not offering autocompletion."; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "Did not receive a type from expression visitor! Not offering autocompletion."; } } else { - kWarning() << "Completion requested for syntactically invalid expression, not offering anything"; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "Completion requested for syntactically invalid expression, not offering anything"; } // append eventually stripped postfix, for e.g. os.chdir| @@ -373,12 +377,12 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::stringFormatt ItemList resultingItems; int cursorPosition; StringFormatter stringFormatter(CodeHelpers::extractStringUnderCursor(m_text, - m_duContext->range().castToSimpleRange().textRange(), - m_position.castToSimpleCursor().textCursor(), + m_duContext->range().castToSimpleRange(), + m_position.castToSimpleCursor(), &cursorPosition)); - kDebug() << "Next identifier id: " << stringFormatter.nextIdentifierId(); - kDebug() << "Cursor position in string: " << cursorPosition; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Next identifier id: " << stringFormatter.nextIdentifierId(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Cursor position in string: " << cursorPosition; bool insideReplacementVariable = stringFormatter.isInsideReplacementVariable(cursorPosition); RangeInString variablePosition = stringFormatter.getVariablePosition(cursorPosition); @@ -407,11 +411,10 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::stringFormatt // in the document. We can safely assume that the replacement variable is on one line, // because the regex does not allow newlines inside replacement variables. KTextEditor::Range range; - range.setBothLines(m_position.line); - range.start().setColumn(m_position.column - (cursorPosition - variablePosition.beginIndex)); - range.end().setColumn(m_position.column + (variablePosition.endIndex - cursorPosition)); + range.setStart({m_position.line, m_position.column - (cursorPosition - variablePosition.beginIndex)}); + range.setEnd({m_position.line, m_position.column + (variablePosition.endIndex - cursorPosition)}); - kDebug() << "Variable under cursor: " << variable->toString(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Variable under cursor: " << variable->toString(); bool hasNumericOnlyOption = variable->hasPrecision() || (variable->hasType() && variable->type() != 's') || variable->align() == '='; @@ -434,7 +437,7 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::stringFormatt } if ( ! variable->hasFormatSpec() ) { - auto addFormatSpec = [&](const QString& format, const QString& title, bool useTemplateEngine=false) + auto addFormatSpec = [&](const QString& format, const QString& title, bool useTemplateEngine) { resultingItems.append(makeFormattingItem(variable->conversion(), format, title, useTemplateEngine)); }; @@ -445,17 +448,17 @@ PythonCodeCompletionContext::ItemList PythonCodeCompletionContext::stringFormatt // These options don't make sense if we've set conversion using str() or repr() if ( ! variable->hasConversion() ) { addFormatSpec(".${precision}", i18n("Specify precision"), true); - addFormatSpec("%", i18n("Format as percentage")); - addFormatSpec("c", i18n("Format as character")); - addFormatSpec("b", i18n("Format as binary number")); - addFormatSpec("o", i18n("Format as octal number")); - addFormatSpec("x", i18n("Format as hexadecimal number")); - addFormatSpec("e", i18n("Format in scientific (exponent) notation")); - addFormatSpec("f", i18n("Format as fixed point number")); + addFormatSpec("%", i18n("Format as percentage"), false); + addFormatSpec("c", i18n("Format as character"), false); + addFormatSpec("b", i18n("Format as binary number"), false); + addFormatSpec("o", i18n("Format as octal number"), false); + addFormatSpec("x", i18n("Format as hexadecimal number"), false); + addFormatSpec("e", i18n("Format in scientific (exponent) notation"), false); + addFormatSpec("f", i18n("Format as fixed point number"), false); } } - kDebug() << "Resulting items size: " << resultingItems.size(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Resulting items size: " << resultingItems.size(); return resultingItems; } @@ -551,8 +554,8 @@ QList PythonCodeCompletionContext::completionItems(bo m_fullCompletion = fullCompletion; ItemList resultingItems; - kDebug() << "Line: " << m_position.line; - kDebug() << "Completion type:" << m_operation; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Line: " << m_position.line; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Completion type:" << m_operation; if ( m_operation != FunctionCallCompletion ) { resultingItems.append(shebangItems()); @@ -564,7 +567,7 @@ QList PythonCodeCompletionContext::completionItems(bo } if ( m_operation == PythonCodeCompletionContext::NoCompletion ) { - kDebug() << "no code completion"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "no code completion"; } else if ( m_operation == PythonCodeCompletionContext::GeneratorVariableCompletion ) { resultingItems.append(generatorItems()); @@ -609,7 +612,7 @@ QList PythonCodeCompletionContext::completionItems(bo DUChainReadLocker lock; QList declarations = m_duContext->allDeclarations(m_position, m_duContext->topContext()); foreach ( const DeclarationDepthPair& d, declarations ) { - if ( d.first and d.first->context()->type() == DUContext::Class ) { + if ( d.first && d.first->context()->type() == DUContext::Class ) { declarations.removeAll(d); } } @@ -649,7 +652,7 @@ QList PythonCodeCompletionContext::getMissingIncludeI } // See if there's a module called like that. - QPair found = ContextBuilder::findModulePath(components.join("."), m_workingOnDocument); + auto found = ContextBuilder::findModulePath(components.join("."), m_workingOnDocument); // Check if anything was found if ( found.first.isValid() ) { @@ -681,7 +684,7 @@ QList PythonCodeCompletionContext::declarationListToI int count = declarations.length(); for ( int i = 0; i < count; i++ ) { if ( maxDepth && maxDepth > declarations.at(i).second ) { - kDebug() << "Skipped completion item because of its depth"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Skipped completion item because of its depth"; continue; } currentDeclaration = DeclarationPointer(declarations.at(i).first); @@ -725,7 +728,6 @@ QList< CompletionTreeItemPointer > PythonCodeCompletionContext::getCompletionIte QList result; UnsureType::Ptr unsure = type.cast(); int count = unsure->typesSize(); - kDebug() << "Getting completion items for " << count << "types of unsure type " << unsure; for ( int i = 0; i < count; i++ ) { result.append(getCompletionItemsForOneType(unsure->types()[i].abstractType())); } @@ -770,20 +772,20 @@ QList PythonCodeCompletionContext::getCompletionItems } // find properties of class declaration TypePtr cls = StructureType::Ptr::dynamicCast(type); - kDebug() << "Finding completion items for class type"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Finding completion items for class type"; if ( ! cls || ! cls->internalContext(m_duContext->topContext()) ) { - kWarning() << "No class type available, no completion offered"; + qCWarning(KDEV_PYTHON_CODECOMPLETION) << "No class type available, no completion offered"; return QList(); } // the PublicOnly will filter out non-explictly defined __get__ etc. functions inherited from object QList searchContexts = Helper::internalContextsForClass(cls, m_duContext->topContext(), Helper::PublicOnly); QList keepDeclarations; foreach ( const DUContext* currentlySearchedContext, searchContexts ) { - kDebug() << "searching context " << currentlySearchedContext->scopeIdentifier() << "for autocompletion items"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "searching context " << currentlySearchedContext->scopeIdentifier() << "for autocompletion items"; QList declarations = currentlySearchedContext->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext(), false); - kDebug() << "found" << declarations.length() << "declarations"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "found" << declarations.length() << "declarations"; // filter out those which are builtin functions, and those which were imported; we don't want those here // also, discard all magic functions from autocompletion @@ -794,7 +796,7 @@ QList PythonCodeCompletionContext::getCompletionItems keepDeclarations.append(current); } else { - kDebug() << "Discarding declaration " << current.first->toString(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Discarding declaration " << current.first->toString(); } } } @@ -803,7 +805,7 @@ QList PythonCodeCompletionContext::getCompletionItems QList PythonCodeCompletionContext::findIncludeItems(IncludeSearchTarget item) { - kDebug() << "TARGET:" << item.directory.pathOrUrl() << item.remainingIdentifiers << item.directory.path(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "TARGET:" << item.directory.path() << item.remainingIdentifiers; QDir currentDirectory(item.directory.path()); QFileInfoList contents = currentDirectory.entryInfoList(QStringList(), QDir::Files | QDir::Dirs); bool atBottom = item.remainingIdentifiers.isEmpty(); @@ -832,7 +834,7 @@ QList PythonCodeCompletionContext::findIncludeItems(I else { QFileInfo file(item.directory.path(), item.remainingIdentifiers.first() + ".py"); item.remainingIdentifiers.removeFirst(); - kDebug() << " CHECK:" << file.absoluteFilePath(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << " CHECK:" << file.absoluteFilePath(); if ( file.exists() ) { sourceFile = file.absoluteFilePath(); } @@ -841,9 +843,9 @@ QList PythonCodeCompletionContext::findIncludeItems(I if ( ! sourceFile.isEmpty() ) { IndexedString filename(sourceFile); TopDUContext* top = DUChain::self()->chainForDocument(filename); - kDebug() << top; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << top; DUContext* c = internalContextForDeclaration(top, item.remainingIdentifiers); - kDebug() << " GOT:" << c; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << " GOT:" << c; if ( c ) { // tell function declaration items not to add brackets items << setOmitParentheses(declarationListToItemList(c->localDeclarations().toList())); @@ -861,7 +863,7 @@ QList PythonCodeCompletionContext::findIncludeItems(I if ( file.fileName().startsWith('.') ) { continue; } - kDebug() << " > CONTENT:" << file.absolutePath() << file.fileName(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << " > CONTENT:" << file.absolutePath() << file.fileName(); if ( file.isFile() ) { if ( file.fileName().endsWith(".py") || file.fileName().endsWith(".so") ) { IncludeItem fileInclude; @@ -926,7 +928,7 @@ DUContext* PythonCodeCompletionContext::internalContextForDeclaration(TopDUConte QList PythonCodeCompletionContext::includeItemsForSubmodule(QString submodule) { - QList searchPaths = Helper::getSearchPaths(m_workingOnDocument); + QList searchPaths = Helper::getSearchPaths(m_workingOnDocument); QStringList subdirs; if ( ! submodule.isEmpty() ) { @@ -943,23 +945,21 @@ QList PythonCodeCompletionContext::includeItemsForSub // Thus, we first generate a list of possible paths, then match them against those which actually exist // and then gather all the items in those paths. - foreach ( KUrl currentPath, searchPaths ) { - kDebug() << "Searching: " << currentPath << subdirs; + foreach ( QUrl currentPath, searchPaths ) { + auto d = QDir(currentPath.path()); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Searching: " << currentPath << subdirs; int identifiersUsed = 0; foreach ( const QString& subdir, subdirs ) { - currentPath.cd(subdir); - QFileInfo d(currentPath.path()); - kDebug() << currentPath << d.exists() << d.isDir(); - if ( ! d.exists() || ! d.isDir() ) { - currentPath.cd(".."); - currentPath.cleanPath(); + qDebug() << "changing into subdir" << subdir; + if ( ! d.cd(subdir) ) { break; } + qCDebug(KDEV_PYTHON_CODECOMPLETION) << d.absolutePath() << d.exists(); identifiersUsed++; } QStringList remainingIdentifiers = subdirs.mid(identifiersUsed, -1); - foundPaths.append(IncludeSearchTarget(currentPath, remainingIdentifiers)); - kDebug() << "Found path:" << currentPath << remainingIdentifiers << subdirs; + foundPaths.append(IncludeSearchTarget(d.absolutePath(), remainingIdentifiers)); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Found path:" << d.absolutePath() << remainingIdentifiers << subdirs; } return findIncludeItems(foundPaths); } @@ -986,8 +986,8 @@ void PythonCodeCompletionContext::summonParentForEventualCall(TokenList allExpre int offset = 0; while ( true ) { QPair nextCall = allExpressions.nextIndexOfStatus(ExpressionParser::EventualCallFound, offset); - kDebug() << "next call:" << nextCall; - kDebug() << allExpressions.toString(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "next call:" << nextCall; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << allExpressions.toString(); if ( nextCall.first == -1 ) { // no more eventual calls break; @@ -995,12 +995,12 @@ void PythonCodeCompletionContext::summonParentForEventualCall(TokenList allExpre offset = nextCall.first; allExpressions.reset(offset); TokenListEntry eventualFunction = allExpressions.weakPop(); - kDebug() << eventualFunction.expression << eventualFunction.status; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << eventualFunction.expression << eventualFunction.status; // it's only a call if a "(" bracket is followed (<- direction) by an expression. if ( eventualFunction.status != ExpressionParser::ExpressionFound ) { continue; // not a call, try the next opening "(" bracket } - kDebug() << "Call found! Creating parent-context."; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Call found! Creating parent-context."; // determine the amount of "free" commas in between allExpressions.reset(); int atParameter = 0; @@ -1039,11 +1039,11 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex m_workingOnDocument = context->topContext()->url().toUrl(); QString textWithoutStrings = CodeHelpers::killStrings(text); - kDebug() << text << position << context->localScopeIdentifier().toString() << context->range(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << text << position << context->localScopeIdentifier().toString() << context->range(); QPair beforeAndAfterCursor = CodeHelpers::splitCodeByCursor(text, - context->range().castToSimpleRange().textRange(), - position.castToSimpleCursor().textCursor()); + context->range().castToSimpleRange(), + position.castToSimpleCursor()); // check if the current position is inside a multi-line comment -> no completion if this is the case CodeHelpers::EndLocation location = CodeHelpers::endsInside(beforeAndAfterCursor.first); @@ -1086,7 +1086,7 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex currentlyCheckedLine -= 1; } while ( currentlyChecked && context->parentContextOf(currentlyChecked) ) { - kDebug() << "checking:" << currentlyChecked->range() << currentlyChecked->type(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "checking:" << currentlyChecked->range() << currentlyChecked->type(); // FIXME: "<=" is not really good, it must be exactly one indent-level less int offset = position.line-currentlyChecked->range().start.line; // If the check leaves the current context, abort. @@ -1096,7 +1096,7 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex if ( indents.indentForLine(indents.linesCount()-1-offset) <= indents.indentForLine(indents.linesCount()-1) ) { - kDebug() << "changing context to" << currentlyChecked->range() + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "changing context to" << currentlyChecked->range() << ( currentlyChecked->type() == DUContext::Class ); context = currentlyChecked; break; @@ -1169,7 +1169,7 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex m_operation = DefineCompletion; } else { - kDebug() << "def outside class context"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "def outside class context"; m_operation = NoCompletion; } return; @@ -1262,8 +1262,8 @@ PythonCodeCompletionContext::PythonCodeCompletionContext(DUContextPointer contex else { m_searchImportItemsInModule = firstPiece + "." + secondPiece; } - kDebug() << firstPiece << secondPiece; - kDebug() << "Got submodule to search:" << m_searchImportItemsInModule << "from text" << textWithoutStrings; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << firstPiece << secondPiece; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "Got submodule to search:" << m_searchImportItemsInModule << "from text" << textWithoutStrings; m_operation = ImportSubCompletion; return; } diff --git a/codecompletion/context.h b/codecompletion/context.h index f6b0667e..3c403b80 100644 --- a/codecompletion/context.h +++ b/codecompletion/context.h @@ -50,10 +50,10 @@ typedef QPair DeclarationDepthPair; **/ class IncludeSearchTarget { public: - IncludeSearchTarget(KUrl d_, QStringList r_) : directory(d_), remainingIdentifiers(r_) { - directory.cleanPath(); + IncludeSearchTarget(QUrl d_, QStringList r_) : directory(d_), remainingIdentifiers(r_) { + directory.setPath(QDir::cleanPath(directory.path())); }; - KUrl directory; + QUrl directory; QStringList remainingIdentifiers; }; @@ -163,7 +163,7 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionContext : public KDevelop: int m_maxFolderScanDepth; QStringList m_searchingForModule; QString m_searchImportItemsInModule; - KUrl m_workingOnDocument; + QUrl m_workingOnDocument; CodeCompletionContext* m_child; diff --git a/codecompletion/helpers.cpp b/codecompletion/helpers.cpp index e92223b3..6c608eed 100644 --- a/codecompletion/helpers.cpp +++ b/codecompletion/helpers.cpp @@ -33,6 +33,9 @@ #include #include +#include +#include "codecompletiondebug.h" + #include "duchain/declarations/functiondeclaration.h" #include "parser/codehelpers.h" @@ -177,7 +180,7 @@ QString ExpressionParser::skipUntilStatus(ExpressionParser::Status requestedStat Status currentStatus = InvalidStatus; while ( currentStatus != requestedStatus ) { lastExpression = popExpression(¤tStatus); - kDebug() << lastExpression << currentStatus; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << lastExpression << currentStatus; if ( currentStatus == NothingFound ) { *ok = ( requestedStatus == NothingFound ); // ok exactly if the caller requested NothingFound as end status return QString(); @@ -238,7 +241,7 @@ QString ExpressionParser::popExpression(ExpressionParser::Status* status) bool lastCharIsSpace = getRemainingCode().right(1).at(0).isSpace(); m_cursorPositionInString -= trailingWhitespace(); if ( operatingOn.endsWith('(') ) { - kDebug() << "eventual call found"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "eventual call found"; m_cursorPositionInString -= 1; *status = EventualCallFound; return QString(); @@ -409,7 +412,7 @@ void createArgumentList(Declaration* dec_, QString& ret, QList< QVariant >* high StringFormatter::StringFormatter(const QString &string) : m_string(string) { - kDebug() << "String being parsed: " << string; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "String being parsed: " << string; QRegExp regex("\\{(\\w+)(?:!([rs]))?(?:\\:(.*))?\\}"); regex.setMinimal(true); int pos = 0; @@ -419,7 +422,7 @@ StringFormatter::StringFormatter(const QString &string) QChar conversion = (conversionStr.isNull() || conversionStr.isEmpty()) ? QChar() : conversionStr.at(0); QString formatSpec = regex.cap(3); - kDebug() << "variable: " << regex.cap(0); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "variable: " << regex.cap(0); // The regex guarantees that conversion is only a single character ReplacementVariable variable(identifier, conversion, formatSpec); diff --git a/codecompletion/items/declaration.cpp b/codecompletion/items/declaration.cpp index 7df09403..ecd537a5 100644 --- a/codecompletion/items/declaration.cpp +++ b/codecompletion/items/declaration.cpp @@ -34,7 +34,9 @@ using namespace KDevelop; namespace Python { -PythonDeclarationCompletionItem::PythonDeclarationCompletionItem(DeclarationPointer decl, KSharedPtr< CodeCompletionContext > context, int inheritanceDepth) +PythonDeclarationCompletionItem::PythonDeclarationCompletionItem(DeclarationPointer decl, + QExplicitlySharedDataPointer context, + int inheritanceDepth) : NormalDeclarationCompletionItem(decl, context, inheritanceDepth) , m_typeHint(PythonCodeCompletionContext::NoHint) , m_addMatchQuality(0) @@ -68,7 +70,7 @@ QVariant PythonDeclarationCompletionItem::data(const QModelIndex& index, int rol return 0; } if ( m_typeHint == PythonCodeCompletionContext::IterableRequested - && dynamic_cast(declaration()->abstractType().unsafeData()) ) + && dynamic_cast(declaration()->abstractType().data()) ) { return 10; } diff --git a/codecompletion/items/declaration.h b/codecompletion/items/declaration.h index 5277ea23..0259b494 100644 --- a/codecompletion/items/declaration.h +++ b/codecompletion/items/declaration.h @@ -29,7 +29,7 @@ namespace Python { class PythonDeclarationCompletionItem : public KDevelop::NormalDeclarationCompletionItem { public: PythonDeclarationCompletionItem(KDevelop::DeclarationPointer decl = KDevelop::DeclarationPointer(), - KSharedPtr context = KSharedPtr(), + QExplicitlySharedDataPointer context = QExplicitlySharedDataPointer(), int inheritanceDepth = 0); virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const; void setTypeHint(PythonCodeCompletionContext::ItemTypeHint type); diff --git a/codecompletion/items/functiondeclaration.cpp b/codecompletion/items/functiondeclaration.cpp index b23f8ee5..b807a2fb 100644 --- a/codecompletion/items/functiondeclaration.cpp +++ b/codecompletion/items/functiondeclaration.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,8 @@ #include "declarations/functiondeclaration.h" #include "duchain/helpers.h" +#include +#include "../codecompletiondebug.h" using namespace KDevelop; using namespace KTextEditor; @@ -115,7 +118,7 @@ QVariant FunctionDeclarationCompletionItem::data(const QModelIndex& index, int r case KDevelop::CodeCompletionModel::MatchQuality: { if ( m_typeHint == PythonCodeCompletionContext::IterableRequested && dec && dec->type() - && dynamic_cast(dec->type()->returnType().unsafeData()) ) + && dynamic_cast(dec->type()->returnType().data()) ) { return 2 + PythonDeclarationCompletionItem::data(index, role, model).toInt(); } @@ -130,16 +133,17 @@ void FunctionDeclarationCompletionItem::setDoNotCall(bool doNotCall) m_doNotCall = doNotCall; } -void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document, const KTextEditor::Range& word) +void FunctionDeclarationCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word) { - kDebug() << "FunctionDeclarationCompletionItem executed"; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "FunctionDeclarationCompletionItem executed"; + KTextEditor::Document* document = view->document(); DeclarationPointer resolvedDecl(Helper::resolveAliasDeclaration(declaration().data())); DUChainReadLocker lock; QPair fdecl = Helper::functionDeclarationForCalledDeclaration(resolvedDecl); lock.unlock(); if ( ! fdecl.first && (! resolvedDecl || ! resolvedDecl->abstractType() || resolvedDecl->abstractType()->whichType() != AbstractType::TypeStructure) ) { - kError() << "ERROR: could not get declaration data, not executing completion item!"; + qCritical(KDEV_PYTHON_CODECOMPLETION) << "ERROR: could not get declaration data, not executing completion item!"; return; } QString suffix = "()"; @@ -151,7 +155,7 @@ void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document { // don't insert brackets if they're already there, // the item is a decorator, or if it's an import item. - suffix = ""; + suffix.clear(); } // place cursor behind bracktes by default int skip = 2; @@ -173,9 +177,7 @@ void FunctionDeclarationCompletionItem::executed(KTextEditor::Document* document } } document->replaceText(word, declaration()->identifier().toString() + suffix); - if ( View* view = document->activeView() ) { - view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) ); - } + view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) ); } FunctionDeclarationCompletionItem::~FunctionDeclarationCompletionItem() { } diff --git a/codecompletion/items/functiondeclaration.h b/codecompletion/items/functiondeclaration.h index bd571c1a..2e301a57 100644 --- a/codecompletion/items/functiondeclaration.h +++ b/codecompletion/items/functiondeclaration.h @@ -41,7 +41,7 @@ class FunctionDeclarationCompletionItem : public Python::PythonDeclarationComple virtual QVariant data(const QModelIndex& index, int role, const CodeCompletionModel* model) const; - virtual void executed(KTextEditor::Document* document, const KTextEditor::Range& word); + virtual void executed(KTextEditor::View* view, const KTextEditor::Range& word) override; private: int m_atArgument; int m_depth; diff --git a/codecompletion/items/implementfunction.cpp b/codecompletion/items/implementfunction.cpp index 8b51fa99..5c619b43 100644 --- a/codecompletion/items/implementfunction.cpp +++ b/codecompletion/items/implementfunction.cpp @@ -22,10 +22,14 @@ #include #include +#include + #include #include #include +#include + using namespace KDevelop; using namespace KTextEditor; @@ -37,14 +41,15 @@ ImplementFunctionCompletionItem::ImplementFunctionCompletionItem(const QString& } -void ImplementFunctionCompletionItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) +void ImplementFunctionCompletionItem::execute(KTextEditor::View* view, const KTextEditor::Range& word) { + auto document = view->document(); const QString finalText = m_name + "(" + m_arguments.join(", ") + "):"; document->replaceText(word, finalText); // 4 spaces is indentation for python. everyone does it like this. you must, too. // TODO use kate settings document->insertLine(word.start().line() + 1, m_previousIndent + " "); - if ( View* view = document->activeView() ) { + if ( View* view = static_cast(ICore::self()->partController())->activeView() ) { view->setCursorPosition(Cursor(word.end().line() + 1, m_previousIndent.length() + 4)); } } diff --git a/codecompletion/items/implementfunction.h b/codecompletion/items/implementfunction.h index 42891cae..dfd838ef 100644 --- a/codecompletion/items/implementfunction.h +++ b/codecompletion/items/implementfunction.h @@ -29,7 +29,7 @@ class ImplementFunctionCompletionItem : public CompletionTreeItem { public: ImplementFunctionCompletionItem(const QString& name, const QStringList& arguments, const QString& previousIndent); - virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); + virtual void execute(KTextEditor::View* view, const KTextEditor::Range& word) override; virtual QVariant data(const QModelIndex& index, int role, const CodeCompletionModel* model) const; private: diff --git a/codecompletion/items/importfile.cpp b/codecompletion/items/importfile.cpp index 56d027d0..bbc9de49 100644 --- a/codecompletion/items/importfile.cpp +++ b/codecompletion/items/importfile.cpp @@ -19,10 +19,14 @@ #include "importfile.h" #include +#include #include #include "duchain/navigation/navigationwidget.h" +#include +#include "codecompletiondebug.h" + using namespace KDevelop; namespace Python { @@ -37,11 +41,11 @@ ImportFileItem::~ImportFileItem() } -void ImportFileItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) +void ImportFileItem::execute(KTextEditor::View* view, const KTextEditor::Range& word) { - kDebug() << "ImportFileItem executed"; - document->replaceText(word, moduleName); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "ImportFileItem executed"; + view->document()->replaceText(word, moduleName); } -} \ No newline at end of file +} diff --git a/codecompletion/items/importfile.h b/codecompletion/items/importfile.h index 76c61ebf..a7077fd3 100644 --- a/codecompletion/items/importfile.h +++ b/codecompletion/items/importfile.h @@ -35,7 +35,7 @@ class ImportFileItem : public IncludeFileItemBase ImportFileItem(const KDevelop::IncludeItem& include); virtual ~ImportFileItem(); - virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); + virtual void execute(KTextEditor::View* view, const KTextEditor::Range& word) override; QString moduleName; KDevelop::IProject* fromProject; }; diff --git a/codecompletion/items/keyword.cpp b/codecompletion/items/keyword.cpp index 834ea70b..81393780 100644 --- a/codecompletion/items/keyword.cpp +++ b/codecompletion/items/keyword.cpp @@ -1,16 +1,16 @@ /***************************************************************************** - * Copyright (c) 2011 Sven Brauch * + * Copyright (c) 2011-2014 Sven Brauch * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License, or (at your option) any later version. * - * * + * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * - * * + * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************** @@ -21,6 +21,7 @@ #include #include #include + #include #include @@ -37,14 +38,14 @@ KeywordItem::KeywordItem(KDevelop::CodeCompletionContext::Ptr context, QString k m_keyword = keyword; } -void KeywordItem::execute(Document* document, const Range& word) +void KeywordItem::execute(View* view, const Range& word) { if ( m_flags & ForceLineBeginning ) { Range newRange(Cursor(word.start().line(), 0), word.end()); - document->replaceText(newRange, m_keyword); + view->document()->replaceText(newRange, m_keyword); } else { - document->replaceText(word, m_keyword); + view->document()->replaceText(word, m_keyword); } } diff --git a/codecompletion/items/keyword.h b/codecompletion/items/keyword.h index 21cc2dc4..5ec224f5 100644 --- a/codecompletion/items/keyword.h +++ b/codecompletion/items/keyword.h @@ -35,8 +35,8 @@ class KeywordItem : public NormalDeclarationCompletionItem ImportantItem = 0x2 }; KeywordItem(CodeCompletionContext::Ptr context, QString keyword, QString descr, Python::KeywordItem::Flags flags = NoFlags); - virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); - virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const; + virtual void execute(KTextEditor::View* view, const KTextEditor::Range& word) override; + virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const override; private: QString m_keyword; QString m_description; diff --git a/codecompletion/items/missingincludeitem.cpp b/codecompletion/items/missingincludeitem.cpp index 49a11107..db5189ae 100644 --- a/codecompletion/items/missingincludeitem.cpp +++ b/codecompletion/items/missingincludeitem.cpp @@ -16,9 +16,15 @@ *****************************************************************************/ #include "missingincludeitem.h" + #include + #include +#include + #include +#include +#include "codecompletiondebug.h" namespace Python { @@ -48,14 +54,14 @@ QVariant MissingIncludeItem::data(const QModelIndex& index, int role, const KDev return QVariant(); } -void MissingIncludeItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) +void MissingIncludeItem::execute(KTextEditor::View* view, const KTextEditor::Range& word) { - kDebug() << "executed with text" << m_text; + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "executed with text" << m_text; // First, add the import statement to the top of the file // FIXME: deal with multi-line comments int insertAt = 0; - for ( int i = 0; i < document->lines(); i++ ) { - const QString& line = document->line(i); + for ( int i = 0; i < view->document()->lines(); i++ ) { + const QString& line = view->document()->line(i); if ( line.trimmed().startsWith('#') || line.trimmed().isEmpty() ) { continue; } @@ -79,11 +85,11 @@ void MissingIncludeItem::execute(KTextEditor::Document* document, const KTextEdi if ( ! m_removeComponents.isEmpty() ) { const KTextEditor::Cursor end = word.end(); const KTextEditor::Cursor start = end - KTextEditor::Cursor(0, m_removeComponents.length()); - document->replaceText(KTextEditor::Range(start, end), m_matchText); + view->document()->replaceText(KTextEditor::Range(start, end), m_matchText); } // Do this only later, otherwise ranges change - document->insertLine(qMax(0, insertAt - 1), m_text); + view->document()->insertLine(qMax(0, insertAt - 1), m_text); } } diff --git a/codecompletion/items/missingincludeitem.h b/codecompletion/items/missingincludeitem.h index 17d646cd..963cede6 100644 --- a/codecompletion/items/missingincludeitem.h +++ b/codecompletion/items/missingincludeitem.h @@ -27,8 +27,8 @@ namespace Python { class MissingIncludeItem : public KDevelop::CompletionTreeItem { public: MissingIncludeItem(const QString& insertText, const QString& matchText, const QString& removeComponents=QString()); - virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); - virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const; + virtual void execute(KTextEditor::View* view, const KTextEditor::Range& word) override; + virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const override; private: const QString m_text; diff --git a/codecompletion/items/replacementvariable.cpp b/codecompletion/items/replacementvariable.cpp index edfc3f62..e188983e 100644 --- a/codecompletion/items/replacementvariable.cpp +++ b/codecompletion/items/replacementvariable.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +// #include not currently supported #include #include @@ -38,8 +38,9 @@ ReplacementVariableItem::ReplacementVariableItem(const ReplacementVariable &vari { } -void ReplacementVariableItem::execute(Document *document, const Range &word) +void ReplacementVariableItem::execute(View* view, const Range &word) { + auto document = view->document(); if ( ! m_position.isValid() ) { m_position = word; } @@ -48,26 +49,28 @@ void ReplacementVariableItem::execute(Document *document, const Range &word) Range removeRange(m_position.start(), removeUntil); if ( document->text(m_position).lastIndexOf('{') != -1 ) { // remove the whole existing expression - removeRange.end().setColumn(m_position.end().column()); + removeRange.setEnd({removeRange.end().line(), m_position.end().column()}); } else { // remove nothing unless there is an opening { already, in that case remove that - removeRange.start() = m_position.end(); - removeRange.end() = m_position.end(); + removeRange= {m_position.end(), m_position.end()}; - Range previousCharacter(word.start(), word.start()); - previousCharacter.start().setColumn(word.start().column() - 1); + Range previousCharacter(word.start() - Cursor(0, 1), word.start()); if ( document->text(previousCharacter) == "{" ) { - removeRange.start().setColumn(removeRange.start().column() - 1); + removeRange.setStart(removeRange.start() - Cursor(0, 1)); } } if ( m_hasEditableFields ) { - TemplateInterface2 *templateInterface = qobject_cast(document->activeView()); - if ( templateInterface ) { + qWarning() << "template interface not supported by editor"; +#if 0 + TODO: re-enable once the template interface exists again + auto iface = qobject_cast(ICore::self()->partController()->activeView()); + if ( iface ) { document->removeText(removeRange); - templateInterface->insertTemplateText(removeRange.start(), m_variable.toString(), QMap(), NULL); + iface->insertTemplateText(removeRange.start(), m_variable.toString(), QMap(), NULL); } +#endif } else { document->removeText(removeRange); diff --git a/codecompletion/items/replacementvariable.h b/codecompletion/items/replacementvariable.h index ab4f1181..5f22cb69 100644 --- a/codecompletion/items/replacementvariable.h +++ b/codecompletion/items/replacementvariable.h @@ -31,7 +31,7 @@ class ReplacementVariableItem : public CompletionTreeItem { public: ReplacementVariableItem(const ReplacementVariable &variable, const QString &description, bool hasEditableFields, KTextEditor::Range position = KTextEditor::Range::invalid()); - virtual void execute(KTextEditor::Document* document, const KTextEditor::Range& word); + virtual void execute(KTextEditor::View* view, const KTextEditor::Range& word) override; virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const; private: diff --git a/codecompletion/model.cpp b/codecompletion/model.cpp index 07a29521..ad3e76e3 100644 --- a/codecompletion/model.cpp +++ b/codecompletion/model.cpp @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2010-2011 Sven Brauch * + * Copyright (c) 2010-2014 Sven Brauch * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -20,6 +20,10 @@ #include #include +#include + +#include +#include "codecompletiondebug.h" #include "context.h" #include "worker.h" @@ -65,27 +69,23 @@ bool PythonCodeCompletionModel::shouldAbortCompletion(KTextEditor::View* view, c { const QString text = view->document()->text(range); if ( completionContext() ) { - KSharedPtr context = KSharedPtr::staticCast( - completionContext() - ); + auto context = static_cast(completionContext().data()); if ( context->completionContextType() == PythonCodeCompletionContext::StringFormattingCompletion ) { if ( text.endsWith('"') || text.endsWith("'") || text.endsWith(' ') ) { return true; } } } - return KTextEditor::CodeCompletionModelControllerInterface3::shouldAbortCompletion(view, range, currentCompletion); + return KTextEditor::CodeCompletionModelControllerInterface::shouldAbortCompletion(view, range, currentCompletion); } QString PythonCodeCompletionModel::filterString(KTextEditor::View *view, const KTextEditor::Range &range, const KTextEditor::Cursor &position) { // TODO The completion context may be null, so we need to check it first. This might a bug. if ( completionContext() ) { - KSharedPtr context = KSharedPtr::staticCast( - completionContext() - ); + auto context = static_cast(completionContext().data()); if (context->completionContextType() == PythonCodeCompletionContext::StringFormattingCompletion) { - return QString(); + return QString(); } } return CodeCompletionModel::filterString(view, range, position); @@ -94,8 +94,7 @@ QString PythonCodeCompletionModel::filterString(KTextEditor::View *view, const K KTextEditor::Range PythonCodeCompletionModel::completionRange(KTextEditor::View* view, const KTextEditor::Cursor& position) { m_currentDocument = view->document()->url(); - kWarning() << "Current document: " << m_currentDocument; - return KTextEditor::CodeCompletionModelControllerInterface3::completionRange(view, position); + return KTextEditor::CodeCompletionModelControllerInterface::completionRange(view, position); } KDevelop::CodeCompletionWorker* PythonCodeCompletionModel::createCompletionWorker() diff --git a/codecompletion/model.h b/codecompletion/model.h index 85335f2d..7d36139e 100644 --- a/codecompletion/model.h +++ b/codecompletion/model.h @@ -22,7 +22,6 @@ #include #include -#include namespace Python { @@ -41,7 +40,7 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionModel : public KDevelop::C virtual bool shouldAbortCompletion(KTextEditor::View* view, const KTextEditor::Range& range, const QString& currentCompletion); QString filterString(KTextEditor::View *view, const KTextEditor::Range &range, const KTextEditor::Cursor &position); - KUrl m_currentDocument; + QUrl m_currentDocument; }; } diff --git a/codecompletion/pythoncompletionexport.h b/codecompletion/pythoncompletionexport.h deleted file mode 100644 index f607003c..00000000 --- a/codecompletion/pythoncompletionexport.h +++ /dev/null @@ -1,34 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2012 Sven Brauch * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License as * - * published by the Free Software Foundation; either version 2 of * - * the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************** - */ - -#ifndef PYTHONCOMPLETIONEXPORT_H -#define PYTHONCOMPLETIONEXPORT_H - -/* needed for KDE_EXPORT macros */ -#include - - -#ifndef KDEVPYTHONCOMPLETION_EXPORT -# ifdef MAKE_KDEV4PYTHONCOMPLETION_LIB -# define KDEVPYTHONCOMPLETION_EXPORT KDE_EXPORT -# else -# define KDEVPYTHONCOMPLETION_EXPORT KDE_IMPORT -# endif -#endif - -#endif \ No newline at end of file diff --git a/codecompletion/tests/CMakeLists.txt b/codecompletion/tests/CMakeLists.txt index c7416d7c..fcbe7ae3 100644 --- a/codecompletion/tests/CMakeLists.txt +++ b/codecompletion/tests/CMakeLists.txt @@ -1,10 +1,15 @@ -kde4_add_unit_test(pycompletiontest pycompletiontest.cpp) +set(pycompletiontest_SRCS + pycompletiontest.cpp + ../codecompletiondebug.cpp) -target_link_libraries(pycompletiontest - kdev4pythonduchain - kdev4pythoncompletion - kdev4pythonparser - ${kdev4pythonparser_LIBRARIES} - ${QT_QTTEST_LIBRARY} - ${KDEVPLATFORM_TESTS_LIBRARIES} +ecm_add_test(${pycompletiontest_SRCS} + TEST_NAME pycompletiontest + LINK_LIBRARIES + kdevpythonduchain + kdevpythoncompletion + kdevpythonparser + ${kdevpythonparser_LIBRARIES} + Qt5::Test + KDev::Tests + KF5::KDELibs4Support ) diff --git a/codecompletion/tests/pycompletiontest.cpp b/codecompletion/tests/pycompletiontest.cpp index eed29d17..75dcbbea 100644 --- a/codecompletion/tests/pycompletiontest.cpp +++ b/codecompletion/tests/pycompletiontest.cpp @@ -28,14 +28,16 @@ #include #include -#include -#include #include #include #include "codecompletion/context.h" #include "codecompletion/helpers.h" +#include +#include +#include "codecompletiondebug.h" + using namespace KDevelop; QTEST_MAIN(Python::PyCompletionTest) @@ -45,7 +47,6 @@ Q_DECLARE_METATYPE(KTextEditor::Range) static int testId = 0; static QString basepath = "/tmp/__kdevpythoncompletiontest.dir/"; -static QFSFileEngine fileEngine; namespace Python { @@ -76,9 +77,8 @@ void makefile(QString filename, QString contents) { fileptr.open(QIODevice::WriteOnly); fileptr.write(contents.toAscii()); fileptr.close(); - KUrl url = KUrl(basepath + filename); - url.cleanPath(); - kDebug() << "updating duchain for " << url.url() << basepath; + auto url = QUrl::fromLocalFile(QDir::cleanPath(basepath + filename)); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "updating duchain for " << url.url() << basepath; const IndexedString urlstring(url); DUChain::self()->updateContextForUrl(urlstring, KDevelop::TopDUContext::ForceUpdate); ICore::self()->languageController()->backgroundParser()->parseDocuments(); @@ -90,11 +90,12 @@ void PyCompletionTest::initShell() AutoTestShell::init(); TestCore* core = new TestCore(); core->initialize(KDevelop::Core::NoUi); - fileEngine.mkdir(basepath, false); - - KUrl doc_url = KUrl(KStandardDirs::locate("data", "kdevpythonsupport/documentation_files/builtindocumentation.py")); - doc_url.cleanPath(KUrl::SimplifyDirSeparators); + QDir d; + d.mkpath(basepath); + auto doc_url = QDir::cleanPath(QStandardPaths::locate(QStandardPaths::GenericDataLocation, + "kdevpythonsupport/documentation_files/builtindocumentation.py")); + DUChain::self()->updateContextForUrl(IndexedString(doc_url), KDevelop::TopDUContext::AllDeclarationsContextsAndUses); ICore::self()->languageController()->backgroundParser()->parseDocuments(); DUChain::self()->waitForUpdate(IndexedString(doc_url), KDevelop::TopDUContext::AllDeclarationsContextsAndUses); @@ -103,8 +104,8 @@ void PyCompletionTest::initShell() KDevelop::CodeRepresentation::setDiskChangesForbidden(true); // now, create a nice little completion hierarchy - fileEngine.mkdir(basepath + "submoduledir", false); - fileEngine.mkdir(basepath + "submoduledir/anothersubdir", false); + d.mkpath(basepath + "submoduledir"); + d.mkpath(basepath + "submoduledir/anothersubdir"); makefile("toplevelmodule.py", "some_var = 3\ndef some_function(): pass\nclass some_class():\n def method(): pass"); makefile("submoduledir/__init__.py", "var_in_sub_init = 5"); makefile("submoduledir/subfile.py", "var_in_subfile = 5\nclass some_subfile_class():\n def method2(): pass"); @@ -467,8 +468,9 @@ void PyCompletionTest::testAutoBrackets() KService::Ptr documentService = KService::serviceByDesktopPath("katepart.desktop"); QVERIFY(documentService); KTextEditor::Document* document = documentService->createInstance(this); + auto view = document->createView(nullptr); QVERIFY(document); - item->execute(document, KTextEditor::Range(0, 0, 0, 0)); + item->execute(view, KTextEditor::Range(0, 0, 0, 0)); QCOMPARE(document->text(), QLatin1String("myprop")); } @@ -543,8 +545,10 @@ void PyCompletionTest::testFunctionDeclarationCompletion() KTextEditor::Document* document = documentService->createInstance(this); QVERIFY(document); document->setText(documentCode); + + auto view = document->createView(nullptr); - completionItems.first()->execute(document, executeRange); + completionItems.first()->execute(view, executeRange); QCOMPARE(document->text(), expectedCode); } @@ -567,7 +571,7 @@ void PyCompletionTest::testFunctionDeclarationCompletion_data() QTest::newRow("class_name_no_constructor_parens") << "class Foo:\n pass\nbar = %INVOKE" << "Foo%CURSOR" << KTextEditor::Range(2, 6, 2, 9) << "Foo()"; - QTest::newRow("class_name_explicit_constructor_parens") << "class Foo:\n def __init__(self):\n pass\nbar = %INVOKE" << "Foo%CURSOR" + QTest::newRow("class_name_explicit_constructor_parens") << "class Foo:\n def __init__(self):\n pass\nbar = %INVOKE" << "Fo%CURSOR" << KTextEditor::Range(3, 6, 3, 9) << "Foo()"; } diff --git a/codecompletion/worker.cpp b/codecompletion/worker.cpp index 8aa73b57..7994f8be 100644 --- a/codecompletion/worker.cpp +++ b/codecompletion/worker.cpp @@ -24,9 +24,12 @@ #include "codehelpers.h" #include +#include +#include "codecompletiondebug.h" + namespace Python { -PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel *parent, KUrl /*document*/) +PythonCodeCompletionWorker::PythonCodeCompletionWorker(PythonCodeCompletionModel *parent, const QUrl& /*document*/) : KDevelop::CodeCompletionWorker(parent), parent(parent) { @@ -48,8 +51,8 @@ KDevelop::CodeCompletionContext* PythonCodeCompletionWorker::createCompletionCon void PythonCodeCompletionWorker::updateContextRange(KTextEditor::Range &contextRange, KTextEditor::View *view, KDevelop::DUContextPointer context) const { if ( CodeHelpers::endsInside(view->document()->text(contextRange)) == CodeHelpers::String ) { - kDebug() << "we're dealing with string completion. extend the range"; - contextRange = context->rangeInCurrentRevision().textRange(); + qCDebug(KDEV_PYTHON_CODECOMPLETION) << "we're dealing with string completion. extend the range"; + contextRange = context->rangeInCurrentRevision(); } } diff --git a/codecompletion/worker.h b/codecompletion/worker.h index f3aa8958..4fcd5925 100644 --- a/codecompletion/worker.h +++ b/codecompletion/worker.h @@ -30,7 +30,7 @@ class KDEVPYTHONCOMPLETION_EXPORT PythonCodeCompletionWorker : public KDevelop:: { public: - PythonCodeCompletionWorker(PythonCodeCompletionModel *parent, KUrl document); + PythonCodeCompletionWorker(PythonCodeCompletionModel *parent, const QUrl& document); virtual KDevelop::CodeCompletionContext* createCompletionContext(KDevelop::DUContextPointer context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const; virtual void updateContextRange(KTextEditor::Range &contextRange, KTextEditor::View *view, KDevelop::DUContextPointer context) const; PythonCodeCompletionModel* parent; diff --git a/codegen/codegendebug.cpp b/codegen/codegendebug.cpp new file mode 100644 index 00000000..67f6334b --- /dev/null +++ b/codegen/codegendebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "codegendebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON_CODEGEN, "kdev.python.codegen") + + diff --git a/codegen/codegendebug.h b/codegen/codegendebug.h new file mode 100644 index 00000000..41bd55ef --- /dev/null +++ b/codegen/codegendebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CODEGENDEBUG_H +#define CODEGENDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON_CODEGEN) + +#endif + diff --git a/codegen/correctionfilegenerator.cpp b/codegen/correctionfilegenerator.cpp index 0a980a91..981846db 100644 --- a/codegen/correctionfilegenerator.cpp +++ b/codegen/correctionfilegenerator.cpp @@ -21,7 +21,6 @@ #include "correctionfilegenerator.h" #include -#include #include #include @@ -38,6 +37,9 @@ #include "duchain/helpers.h" #include "parser/codehelpers.h" +#include +#include "codegendebug.h" + using namespace KDevelop; namespace Python { @@ -67,7 +69,7 @@ void TypeCorrection::doContextMenu(ContextMenuExtension &extension, Context *con && declaration->abstractType()->whichType() == AbstractType::TypeFunction)) ) { QAction* action = new QAction(i18n("Specify type for \"%1\"...", declaration->qualifiedIdentifier().toString()), 0); action->setData(QVariant::fromValue(IndexedDeclaration(declaration))); - action->setIcon(KIcon("code-class")); + action->setIcon(QIcon::fromTheme("code-class")); connect(action, SIGNAL(triggered(bool)), this, SLOT(executeSpecifyTypeAction())); extension.addAction(ContextMenuExtension::ExtensionGroup, action); @@ -79,7 +81,7 @@ void TypeCorrection::executeSpecifyTypeAction() { QAction* action = qobject_cast(sender()); if ( ! action ) { - kWarning() << "slot not invoked by triggering a QAction, should not happen"; // :) + qCWarning(KDEV_PYTHON_CODEGEN) << "slot not invoked by triggering a QAction, should not happen"; // :) return; } @@ -90,7 +92,7 @@ void TypeCorrection::executeSpecifyTypeAction() } if ( ! decl.isValid() ) { - kWarning() << "No declaration found!"; + qCWarning(KDEV_PYTHON_CODEGEN) << "No declaration found!"; return; } @@ -102,7 +104,7 @@ void TypeCorrection::executeSpecifyTypeAction() hintType = CorrectionFileGenerator::LocalVariableHint; } else { - kWarning() << "Correction requested for something that's not a local variable or function."; + qCWarning(KDEV_PYTHON_CODEGEN) << "Correction requested for something that's not a local variable or function."; return; } @@ -133,7 +135,7 @@ void TypeCorrection::accepted() CorrectionAssistant *dialog = qobject_cast(sender()); Q_ASSERT(dialog); if ( ! dialog ) { - kWarning() << "accepted() called without a sender"; + qCWarning(KDEV_PYTHON_CODEGEN) << "accepted() called without a sender"; return; } @@ -147,11 +149,11 @@ void TypeCorrection::accepted() } if ( ! decl.isValid() ) { - kWarning() << "No declaration found!"; + qCWarning(KDEV_PYTHON_CODEGEN) << "No declaration found!"; return; } - KUrl correctionFile = Helper::getLocalCorrectionFile(decl.data()->topContext()->url().toUrl()); + auto correctionFile = Helper::getLocalCorrectionFile(decl.data()->topContext()->url().toUrl()); if ( correctionFile.isEmpty() ) { KMessageBox::error(0, i18n("Sorry, cannot create hints for files which are not part of a project.")); return; @@ -162,7 +164,7 @@ void TypeCorrection::accepted() generator.addHint(m_ui->typeText->text(), m_ui->importsText->text().split(',', QString::SkipEmptyParts), decl.data(), hintType); - kDebug() << "Forcing a reparse on " << decl.data()->topContext()->url(); + qCDebug(KDEV_PYTHON_CODEGEN) << "Forcing a reparse on " << decl.data()->topContext()->url(); ICore::self()->languageController()->backgroundParser()->addDocument(IndexedString(decl.data()->topContext()->url()), TopDUContext::ForceUpdate); ICore::self()->languageController()->backgroundParser()->addDocument(IndexedString(correctionFile), @@ -173,11 +175,11 @@ CorrectionFileGenerator::CorrectionFileGenerator(const QString &filePath) : m_file(filePath) { Q_ASSERT(! filePath.isEmpty()); - kDebug() << "Correction file path: " << filePath; + qCDebug(KDEV_PYTHON_CODEGEN) << "Correction file path: " << filePath; QFileInfo info(m_file); if ( ! info.absoluteDir().exists() ) { - kDebug() << "Directory does not exist. Creating..."; + qCDebug(KDEV_PYTHON_CODEGEN) << "Directory does not exist. Creating..."; info.absoluteDir().mkpath(info.absolutePath()); } @@ -192,7 +194,7 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList CorrectionFileGenerator::HintType hintType) { if ( ! forDeclaration || ! forDeclaration->context() ) { - kWarning() << "Declaration does not have context!" << (forDeclaration ? forDeclaration->toString() : ""); + qCWarning(KDEV_PYTHON_CODEGEN) << "Declaration does not have context!" << (forDeclaration ? forDeclaration->toString() : ""); return; } @@ -216,8 +218,8 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList bool inFunction = context->type() == DUContext::Function || (context->owner() && context->owner()->abstractType()->whichType() == AbstractType::TypeFunction); - kDebug() << "Are we in a class: " << inClass; - kDebug() << "Are we in a function: " << inFunction; + qCDebug(KDEV_PYTHON_CODEGEN) << "Are we in a class: " << inClass; + qCDebug(KDEV_PYTHON_CODEGEN) << "Are we in a function: " << inFunction; QString enclosingClassIdentifier, enclosingFunctionIdentifier; @@ -236,8 +238,8 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList } } - kDebug() << "Enclosing class: " << enclosingClassIdentifier; - kDebug() << "Enclosing function: " << enclosingFunctionIdentifier; + qCDebug(KDEV_PYTHON_CODEGEN) << "Enclosing class: " << enclosingClassIdentifier; + qCDebug(KDEV_PYTHON_CODEGEN) << "Enclosing function: " << enclosingFunctionIdentifier; QString declarationIdentifier = forDeclaration->identifier().identifier().str(); @@ -269,9 +271,9 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList foundClassDeclaration = true; } - kDebug() << "Found class declaration: " << foundClassDeclaration << enclosingClassIdentifier; - kDebug() << "Found function declaration: " << foundFunctionDeclaration << functionIdentifier; - kDebug() << "Line: " << line; + qCDebug(KDEV_PYTHON_CODEGEN) << "Found class declaration: " << foundClassDeclaration << enclosingClassIdentifier; + qCDebug(KDEV_PYTHON_CODEGEN) << "Found function declaration: " << foundFunctionDeclaration << functionIdentifier; + qCDebug(KDEV_PYTHON_CODEGEN) << "Line: " << line; int indentsForNextStatement = m_fileIndents->indentForLine(line); @@ -322,7 +324,7 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList else if ( hintType == LocalVariableHint ) { hintCode = "l_" + declarationIdentifier + " = " + typeCode; } - kDebug() << "Hint code: " << hintCode; + qCDebug(KDEV_PYTHON_CODEGEN) << "Hint code: " << hintCode; hintCode.prepend(QString(indentsForNextStatement, ' ')); newCode.append(hintCode); @@ -351,8 +353,8 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList QTemporaryFile temp; if ( checkForValidSyntax() && temp.open() ) { - kDebug() << "File path: " << m_file.fileName(); - kDebug() << "Temporary file path: " << temp.fileName(); + qCDebug(KDEV_PYTHON_CODEGEN) << "File path: " << m_file.fileName(); + qCDebug(KDEV_PYTHON_CODEGEN) << "Temporary file path: " << temp.fileName(); QTextStream stream(&temp); stream << m_code.join("\n"); m_fileIndents.reset(new FileIndentInformation(m_code)); @@ -362,7 +364,7 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList success = success ? QFile::rename(temp.fileName(), m_file.fileName()) : false; if ( success && m_file.open(QFile::ReadWrite) ) { - kDebug() << "Successfully saved correction file."; + qCDebug(KDEV_PYTHON_CODEGEN) << "Successfully saved correction file."; m_oldContents = m_code; } @@ -371,7 +373,7 @@ void CorrectionFileGenerator::addHint(const QString &typeCode, const QStringList } } else { - kDebug() << "Something went wrong, reverting changes to correction file"; + qCDebug(KDEV_PYTHON_CODEGEN) << "Something went wrong, reverting changes to correction file"; m_code = m_oldContents; } } diff --git a/codegen/refactoring.cpp b/codegen/refactoring.cpp index 7ab341cf..c2345b5c 100644 --- a/codegen/refactoring.cpp +++ b/codegen/refactoring.cpp @@ -23,6 +23,8 @@ #include "refactoring.h" #include "duchain/helpers.h" +#include +#include "codegendebug.h" namespace Python { @@ -47,7 +49,7 @@ Refactoring::Refactoring(QObject *parent) bool Refactoring::acceptForContextMenu(const KDevelop::Declaration* decl) { if (decl->topContext() == Helper::getDocumentationFileContext()) { - kDebug() << "in doc file, not offering rename action"; + qCDebug(KDEV_PYTHON_CODEGEN) << "in doc file, not offering rename action"; return false; } return true; diff --git a/debugger/CMakeLists.txt b/debugger/CMakeLists.txt index df2b2dc2..9b84a923 100644 --- a/debugger/CMakeLists.txt +++ b/debugger/CMakeLists.txt @@ -18,20 +18,20 @@ set(kdevpdb_PART_SRCS debugjob.cpp debugsession.cpp pdbdebuggerplugin.cpp + debuggerdebug.cpp ) -kde4_add_plugin(kdevpdb ${kdevpdb_PART_SRCS}) +add_library(kdevpdb MODULE ${kdevpdb_PART_SRCS}) target_link_libraries(kdevpdb - sublime - kdev4pythonparser - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDEVPLATFORM_DEBUGGER_LIBRARIES} - ${KDEVPLATFORM_OUTPUTVIEW_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDE4_KDEUI_LIBS} - ${KDEVPLATFORM_UTIL_LIBRARIES} - ${KDE4_KTEXTEDITOR_LIBS} + kdevpythonparser + KDev::Interfaces + KDev::Language + KDev::Debugger + KDev::OutputView + KDev::Project + KDev::Util + KF5::TextEditor + KF5::KDELibs4Support ${KDE4WORKSPACE_PROCESSUI_LIBS} ) diff --git a/debugger/__kdevpython_debugger_utils.py b/debugger/__kdevpython_debugger_utils.py index 04917a39..1c538fc7 100644 --- a/debugger/__kdevpython_debugger_utils.py +++ b/debugger/__kdevpython_debugger_utils.py @@ -1,5 +1,8 @@ # This file is imported from within the debugger +# Copyright 2014 Sven Brauch +# License: GPL v2+ + from kdevpdb import kdevOutputFormatter __kdevpython_builtin_locals = locals diff --git a/debugger/breakpointcontroller.cpp b/debugger/breakpointcontroller.cpp index 05f3e5b9..580e0508 100644 --- a/debugger/breakpointcontroller.cpp +++ b/debugger/breakpointcontroller.cpp @@ -20,11 +20,14 @@ #include "breakpointcontroller.h" #include +#include +#include "debuggerdebug.h" + namespace Python { BreakpointController::BreakpointController(IDebugSession* parent): IBreakpointController(parent) { - kDebug() << "constructing breakpoint controller"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "constructing breakpoint controller"; connect(debugSession(), SIGNAL(event(IDebugSession::event_t)), this, SLOT(slotEvent(IDebugSession::event_t))); } @@ -35,7 +38,7 @@ DebugSession* BreakpointController::session() void BreakpointController::slotEvent(IDebugSession::event_t evt) { - kDebug() << evt; + qCDebug(KDEV_PYTHON_DEBUGGER) << evt; if ( evt == IDebugSession::connected_to_program ) { foreach ( Breakpoint* bp, breakpointModel()->breakpoints() ) { if ( bp->deleted() ) { @@ -48,7 +51,7 @@ void BreakpointController::slotEvent(IDebugSession::event_t evt) void BreakpointController::sendMaybe(KDevelop::Breakpoint* breakpoint) { - kDebug() << "sending breakpoint: " << breakpoint << "( deleted:" << breakpoint->deleted() << ")"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "sending breakpoint: " << breakpoint << "( deleted:" << breakpoint->deleted() << ")"; if ( breakpoint->deleted() ) { session()->removeBreakpoint(breakpoint); } @@ -59,4 +62,4 @@ void BreakpointController::sendMaybe(KDevelop::Breakpoint* breakpoint) } -#include "breakpointcontroller.moc" \ No newline at end of file +#include "breakpointcontroller.moc" diff --git a/debugger/debuggerdebug.cpp b/debugger/debuggerdebug.cpp new file mode 100644 index 00000000..057f1895 --- /dev/null +++ b/debugger/debuggerdebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "debuggerdebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON_DEBUGGER, "kdev.python.debugger") + + diff --git a/debugger/debuggerdebug.h b/debugger/debuggerdebug.h new file mode 100644 index 00000000..fc0318e5 --- /dev/null +++ b/debugger/debuggerdebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DEBUGGERDEBUG_H +#define DEBUGGERDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON_DEBUGGER) + +#endif + diff --git a/debugger/debugjob.cpp b/debugger/debugjob.cpp index 0d581e24..aa2bba25 100644 --- a/debugger/debugjob.cpp +++ b/debugger/debugjob.cpp @@ -18,8 +18,7 @@ #include "debugjob.h" -#include -#include + #include #include @@ -28,14 +27,18 @@ #include #include +#include +#include +#include "debuggerdebug.h" + namespace Python { void DebugJob::start() { QStringList program; - QString debuggerUrl = KStandardDirs::locate("data", "kdevpythonsupport/debugger/") + "/kdevpdb.py"; - program << m_interpreter << "-u" << debuggerUrl << m_scriptUrl.path(KUrl::RemoveTrailingSlash) << m_args; + QString debuggerUrl = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevpythonsupport/debugger", QStandardPaths::LocateDirectory) + "/kdevpdb.py"; + program << m_interpreter << "-u" << debuggerUrl << m_scriptUrl.url(QUrl::StripTrailingSlash) << m_args; m_session = new DebugSession(program, m_workingDirectory); setStandardToolView(KDevelop::IOutputView::DebugView); @@ -49,13 +52,13 @@ void DebugJob::start() startOutput(); - kDebug() << "connecting standardOutputReceived"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "connecting standardOutputReceived"; connect(m_session, SIGNAL(realDataReceived(QStringList)), this, SLOT(standardOutputReceived(QStringList))); connect(m_session, SIGNAL(stderrReceived(QStringList)), this, SLOT(standardErrorReceived(QStringList))); connect(m_session, SIGNAL(finished()), this, SLOT(sessionFinished())); KDevelop::ICore::self()->debugController()->addSession(m_session); m_session->start(); - kDebug() << "starting program:" << program; + qCDebug(KDEV_PYTHON_DEBUGGER) << "starting program:" << program; } void DebugJob::sessionFinished() @@ -72,7 +75,7 @@ void DebugJob::standardErrorReceived(QStringList lines) void DebugJob::standardOutputReceived(QStringList lines) { - kDebug() << "standard output received:" << lines << outputModel(); + qCDebug(KDEV_PYTHON_DEBUGGER) << "standard output received:" << lines << outputModel(); if ( OutputModel* m = outputModel() ) { m->appendLines(lines); } @@ -85,7 +88,7 @@ OutputModel* DebugJob::outputModel() bool DebugJob::doKill() { - kDebug() << "kill signal received"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "kill signal received"; m_session->stopDebugger(); return true; } diff --git a/debugger/debugjob.h b/debugger/debugjob.h index 1cf4e202..e73339bb 100644 --- a/debugger/debugjob.h +++ b/debugger/debugjob.h @@ -23,7 +23,6 @@ #include #include #include "debugsession.h" -#include namespace Python { @@ -42,10 +41,10 @@ Q_OBJECT virtual void start(); virtual bool doKill(); - KUrl m_scriptUrl; + QUrl m_scriptUrl; QString m_interpreter; QStringList m_args; - KUrl m_workingDirectory; + QUrl m_workingDirectory; private slots: void standardOutputReceived(QStringList lines); diff --git a/debugger/debugsession.cpp b/debugger/debugsession.cpp index 68eb2d70..44d85eac 100644 --- a/debugger/debugsession.cpp +++ b/debugger/debugsession.cpp @@ -19,8 +19,7 @@ #include #include -#include -#include + #include #include @@ -34,6 +33,10 @@ #include "variable.h" #include "breakpointcontroller.h" +#include +#include +#include "debuggerdebug.h" + using namespace KDevelop; static QByteArray debuggerPrompt = "__KDEVPYTHON_DEBUGGER_PROMPT"; @@ -42,29 +45,37 @@ static QByteArray debuggerOutputEnd = "<<<__KDEVPYTHON_END___DEBUGGER_OUTPUT"; namespace Python { -KDevelop::IFrameStackModel* DebugSession::createFrameStackModel() -{ - return new PdbFrameStackModel(this); -} - -DebugSession::DebugSession(QStringList program, const KUrl &workingDirectory) : +DebugSession::DebugSession(QStringList program, const QUrl &workingDirectory) : IDebugSession() + , m_breakpointController(nullptr) + , m_variableController(nullptr) + , m_frameStackModel(nullptr) , m_workingDirectory(workingDirectory) , m_nextNotifyMethod(0) , m_inDebuggerData(0) { - kDebug() << "creating debug session"; - m_variableController = new Python::VariableController(this); - m_breakpointController = new Python::BreakpointController(this); + qCDebug(KDEV_PYTHON_DEBUGGER) << "creating debug session"; m_program = program; + m_breakpointController = new Python::BreakpointController(this); m_variableController = new VariableController(this); + m_frameStackModel = new PdbFrameStackModel(this); } -IVariableController* DebugSession::variableController() +IBreakpointController* DebugSession::breakpointController() const +{ + return m_breakpointController; +} + +IVariableController* DebugSession::variableController() const { return m_variableController; } +IFrameStackModel* DebugSession::frameStackModel() const +{ + return m_frameStackModel; +} + void DebugSession::start() { setState(StartingState); @@ -80,7 +91,7 @@ void DebugSession::start() m_debuggerProcess->start(); m_debuggerProcess->waitForStarted(); InternalPdbCommand* path = new InternalPdbCommand(0, 0, - "import sys; sys.path.append('"+KStandardDirs::locate("data", "kdevpythonsupport/debugger/")+"')\n"); + "import sys; sys.path.append('"+QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevpythonsupport/debugger/")+"')\n"); InternalPdbCommand* cmd = new InternalPdbCommand(0, 0, "import __kdevpython_debugger_utils\n"); addCommand(path); addCommand(cmd); @@ -107,7 +118,7 @@ QStringList byteArrayToStringList(const QByteArray& r) { void DebugSession::dataAvailable() { QByteArray data = m_debuggerProcess->readAllStandardOutput(); - kDebug() << data.length() << "bytes of data available"; + qCDebug(KDEV_PYTHON_DEBUGGER) << data.length() << "bytes of data available"; // remove pointless state changes data.replace(debuggerOutputBegin+debuggerOutputEnd, ""); @@ -131,7 +142,7 @@ void DebugSession::dataAvailable() nextChangeAt = atLastChange ? len : qMin(nextChangeAt, len); - kDebug() << data; + qCDebug(KDEV_PYTHON_DEBUGGER) << data; Q_ASSERT(m_inDebuggerData == 0 || m_inDebuggerData == 1); if ( m_inDebuggerData == 1 ) { @@ -181,7 +192,7 @@ void DebugSession::dataAvailable() else { notifyNext(); if ( m_commandQueue.isEmpty() ) { - kDebug() << "Changing state to PausedState"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "Changing state to PausedState"; setState(PausedState); } } @@ -197,7 +208,7 @@ void DebugSession::dataAvailable() void DebugSession::setNotifyNext(QWeakPointer object, const char* method) { - kDebug() << "set notify next:" << object << method; + qCDebug(KDEV_PYTHON_DEBUGGER) << "set notify next:" << object << method; m_nextNotifyObject = object; m_nextNotifyMethod = method; } @@ -205,12 +216,12 @@ void DebugSession::setNotifyNext(QWeakPointer object, const char* metho void DebugSession::notifyNext() { QSharedPointer lock = m_nextNotifyObject.toStrongRef(); - kDebug() << "notify next:" << m_nextNotifyObject << m_nextNotifyObject.data() << this; - if ( m_nextNotifyMethod and m_nextNotifyObject ) { + qCDebug(KDEV_PYTHON_DEBUGGER) << "notify next:" << m_nextNotifyObject << m_nextNotifyObject.data() << this; + if ( m_nextNotifyMethod && m_nextNotifyObject ) { QMetaObject::invokeMethod(m_nextNotifyObject.data(), m_nextNotifyMethod, Qt::DirectConnection, Q_ARG(QByteArray, m_buffer)); } else { - kDebug() << "notify called, but nothing to notify!"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "notify called, but nothing to notify!"; } m_buffer.clear(); m_nextNotifyMethod = 0; @@ -219,9 +230,9 @@ void DebugSession::notifyNext() void DebugSession::processNextCommand() { - kDebug() << "processing next debugger command in queue"; - if ( m_processBusy or m_state == EndedState ) { - kDebug() << "process is busy or ended, aborting"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "processing next debugger command in queue"; + if ( m_processBusy || m_state == EndedState ) { + qCDebug(KDEV_PYTHON_DEBUGGER) << "process is busy or ended, aborting"; return; } m_processBusy = true; @@ -233,7 +244,7 @@ void DebugSession::processNextCommand() m_commandQueue.removeFirst(); setNotifyNext(cmd->notifyObject(), cmd->notifyMethod()); cmd->run(this); - kDebug() << "command executed, deleting it."; + qCDebug(KDEV_PYTHON_DEBUGGER) << "command executed, deleting it."; delete cmd; if ( ! m_commandQueue.isEmpty() ) { processNextCommand(); @@ -242,7 +253,7 @@ void DebugSession::processNextCommand() void DebugSession::setState(DebuggerState state) { - kDebug() << "Setting state to" << state; + qCDebug(KDEV_PYTHON_DEBUGGER) << "Setting state to" << state; if ( state == m_state ) { return; @@ -262,14 +273,14 @@ void DebugSession::setState(DebuggerState state) } } - kDebug() << "debugger state changed to" << m_state; + qCDebug(KDEV_PYTHON_DEBUGGER) << "debugger state changed to" << m_state; raiseEvent(program_state_changed); emit stateChanged(m_state); } void DebugSession::write(const QByteArray& cmd) { - kDebug() << " >>> WRITE:" << cmd; + qCDebug(KDEV_PYTHON_DEBUGGER) << " >>> WRITE:" << cmd; m_debuggerProcess->write(cmd); } @@ -342,7 +353,7 @@ void DebugSession::addCommand(PdbCommand* cmd) if ( m_state == EndedState || m_state == StoppingState ) { return; } - kDebug() << " +++ adding command to queue:" << cmd; + qCDebug(KDEV_PYTHON_DEBUGGER) << " +++ adding command to queue:" << cmd; m_commandQueue.append(cmd); if ( cmd->type() == PdbCommand::UserType ) { // this is queued and will run after the command is executed. @@ -353,7 +364,7 @@ void DebugSession::addCommand(PdbCommand* cmd) void DebugSession::checkCommandQueue() { - kDebug() << "items in queue:" << m_commandQueue.length(); + qCDebug(KDEV_PYTHON_DEBUGGER) << "items in queue:" << m_commandQueue.length(); if ( m_commandQueue.isEmpty() ) { return; } @@ -386,7 +397,7 @@ void DebugSession::runImmediately(const QString& cmd) if ( state() == ActiveState ) { m_nextNotifyMethod = 0; m_nextNotifyObject.clear(); // TODO is this correct? - kDebug() << "interrupting debugger"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "interrupting debugger"; kill(m_debuggerProcess->pid(), SIGINT); write(cmd.toAscii()); write("continue\n"); @@ -400,20 +411,20 @@ void DebugSession::runImmediately(const QString& cmd) void DebugSession::addBreakpoint(Breakpoint* bp) { QString location = bp->url().path() + ":" + QString::number(bp->line() + 1); - kDebug() << "adding breakpoint" << location; + qCDebug(KDEV_PYTHON_DEBUGGER) << "adding breakpoint" << location; runImmediately("break " + location + '\n'); } void DebugSession::removeBreakpoint(Breakpoint* bp) { QString location = bp->url().path() + ":" + QString::number(bp->line() + 1); - kDebug() << "deleting breakpoint" << location; + qCDebug(KDEV_PYTHON_DEBUGGER) << "deleting breakpoint" << location; runImmediately("clear " + location + '\n'); } void DebugSession::createVariable(Python::Variable* variable, QObject* callback, const char* callbackMethod) { - kDebug() << "asked to create variable"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "asked to create variable"; InternalPdbCommand* cmd = new InternalPdbCommand(variable, "dataFetched", ("print(" + variable->expression() + ")\n").toAscii()); variable->m_notifyCreated = callback; @@ -428,13 +439,13 @@ void DebugSession::clearOutputBuffer() void DebugSession::updateLocation() { - kDebug() << "updating location"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "updating location"; InternalPdbCommand* cmd = new InternalPdbCommand(this, "locationUpdateReady", "where\n"); addCommand(cmd); } void DebugSession::locationUpdateReady(QByteArray data) { - kDebug() << "Got where information: " << data; + qCDebug(KDEV_PYTHON_DEBUGGER) << "Got where information: " << data; QList lines = data.split('\n'); if ( lines.length() >= 3 ) { lines.removeLast(); // prompt @@ -444,8 +455,8 @@ void DebugSession::locationUpdateReady(QByteArray data) { QRegExp m("^> (/.*\\.py)\\((\\d*)\\).*$"); m.setMinimal(true); m.exactMatch(where); - setCurrentPosition(KUrl(m.capturedTexts().at(1)), m.capturedTexts().at(2).toInt() - 1 , ""); - kDebug() << "New position: " << m.capturedTexts().at(1) << m.capturedTexts().at(2).toInt() - 1 << m.capturedTexts() << where; + setCurrentPosition(QUrl::fromLocalFile(m.capturedTexts().at(1)), m.capturedTexts().at(2).toInt() - 1 , ""); + qCDebug(KDEV_PYTHON_DEBUGGER) << "New position: " << m.capturedTexts().at(1) << m.capturedTexts().at(2).toInt() - 1 << m.capturedTexts() << where; } } @@ -461,7 +472,7 @@ void DebugSession::stopDebugger() m_commandQueue.clear(); m_nextNotifyMethod = 0; m_nextNotifyObject.clear(); - kDebug() << "killed debugger"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "killed debugger"; setState(IDebugSession::EndedState); } diff --git a/debugger/debugsession.h b/debugger/debugsession.h index f45b87f7..8310f805 100644 --- a/debugger/debugsession.h +++ b/debugger/debugsession.h @@ -23,6 +23,9 @@ #include #include +#include +#include "debuggerdebug.h" + #include #include #include @@ -36,13 +39,14 @@ struct PdbCommand; class DebugSession : public KDevelop::IDebugSession { -Q_OBJECT -protected: - virtual KDevelop::IFrameStackModel* createFrameStackModel(); - + Q_OBJECT public: - DebugSession(QStringList program, const KUrl& workingDirectory); + DebugSession(QStringList program, const QUrl& workingDirectory); virtual ~DebugSession(); + + virtual IBreakpointController* breakpointController() const; + virtual IFrameStackModel* frameStackModel() const; + /** * @brief Start the debugger. **/ @@ -101,7 +105,7 @@ Q_OBJECT /** * @brief Access this session's variable controller **/ - virtual IVariableController* variableController(); + virtual IVariableController* variableController() const; /// Those functions just execute the basic debugger commands. They're used when the user /// clicks the appropriate button. @@ -207,12 +211,15 @@ public slots: void stderrReceived(QStringList); private: + IBreakpointController* m_breakpointController; + IVariableController* m_variableController; + IFrameStackModel* m_frameStackModel; KProcess* m_debuggerProcess; IDebugSession::DebuggerState m_state; QByteArray m_buffer; QStringList m_program; QList m_commandQueue; - const KUrl& m_workingDirectory; + const QUrl& m_workingDirectory; private: /// objects to notify next QWeakPointer m_nextNotifyObject; @@ -307,7 +314,7 @@ struct SimplePdbCommand : public PdbCommand { }; void run(DebugSession* session) { Q_ASSERT(m_command.endsWith('\n') && "command must end with a newline"); - kDebug() << "running command:" << m_command.toAscii() << m_notifyMethod; + qCDebug(KDEV_PYTHON_DEBUGGER) << "running command:" << m_command.toAscii() << m_notifyMethod; session->write(m_command.toAscii()); } private: diff --git a/debugger/kdevpdb.desktop b/debugger/kdevpdb.desktop index 4e219e9f..fad4d0ee 100644 --- a/debugger/kdevpdb.desktop +++ b/debugger/kdevpdb.desktop @@ -3,12 +3,14 @@ Encoding=UTF-8 Type=Service Exec=blubb Comment=This plugin provides a frontend for PDB +Comment[ar]=توفّر هذه الملحقة صدرًا لِـ PDB Comment[bs]=Ovaj dodatak daje prikaz za PDB Comment[ca]=Aquest connector proveeix d'un frontal pel PDB Comment[ca@valencia]=Este connector proveeix d'un frontal pel PDB Comment[da]=Dette plugin er en brugerflade til PDB Comment[de]=Dieses Modul stellt eine Oberfläche für PDB zur Verfügung. Comment[el]=Αυτό το πρόσθετο παρέχει ένα περιβάλλον για το PDB +Comment[en_GB]=This plugin provides a frontend for PDB Comment[es]=Este complemento proporciona una interfaz para PDB Comment[et]=PDB kasutajaliidese plugin Comment[fi]=Tämä liitännäinen tarjoaa PDB-käyttöliittymän @@ -18,6 +20,7 @@ Comment[gl]=Este complemento fornece unha interface para PDB. Comment[hu]=Ez a bővítmény egy felületet biztosít a PDB-hez Comment[it]=Questa estensione fornisce un'interfaccia per PDB Comment[kk]=Бұл плагин PDB-ге интерфейс жасайды +Comment[ko]=이 플러그인은 PDB 프론트엔드를 제공합니다 Comment[mr]=हे प्लगइन पीडीबी करिता फ्रंटएन्ड पुरविते Comment[nb]=Dette programtillegget er et forstykke til PDB Comment[nds]=Dit Moduul stellt en Böversiet för PDB praat. @@ -42,6 +45,7 @@ Name[ca@valencia]=kdevpdb Name[da]=kdevpdb Name[de]=kdevpdb Name[el]=kdevpdb +Name[en_GB]=kdevpdb Name[es]=kdevpdb Name[et]=kdevpdb Name[fi]=kdevpdb @@ -51,6 +55,7 @@ Name[gl]=kdevpdb Name[hu]=kdevpdb Name[it]=kdevpdb Name[kk]=kdevpdb +Name[ko]=kdevpdb Name[mr]=के-डेव्ह-पीडीबी Name[nb]=kdevpdb Name[nl]=kdevpdb @@ -68,12 +73,14 @@ Name[x-test]=xxkdevpdbxx Name[zh_CN]=kdevpdb Name[zh_TW]=kdevpdb GenericName=Python Debugger Frontend +GenericName[ar]=صدر منقّح بايثون GenericName[bs]=Prikaz za Python debager GenericName[ca]=Frontal del depurador de Python GenericName[ca@valencia]=Frontal del depurador de Python GenericName[da]=Brugerflade til Python-fejlsøgeren GenericName[de]=Oberfläche für Python-Debugger GenericName[el]=Python Debugger Frontend +GenericName[en_GB]=Python Debugger Frontend GenericName[es]=Interfaz de depurador para Python GenericName[et]=Pythoni siluri kasutajaliides GenericName[fi]=Python Debugger -käyttöliittymä @@ -83,6 +90,7 @@ GenericName[gl]=Interface de depuración de Python GenericName[hu]=Python hibakövetési felület GenericName[it]=Interfaccia debugger Python GenericName[kk]=Python жөндегіш интерфейсі +GenericName[ko]=파이썬 디버거 프론트엔드 GenericName[mr]=पायथोन डिबगर फ्रंटएन्ड GenericName[nb]=Grensesnitt for Python-feilsøker GenericName[nl]=Frontend voor Python-debugger @@ -102,7 +110,7 @@ GenericName[zh_TW]=Python 除錯器前端介面 Icon=text-x-python X-KDE-Library=kdevpdb X-KDevelop-Category=Global -X-KDevelop-Version=18 +X-KDevelop-Version=19 X-KDE-PluginInfo-Name=kdevpdb X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-Category=Debugging diff --git a/debugger/kdevpdb.py b/debugger/kdevpdb.py index cf432e43..3d0ba281 100644 --- a/debugger/kdevpdb.py +++ b/debugger/kdevpdb.py @@ -1,3 +1,6 @@ +# Copyright 2014 Sven Brauch +# License: GPL v2+ + from pdb import * import sys @@ -40,4 +43,4 @@ def _runscript(self, filename): if __name__ == '__main__': import pdb pdb.Pdb = kdevPdb - pdb.main() \ No newline at end of file + pdb.main() diff --git a/debugger/pdbdebuggerplugin.cpp b/debugger/pdbdebuggerplugin.cpp index bd843476..6ad9f2e2 100644 --- a/debugger/pdbdebuggerplugin.cpp +++ b/debugger/pdbdebuggerplugin.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include "pdbdebuggerplugin.h" #include "pdblauncher.h" @@ -37,12 +37,12 @@ namespace Python { K_PLUGIN_FACTORY(PdbDebuggerPluginFactory, registerPlugin(); ) K_EXPORT_PLUGIN(PdbDebuggerPluginFactory( KAboutData("kdevpdbsupport", "kdevpython", ki18n("Python Debugger (pdb) Support"), - KDEVPYTHON_VERSION_STR, ki18n("Support for the Python Debugger"), KAboutData::License_GPL) + KDEVPYTHON_VERSION_STR, ki18n("Support for the Python Debugger"), K4AboutData::License_GPL) .addAuthor(ki18n("Sven Brauch"), ki18n("Author"), "svenbrauch@googlemail.com", "") )) PdbDebuggerPlugin::PdbDebuggerPlugin(QObject* parent, const QVariantList&) - : IPlugin(PdbDebuggerPluginFactory::componentData(), parent) + : IPlugin("kdevpdbsupport", parent) { IExecuteScriptPlugin* iface = KDevelop::ICore::self()->pluginController() ->pluginForExtension("org.kdevelop.IExecuteScriptPlugin")->extension(); diff --git a/debugger/pdbframestackmodel.cpp b/debugger/pdbframestackmodel.cpp index 67609340..93659379 100644 --- a/debugger/pdbframestackmodel.cpp +++ b/debugger/pdbframestackmodel.cpp @@ -19,9 +19,11 @@ #include "pdbframestackmodel.h" #include "debugsession.h" -#include #include +#include +#include "debuggerdebug.h" + using namespace KDevelop; namespace Python { @@ -44,7 +46,7 @@ void PdbFrameStackModel::setDebuggerAtFrame(int newFrame) void PdbFrameStackModel::framesFetched(QByteArray framelist) { - kDebug() << "frames fetched:" << framelist; + qCDebug(KDEV_PYTHON_DEBUGGER) << "frames fetched:" << framelist; QList lines = framelist.split('\n'); QList frames; bool parsingLocation = false; @@ -65,7 +67,7 @@ void PdbFrameStackModel::framesFetched(QByteArray framelist) // version 1 has some *really* weird "greedy" ruleset which makes no sense at all for me location.setPatternSyntax(QRegExp::RegExp2); if ( location.exactMatch(line) ) { - kDebug() << location.capturedTexts(); + qCDebug(KDEV_PYTHON_DEBUGGER) << location.capturedTexts(); if ( ! location.capturedTexts().at(1).isEmpty() ) { m_debuggerAtFrame = framesCount; } @@ -74,12 +76,12 @@ void PdbFrameStackModel::framesFetched(QByteArray framelist) currentFrame->name = location.capturedTexts().at(4); } else { - kDebug() << "regular expression mismatches" << line; + qCDebug(KDEV_PYTHON_DEBUGGER) << "regular expression mismatches" << line; } } } m_debuggerAtFrame = framesCount - m_debuggerAtFrame - 1; - kDebug() << "at frame:" << m_debuggerAtFrame; + qCDebug(KDEV_PYTHON_DEBUGGER) << "at frame:" << m_debuggerAtFrame; QList framesReversed; for ( int i = frames.length() - 1; i >= 0; i-- ) { framesReversed.append(frames.at(i)); @@ -90,8 +92,8 @@ void PdbFrameStackModel::framesFetched(QByteArray framelist) void PdbFrameStackModel::threadsFetched(QByteArray threadsData) { - kDebug() << "threads fetched" << threadsData; - kDebug() << "Implement me: Thread debugging is not supported by pdb."; + qCDebug(KDEV_PYTHON_DEBUGGER) << "threads fetched" << threadsData; + qCDebug(KDEV_PYTHON_DEBUGGER) << "Implement me: Thread debugging is not supported by pdb."; QList threads; ThreadItem mainThread; mainThread.nr = 0; @@ -103,14 +105,14 @@ void PdbFrameStackModel::threadsFetched(QByteArray threadsData) void PdbFrameStackModel::fetchFrames(int /*threadNumber*/, int /*from*/, int /*to*/) { - kDebug() << "frames requested"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "frames requested"; InternalPdbCommand* cmd = new InternalPdbCommand(this, "framesFetched", "where\n"); static_cast(session())->addCommand(cmd); } void PdbFrameStackModel::fetchThreads() { - kDebug() << "threads requested"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "threads requested"; // pdb doesn't support threads. InternalPdbCommand* cmd = new InternalPdbCommand(this, "threadsFetched", "pass\n"); static_cast(session())->addCommand(cmd); @@ -118,4 +120,4 @@ void PdbFrameStackModel::fetchThreads() } -#include "pdbframestackmodel.moc" \ No newline at end of file +#include "pdbframestackmodel.moc" diff --git a/debugger/pdblauncher.cpp b/debugger/pdblauncher.cpp index 03a6a8d3..59dc4117 100644 --- a/debugger/pdblauncher.cpp +++ b/debugger/pdblauncher.cpp @@ -31,9 +31,11 @@ #include #include #include -#include #include +#include +#include "debuggerdebug.h" + namespace Python { @@ -64,7 +66,7 @@ QString PdbLauncher::name() const KJob* PdbLauncher::start(const QString& launchMode, KDevelop::ILaunchConfiguration* cfg) { - kDebug() << "start of debugger process requested"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "start of debugger process requested"; if ( launchMode == "debug" ) { IExecuteScriptPlugin* iface = KDevelop::ICore::self()->pluginController() ->pluginForExtension("org.kdevelop.IExecuteScriptPlugin")->extension(); @@ -78,7 +80,7 @@ KJob* PdbLauncher::start(const QString& launchMode, KDevelop::ILaunchConfigurati p.start(interpreter, QStringList() << "--version"); p.waitForFinished(500); QByteArray version = p.readAll(); - kDebug() << "interpreter version:" << version; + qCDebug(KDEV_PYTHON_DEBUGGER) << "interpreter version:" << version; if ( ! version.startsWith("Python 3.") ) { KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), i18n("Sorry, debugging is only supported for Python 3.x applications."), @@ -96,7 +98,7 @@ KJob* PdbLauncher::start(const QString& launchMode, KDevelop::ILaunchConfigurati l << job; return new KDevelop::ExecuteCompositeJob( KDevelop::ICore::self()->runController(), l ); } - kDebug() << "unknown launch mode"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "unknown launch mode"; return 0; } diff --git a/debugger/variable.cpp b/debugger/variable.cpp index 54073a8e..65598506 100644 --- a/debugger/variable.cpp +++ b/debugger/variable.cpp @@ -21,6 +21,9 @@ #include "debugsession.h" #include +#include +#include "debuggerdebug.h" + namespace Python { Variable::Variable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent, const QString& expression, const QString& display): @@ -39,7 +42,7 @@ void Variable::dataFetched(QByteArray rawData) } setValue(value); setHasMore(true); - kDebug() << "value set to" << value << ", calling update method"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "value set to" << value << ", calling update method"; QMetaObject::invokeMethod(m_notifyCreated, m_notifyCreatedMethod, Qt::QueuedConnection, Q_ARG(bool, true)); } @@ -80,7 +83,7 @@ void Variable::moreChildrenFetched(QByteArray rawData) while ( i < data.length() ) { QByteArray d = data.at(i); // sort magic functions at the end of the list, they're not too interesting usually - if ( d.startsWith('_') and i < initialLength ) { + if ( d.startsWith('_') && i < initialLength ) { data.append(d); i++; continue; @@ -104,7 +107,7 @@ void Variable::moreChildrenFetched(QByteArray rawData) } Variable* v = new Variable(model_, this, childName, prettyName); appendChild(v); - kDebug() << "adding child:" << expression() << i << d; + qCDebug(KDEV_PYTHON_DEBUGGER) << "adding child:" << expression() << i << d; v->setValue(realValue); v->setId(pythonId); v->setHasMoreInitial(true); diff --git a/debugger/variablecontroller.cpp b/debugger/variablecontroller.cpp index 4c3b7725..dfceed92 100644 --- a/debugger/variablecontroller.cpp +++ b/debugger/variablecontroller.cpp @@ -34,6 +34,9 @@ #include #include +#include +#include "debuggerdebug.h" + using namespace KDevelop; namespace Python { @@ -50,7 +53,7 @@ void VariableController::addWatch(KDevelop::Variable* variable) void VariableController::addWatchpoint(KDevelop::Variable* /*variable*/) { - kWarning() << "addWatchpoint requested (not implemented)"; + qCWarning(KDEV_PYTHON_DEBUGGER) << "addWatchpoint requested (not implemented)"; } void VariableController::handleEvent(IDebugSession::event_t event) @@ -61,9 +64,9 @@ void VariableController::handleEvent(IDebugSession::event_t event) int delta = model->currentFrame() - model->debuggerAtFrame(); model->setDebuggerAtFrame(model->currentFrame()); bool positive = delta > 0; - kDebug() << "changing frame by" << delta; + qCDebug(KDEV_PYTHON_DEBUGGER) << "changing frame by" << delta; for ( int i = delta; i != 0; i += ( positive ? -1 : 1 ) ) { - kDebug() << ( positive ? "up" : "down" ) << model->currentFrame() << model->debuggerAtFrame(); + qCDebug(KDEV_PYTHON_DEBUGGER) << ( positive ? "up" : "down" ) << model->currentFrame() << model->debuggerAtFrame(); s->addSimpleInternalCommand(positive ? "up" : "down"); } } @@ -82,15 +85,15 @@ QString VariableController::expressionUnderCursor(KTextEditor::Document* doc, co if ( ! doc->isModified() ) { if ( TopDUContext* context = DUChain::self()->chainForDocument(doc->url()) ) { DUContext* contextAtCursor = context->findContextAt(CursorInRevision(cursor.line(), cursor.column())); - if ( contextAtCursor and contextAtCursor->type() == DUContext::Class ) { - if ( contextAtCursor->owner() and ! contextAtCursor->owner()->identifier().isEmpty() ) { + if ( contextAtCursor && contextAtCursor->type() == DUContext::Class ) { + if ( contextAtCursor->owner() && ! contextAtCursor->owner()->identifier().isEmpty() ) { prefix = contextAtCursor->owner()->identifier().toString() + "."; } } } } else { - kDebug() << "duchain unavailable for document" << doc->url() << "or document out of date"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "duchain unavailable for document" << doc->url() << "or document out of date"; } TextDocumentLazyLineFetcher linefetcher(doc); @@ -101,7 +104,7 @@ void VariableController::localsUpdateReady(QByteArray rawData) { QRegExp formatExtract("([a-zA-Z0-9_]+) \\=\\> (.*)"); QList data = rawData.split('\n'); - kDebug() << "locals update:" << data; + qCDebug(KDEV_PYTHON_DEBUGGER) << "locals update:" << data; int i = 0; QStringList vars; @@ -113,7 +116,7 @@ void VariableController::localsUpdateReady(QByteArray rawData) vars << key; values[key] = formatExtract.capturedTexts().at(2); } - else kWarning() << "mismatch:" << d; + else qCWarning(KDEV_PYTHON_DEBUGGER) << "mismatch:" << d; i++; } QList variableObjects = KDevelop::ICore::self()->debugController()->variableCollection() @@ -127,7 +130,7 @@ void VariableController::localsUpdateReady(QByteArray rawData) void VariableController::update() { - kDebug() << "update requested"; + qCDebug(KDEV_PYTHON_DEBUGGER) << "update requested"; DebugSession* d = static_cast(parent()); if (autoUpdate() & UpdateWatches) { variableCollection()->watches()->reinstall(); diff --git a/docfilekcm/CMakeLists.txt b/docfilekcm/CMakeLists.txt index 7779380d..84e584cb 100644 --- a/docfilekcm/CMakeLists.txt +++ b/docfilekcm/CMakeLists.txt @@ -4,16 +4,19 @@ set(kcm_docfiles_SRCS kcm_docfiles.cpp ) -kde4_add_plugin(kcm_docfiles ${kcm_docfiles_SRCS}) +add_library(kcm_docfiles MODULE ${kcm_docfiles_SRCS}) target_link_libraries(kcm_docfiles - ${KDE4_KIO_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDEVPLATFORM_UTIL_LIBRARIES} - ${KDE4_KNEWSTUFF3_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} + KF5::KIOCore + KF5::Archive + KF5::KCMUtils + KF5::NewStuff + KF5::KDELibs4Support + KDev::Interfaces + KDev::Language + KDev::Project + KDev::Util + KDev::Interfaces ) install(TARGETS kcm_docfiles @@ -26,4 +29,4 @@ install(FILES kdev_python_docfiles.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) install(FILES ../documentation_src/introspection/introspect.py - DESTINATION ${DATA_INSTALL_DIR}/kdevpythonsupport/scripts) \ No newline at end of file + DESTINATION ${DATA_INSTALL_DIR}/kdevpythonsupport/scripts) diff --git a/docfilekcm/docfilemanagerwidget.cpp b/docfilekcm/docfilemanagerwidget.cpp index 2c50c352..c78e94a4 100644 --- a/docfilekcm/docfilemanagerwidget.cpp +++ b/docfilekcm/docfilemanagerwidget.cpp @@ -36,8 +36,10 @@ #include #include #include +#include +#include +#include -#include #include #include #include @@ -47,6 +49,7 @@ #include #include #include +#include DocfileManagerWidget::DocfileManagerWidget(QWidget* parent) : QWidget(parent) @@ -68,15 +71,15 @@ DocfileManagerWidget::DocfileManagerWidget(QWidget* parent) // construct the buttons for up/download QVBoxLayout* buttonsLayout = new QVBoxLayout; QPushButton* ghnsButton = new QPushButton(i18n("Download new")); - ghnsButton->setIcon(KIcon("get-hot-new-stuff")); + ghnsButton->setIcon(QIcon::fromTheme("get-hot-new-stuff")); QPushButton* generateButton = new QPushButton(i18n("Generate...")); - generateButton->setIcon(KIcon("tools-wizard")); + generateButton->setIcon(QIcon::fromTheme("tools-wizard")); QPushButton* uploadButton = new QPushButton(i18n("Share selected")); - uploadButton->setIcon(KIcon("applications-internet")); // TODO better icon semantically + uploadButton->setIcon(QIcon::fromTheme("applications-internet")); // TODO better icon semantically QPushButton* importButton = new QPushButton(i18n("Import from editor")); importButton->setToolTip(i18n("Copy the contents of the active editor window " "to a new file in the documentation directory")); - importButton->setIcon(KIcon("edit-copy")); + importButton->setIcon(QIcon::fromTheme("edit-copy")); buttonsLayout->addWidget(ghnsButton); buttonsLayout->addWidget(uploadButton); buttonsLayout->addWidget(generateButton); @@ -92,11 +95,11 @@ DocfileManagerWidget::DocfileManagerWidget(QWidget* parent) QFrame* separator2 = new QFrame(); separator2->setFrameShape(QFrame::HLine); QPushButton* openFileManagerButton = new QPushButton(i18n("Open file manager")); - openFileManagerButton->setIcon(KIcon("system-file-manager")); + openFileManagerButton->setIcon(QIcon::fromTheme("system-file-manager")); QPushButton* openTextEditorButton = new QPushButton(i18nc("Edit selected files", "Edit selected")); - openTextEditorButton->setIcon(KIcon("kate")); + openTextEditorButton->setIcon(QIcon::fromTheme("kate")); QPushButton* searchPathsButton = new QPushButton(i18n("Search paths...")); - searchPathsButton->setIcon(KIcon("folder")); + searchPathsButton->setIcon(QIcon::fromTheme("folder")); buttonsLayout->addWidget(separator); buttonsLayout->addWidget(openFileManagerButton); buttonsLayout->addWidget(openTextEditorButton); @@ -123,8 +126,7 @@ DocfileManagerWidget::DocfileManagerWidget(QWidget* parent) void DocfileManagerWidget::showSearchPaths() { - KStandardDirs d; - QStringList dirs = d.findDirs("data", "kdevpythonsupport/documentation_files"); + QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kdevpythonsupport/documentation_files", QStandardPaths::LocateDirectory); QLabel* dirsMessageLabel = new QLabel(i18nc("displays a list of search paths below", "Paths searched for documentation by kdev-python (in this order):")); QTextEdit* paths = new QTextEdit; @@ -149,7 +151,7 @@ void DocfileManagerWidget::showSearchPaths() void DocfileManagerWidget::openDocfilePath() { - KUrl docfileDirectory(docfilePath()); + auto docfileDirectory = QUrl::fromLocalFile(docfilePath()); KRun::runUrl(docfileDirectory, KMimeType::findByUrl(docfileDirectory)->name(), this); } @@ -158,7 +160,7 @@ void DocfileManagerWidget::copyEditorContents() KDevelop::IDocumentController* documentController = KDevelop::ICore::self()->documentController(); if ( documentController->activeDocument() ) { if ( KTextEditor::Document* doc = documentController->activeDocument()->textDocument() ) { - KDialog* dialog = new KDialog(this); + auto dialog = new KDialog(this); dialog->setButtons(KDialog::Ok | KDialog::Cancel); QWidget* contents = new QWidget; contents->setLayout(new QVBoxLayout); @@ -171,11 +173,11 @@ void DocfileManagerWidget::copyEditorContents() contents->layout()->addWidget(new QLabel(i18n("After copying, you will be editing the new document."))); dialog->setMainWidget(contents); if ( dialog->exec() == KDialog::Accepted ) { - KUrl target = KUrl(docfilePath() + "/" + lineEdit->text()); - target.cleanPath(KUrl::SimplifyDirSeparators); - QDir d(target.directory()); + auto target = QUrl::fromLocalFile(docfilePath() + "/" + lineEdit->text()); + // TODO QUrl: cleanPath? + QDir d(target.url()); if ( ! d.exists() ) { - d.mkpath(target.directory()); + d.mkpath(d.absolutePath()); } doc->saveAs(target); } @@ -190,18 +192,17 @@ void DocfileManagerWidget::openSelectedInTextEditor() KMessageBox::information(this, i18n("Please select at least one file from the list for editing.")); } foreach ( const QUrl& item, selected ) { - KUrl fullUrl(item); - fullUrl.setProtocol("file"); // TODO isn't there a more elegant solution for this? - KDevelop::ICore::self()->documentController()->openDocument(fullUrl); + KDevelop::ICore::self()->documentController()->openDocument(item); } } QString DocfileManagerWidget::docfilePath() { - KStandardDirs d; // finds a local directory which is contained in the dirs searched by the parser, code // and creates it if it doesn't exist - QString path = d.locateLocal("data", "kdevpythonsupport/documentation_files/", true); + QDir dir(QStandardPaths::GenericDataLocation + "kdevpython/documentation_files/"); + dir.mkpath(QStandardPaths::GenericDataLocation + "kdevpython/documentation_files/"); + QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + "kdevpythonsupport/documentation_files/"; return path; } @@ -224,8 +225,7 @@ void DocfileManagerWidget::runWizard() void DocfileManagerWidget::showGHNSDialog() { - KStandardDirs d; - QString knsrc = d.findResource("config", "kdev_python_docfiles.knsrc"); + QString knsrc = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "kdev_python_docfiles.knsrc"); KNS3::DownloadDialog dialog(knsrc, this); dialog.exec(); } @@ -254,8 +254,7 @@ QTemporaryFile* DocfileManagerWidget::makeArchive(const QList< QUrl >& urls) con void DocfileManagerWidget::uploadSelected() { - KStandardDirs d; - QString knsrc = d.findResource("config", "kdev_python_docfiles.knsrc"); + QString knsrc = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "kdev_python_docfiles.knsrc"); KNS3::UploadDialog dialog(knsrc, this); QList selected = selectedItems(); // always make a tar archive out of the selected files, even if it's only one diff --git a/docfilekcm/docfilewizard.cpp b/docfilekcm/docfilewizard.cpp index ec609fd9..915784eb 100644 --- a/docfilekcm/docfilewizard.cpp +++ b/docfilekcm/docfilewizard.cpp @@ -33,10 +33,9 @@ #include #include #include +#include #include -#include -#include #include #include #include @@ -92,13 +91,13 @@ DocfileWizard::DocfileWizard(const QString& workingDirectory, QWidget* parent) QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setDirection(QBoxLayout::RightToLeft); QPushButton* closeButton = new QPushButton(i18n("Close")); - closeButton->setIcon(KIcon("dialog-close")); + closeButton->setIcon(QIcon::fromTheme("dialog-close")); saveButton = new QPushButton(i18n("Save and close")); saveButton->setEnabled(false); - saveButton->setIcon(KIcon("dialog-ok-apply")); + saveButton->setIcon(QIcon::fromTheme("dialog-ok-apply")); runButton = new QPushButton(i18n("Generate")); runButton->setDefault(true); - runButton->setIcon(KIcon("tools-wizard")); + runButton->setIcon(QIcon::fromTheme("tools-wizard")); buttonsLayout->addWidget(closeButton); buttonsLayout->addWidget(runButton); buttonsLayout->addWidget(saveButton); @@ -145,8 +144,7 @@ bool DocfileWizard::run() // process already running return false; } - KStandardDirs d; - QString scriptUrl = d.findResource("data", "kdevpythonsupport/scripts/introspect.py"); + QString scriptUrl = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevpythonsupport/scripts/introspect.py"); if ( scriptUrl.isEmpty() ) { KMessageBox::error(this, i18n("Couldn't find the introspect.py script; check your installation!")); return false; @@ -193,7 +191,7 @@ void DocfileWizard::saveAndClose() outputFile.fileName())) == KMessageBox::Yes; } if ( mayWrite ) { - QString basePath = KUrl(outputFile.fileName()).directory(); + auto basePath = QUrl::fromLocalFile(outputFile.fileName()).url(QUrl::RemoveFilename); if ( ! QDir(basePath).exists() ) { QDir(basePath).mkpath(basePath); } diff --git a/docfilekcm/kcm_docfiles.cpp b/docfilekcm/kcm_docfiles.cpp index 2a2bbc5c..60da38de 100644 --- a/docfilekcm/kcm_docfiles.cpp +++ b/docfilekcm/kcm_docfiles.cpp @@ -24,15 +24,12 @@ #include #include -#include - #include "docfilemanagerwidget.h" -K_PLUGIN_FACTORY(DocfilesKCModuleFactory, registerPlugin(); ) -K_EXPORT_PLUGIN(DocfilesKCModuleFactory("kcm_docfiles", "kdevpythonsupport")) +K_PLUGIN_FACTORY(DocfilesKCModuleFactory, registerPlugin();) DocfilesKCModule::DocfilesKCModule(QWidget* parent, const QVariantList& args) - : KCModule(DocfilesKCModuleFactory::componentData(), parent, args) + : KCModule(parent, args) { managerWidget = new DocfileManagerWidget(parent); parent->layout()->addWidget(managerWidget); @@ -43,3 +40,4 @@ DocfilesKCModule::~DocfilesKCModule() } +#include "kcm_docfiles.moc" diff --git a/docfilekcm/kcm_docfiles.h b/docfilekcm/kcm_docfiles.h index 47537bd1..317885e8 100644 --- a/docfilekcm/kcm_docfiles.h +++ b/docfilekcm/kcm_docfiles.h @@ -17,15 +17,18 @@ * along with this program; if not, see . * ************************************************************************/ -#ifndef KCM_CUSTOMBUILDSYSTEM_H -#define KCM_CUSTOMBUILDSYSTEM_H +#ifndef KCM_PY_DOCFILES_H +#define KCM_PY_DOCFILES_H #include #include +#include + class DocfileManagerWidget; class DocfilesKCModule : public KCModule { +Q_OBJECT public: DocfilesKCModule( QWidget* parent, const QVariantList& args = QVariantList() ); virtual ~DocfilesKCModule(); diff --git a/docfilekcm/kcm_kdevpythondocfiles.desktop b/docfilekcm/kcm_kdevpythondocfiles.desktop index 984f060d..6cbf4613 100644 --- a/docfilekcm/kcm_kdevpythondocfiles.desktop +++ b/docfilekcm/kcm_kdevpythondocfiles.desktop @@ -10,12 +10,14 @@ X-KDE-ParentComponents=kdevplatform X-KDE-CfgDlgHierarchy=GENERAL Name=Python documentation data +Name[ar]=بيانات توثيق بايثون Name[bs]=Python dokumentacijski podaci Name[ca]=Dades de la documentació de Python Name[ca@valencia]=Dades de la documentació de Python Name[da]=Python dokumentationsdata Name[de]=Python-Dokumentationsdaten Name[el]=Δεδομένα τεκμηρίωσης Python +Name[en_GB]=Python documentation data Name[es]=Datos de documentación para Python Name[fi]=Python-dokumentaatiodata Name[fr]=Données de documentation pour Python @@ -23,6 +25,7 @@ Name[gl]=Datos da documentación de Python Name[hu]=Python dokumentációs adatok Name[it]=Dati della documentazione di Python Name[kk]=Python құжаттама дерегі +Name[ko]=파이썬 문서 데이터 Name[mr]=पायथोन दस्तऐवजीकरण डेटा Name[nb]=Python dokumentasjonsdata Name[nl]=Gegevens voor Python-documentatie @@ -36,14 +39,17 @@ Name[sv]=Python-dokumentationsdata Name[tr]=Python belgelendirme verisi Name[uk]=Дані документації Python Name[x-test]=xxPython documentation dataxx +Name[zh_CN]=Python 文档数据 Name[zh_TW]=Python 文件資料 Comment=Manage documentation files used by the Python plugin +Comment[ar]=أدر ملفّات التّوثيق الّتي تستخدمها ملحقة بايثون Comment[bs]=Upravljajte dokumentacijskim datotekama koje koristi Python dodatak Comment[ca]=Gestiona els fitxers de documentació usats pel connector de Python Comment[ca@valencia]=Gestiona els fitxers de documentació usats pel connector de Python Comment[da]=Håndtér dokumentationsfiler som bruges af Python-pluginet Comment[de]=Verwaltet Dokumentationsdateien, die vom Pythonmodul verwendet werden Comment[el]=Διαχείριση αρχείων τεκμηρίωσης που χρησιμεύουν στο πρόσθετο Python +Comment[en_GB]=Manage documentation files used by the Python plugin Comment[es]=Gestionar archivos de documentación usados por el complemento de Python Comment[fi]=Hallitse Python-liitännäisen käyttämiä dokumentaatiotiedostoja Comment[fr]=Gère les fichiers de documentation utilisés par le module externe Python @@ -51,6 +57,7 @@ Comment[gl]=Xestiona os ficheiros de documentación usados por complemento de Py Comment[hu]=Dokumentációs fájlok kezelése a Python bővítmény használatával Comment[it]=Gestisce i file della documentazione usati dall'estensione Python Comment[kk]=Python плагині қолданатын құжаттама файлдарды басқару +Comment[ko]=파이썬 플러그인에서 사용하는 문서 파일 관리 Comment[mr]=पायथोन प्लगइन द्वारे वापरल्या जाणारे दस्तऐवजीकरण व्यवस्थापीत करा Comment[nb]=Håndtere dokumentasjonsfiler som Python-programtillegget bruker Comment[nl]=Documentatiebestanden beheren gebruikt door de plug-in van Python @@ -64,4 +71,5 @@ Comment[sv]=Hantera dokumentationsfiler som används av Python-insticksprogramme Comment[tr]=Pyhton eklentiis tarafından kullanılan belgelendirme dosyalarını yönetin Comment[uk]=Керування файлами документації, що використовуються додатком Python Comment[x-test]=xxManage documentation files used by the Python pluginxx +Comment[zh_CN]=管理 Python 插件使用的文档 Comment[zh_TW]=管理 Python 外掛程式會使用的文件檔 diff --git a/documentation_files/COPYING b/documentation_files/COPYING new file mode 100644 index 00000000..dfd08b5d --- /dev/null +++ b/documentation_files/COPYING @@ -0,0 +1,2 @@ +All files in this subdirectory tree are generated automatically and are not +subject to copyright, unless the file header says something different. diff --git a/documentation_src/introspection/introspect.py b/documentation_src/introspection/introspect.py index 2df2adf0..540685a4 100644 --- a/documentation_src/introspection/introspect.py +++ b/documentation_src/introspection/introspect.py @@ -2,7 +2,7 @@ # -*- Coding:utf-8 -*- # Copyright 2013 by Sven Brauch -# License: GNU GPL v3 or later +# License: GNU GPL v2 or later # The script output is not copyrighted, use it for whatever you want. # WARNING: This script does things which can cause bad stuff to happen diff --git a/documentation_src/numpy/generate_numpy_doc.py b/documentation_src/numpy/generate_numpy_doc.py index 786453ed..d861e1fa 100644 --- a/documentation_src/numpy/generate_numpy_doc.py +++ b/documentation_src/numpy/generate_numpy_doc.py @@ -1,5 +1,8 @@ #!/usr/bin/env python +# Copyright 2014 Sven Brauch +# License: GPL v2+ + import importlib modules = ["numpy", "numpy.ctypeslib", diff --git a/documentation_src/pyqt/generate.sh b/documentation_src/pyqt/generate.sh index 70b1c5b6..b6d0ee9e 100644 --- a/documentation_src/pyqt/generate.sh +++ b/documentation_src/pyqt/generate.sh @@ -1,3 +1,6 @@ +# Copyright 2014 Sven Brauch +# License: GPL v2+ + pyqt=($(ls /usr/share/sip/PyQt4)) element_count=${#pyqt[@]} for index in $(seq $element_count); do diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 1c1720c8..9faa2b9d 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -19,6 +19,7 @@ set(duchain_SRCS declarationbuilder.cpp usebuilder.cpp dumpchain.cpp + duchaindebug.cpp navigation/navigationwidget.cpp navigation/declarationnavigationcontext.cpp @@ -30,18 +31,23 @@ set(duchain_SRCS ) -kde4_add_library( kdev4pythonduchain SHARED ${duchain_SRCS} ) -target_link_libraries( kdev4pythonduchain LINK_PRIVATE - ${KDE4_KDECORE_LIBS} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDE4_KTEXTEDITOR_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${QT_QTWEBKIT_LIBRARY} - kdev4pythonparser +add_library( kdevpythonduchain SHARED ${duchain_SRCS} ) + +generate_export_header( kdevpythonduchain EXPORT_MACRO_NAME KDEVPYTHONDUCHAIN_EXPORT + EXPORT_FILE_NAME pythonduchainexport.h +) + +target_link_libraries( kdevpythonduchain LINK_PRIVATE + Qt5::WebKitWidgets + KF5::KDELibs4Support + KF5::TextEditor + KDev::Interfaces + KDev::Language + KDev::Project + kdevpythonparser ) -install(TARGETS kdev4pythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS kdevpythonduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(navigation) diff --git a/duchain/assistants/missingincludeassistant.cpp b/duchain/assistants/missingincludeassistant.cpp index 2883043e..03769346 100644 --- a/duchain/assistants/missingincludeassistant.cpp +++ b/duchain/assistants/missingincludeassistant.cpp @@ -1,6 +1,6 @@ /* - * - * Copyright 2013 + * This file is part of kdev-python, the Python language support plugin for KDevelop + * Copyright 2013 Sven Brauch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,8 +29,11 @@ #include -#include -#include +#include +#include +#include "../duchaindebug.h" + + #include #include @@ -46,9 +49,9 @@ MissingIncludeProblem::MissingIncludeProblem(const QString &moduleName, IndexedS } -KSharedPtr MissingIncludeProblem::solutionAssistant() const +QExplicitlySharedDataPointer MissingIncludeProblem::solutionAssistant() const { - return KSharedPtr(new MissingIncludeAssistant(m_moduleName, m_currentDocument)); + return QExplicitlySharedDataPointer(new MissingIncludeAssistant(m_moduleName, m_currentDocument)); } DocumentationGeneratorAction::DocumentationGeneratorAction(const QString& module, const IndexedString& document) @@ -67,13 +70,14 @@ QString DocumentationGeneratorAction::description() const void DocumentationGeneratorAction::execute() { // yes, it's duplicate from the doc file widget, but it's too painful to share it - KStandardDirs d; - QString path = d.locateLocal("data", "kdevpythonsupport/documentation_files/", true); + QDir dir(QStandardPaths::GenericDataLocation + "kdevpythonsupport/documentation_files/"); + dir.mkpath(QStandardPaths::GenericDataLocation + "kdevpythonsupport/documentation_files/"); + QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + "kdevpythonsupport/documentation_files/"; DocfileWizard wizard(path); wizard.setModuleName(module); wizard.exec(); if ( ! wizard.wasSavedAs().isNull() ) { - ICore::self()->documentController()->openDocument(KUrl(wizard.wasSavedAs())); + ICore::self()->documentController()->openDocument(QUrl::fromLocalFile(wizard.wasSavedAs())); // force a recursive update of the context, so that all the imports are reparsed too // (since they potentially have changed through this action) ICore::self()->languageController()->backgroundParser()->addDocument(document, TopDUContext::ForceUpdateRecursive); @@ -83,7 +87,7 @@ void DocumentationGeneratorAction::execute() void MissingIncludeAssistant::createActions() { - KSharedPtr action(new DocumentationGeneratorAction(module, document)); + QExplicitlySharedDataPointer action(new DocumentationGeneratorAction(module, document)); addAction(action); } @@ -96,4 +100,4 @@ MissingIncludeAssistant::MissingIncludeAssistant(const QString& module, const In } -#include "missingincludeassistant.moc" \ No newline at end of file +#include "missingincludeassistant.moc" diff --git a/duchain/assistants/missingincludeassistant.h b/duchain/assistants/missingincludeassistant.h index c3bb2e0d..576f2dd5 100644 --- a/duchain/assistants/missingincludeassistant.h +++ b/duchain/assistants/missingincludeassistant.h @@ -24,11 +24,11 @@ #define PYTHON_MISSINGINCLUDEASSISTANT_H #include -#include +#include #include #include -#include +#include namespace Python { @@ -36,7 +36,7 @@ namespace Python { class MissingIncludeProblem : public KDevelop::Problem { public: MissingIncludeProblem(const QString& moduleName, KDevelop::IndexedString currentDocument); - virtual KSharedPtr< KDevelop::IAssistant > solutionAssistant() const; + virtual QExplicitlySharedDataPointer solutionAssistant() const override; private: QString m_moduleName; diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 40e344b5..0b42c551 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -28,8 +28,6 @@ #include "declarationbuilder.h" #include "helpers.h" -#include - #include #include @@ -160,7 +158,7 @@ RangeInRevision ContextBuilder::editorFindRange(Ast* fromNode, Ast* toNode) } CursorInRevision ContextBuilder::editorFindPositionSafe(Ast* node) { - if ( not node ) { + if ( !node ) { return CursorInRevision::invalid(); } return editor()->findPosition(node); @@ -297,8 +295,8 @@ void ContextBuilder::visitClassDefinition( ClassDefinitionAst* node ) } void ContextBuilder::visitCode(CodeAst* node) { - KUrl doc_url = KUrl(Helper::getDocumentationFile()); - IndexedString doc = IndexedString(doc_url.path()); + auto doc_url = Helper::getDocumentationFile(); + IndexedString doc = IndexedString(doc_url); Q_ASSERT(currentlyParsedDocument().toUrl().isValid()); if ( currentlyParsedDocument() != doc ) { // Search for the python built-in functions file, and dump its contents into the current file. @@ -321,17 +319,17 @@ void ContextBuilder::visitCode(CodeAst* node) { AstDefaultVisitor::visitCode(node); } -QPair ContextBuilder::findModulePath(const QString& name, const KUrl& currentDocument) +QPair ContextBuilder::findModulePath(const QString& name, const QUrl& currentDocument) { QStringList nameComponents = name.split("."); - QList searchPaths; + QList searchPaths; if ( name.startsWith('.') ) { /* To take care for imports like "from ....xxxx.yyy import zzz" * we need to take current doc path and run "cd .." enough times */ nameComponents.removeFirst(); QString tname = name.mid(1); // remove first dot - QDir curPathDir = QDir(currentDocument.directory()); + QDir curPathDir = QDir(currentDocument.adjusted(QUrl::RemoveFilename).toLocalFile()); foreach(QString c, tname) { if (c != ".") break; @@ -347,10 +345,10 @@ QPair ContextBuilder::findModulePath(const QString& name, con searchPaths = Helper::getSearchPaths(currentDocument); } // Loop over all the name components, and find matching folders or files. - KUrl tmp; + QDir tmp; QStringList leftNameComponents; - foreach ( KUrl currentPath, searchPaths ) { - tmp = currentPath; + foreach ( QUrl currentPath, searchPaths ) { + tmp.setPath(currentPath.path()); leftNameComponents = nameComponents; foreach ( QString component, nameComponents ) { if ( component == "*" ) { @@ -361,7 +359,7 @@ QPair ContextBuilder::findModulePath(const QString& name, con // only empty the list if not importing *, this is convenient later on leftNameComponents.removeFirst(); } - QString testFilename = tmp.path(KUrl::AddTrailingSlash) + component; + QString testFilename = tmp.path() + "/" + component; tmp.cd(component); QFileInfo sourcedir(testFilename); @@ -375,13 +373,13 @@ QPair ContextBuilder::findModulePath(const QString& name, con // the file matching the next name component will be returned, // toegether with a list of names which must be resolved inside that file. if ( sourcefile.exists() ) { - KUrl sourceUrl = testFilename + extension; - sourceUrl.cleanPath(); + auto sourceUrl = QUrl::fromLocalFile(testFilename + extension); + // TODO QUrl: cleanPath? return qMakePair(sourceUrl, leftNameComponents); } else if ( sourcedir.exists() && sourcedir.isDir() ) { - KUrl path(testFilename + "/__init__.py"); - path.cleanPath(); + auto path = QUrl::fromLocalFile(testFilename + "/__init__.py"); + // TODO QUrl: cleanPath? return qMakePair(path, leftNameComponents); } } @@ -393,28 +391,28 @@ QPair ContextBuilder::findModulePath(const QString& name, con RangeInRevision ContextBuilder::rangeForArgumentsContext(FunctionDefinitionAst* node) { - SimpleCursor start = node->name->range().end; - SimpleCursor end = start; + auto start = node->name->range().end(); + auto end = start; if ( node->arguments->kwarg ) { - end = node->arguments->kwarg->range().end; + end = node->arguments->kwarg->range().end(); } else if ( node->arguments->vararg ) { - end = node->arguments->vararg->range().end; + end = node->arguments->vararg->range().end(); } if ( ! node->arguments->arguments.isEmpty() && node->arguments->vararg ) { if ( node->arguments->vararg->appearsBefore(node->arguments->arguments.last()) ) { - end = node->arguments->arguments.last()->range().end; + end = node->arguments->arguments.last()->range().end(); } } else if ( ! node->arguments->arguments.isEmpty() ) { - end = node->arguments->arguments.last()->range().end; + end = node->arguments->arguments.last()->range().end(); } if ( ! node->arguments->defaultValues.isEmpty() ) { - end = qMax(node->arguments->defaultValues.last()->range().end, end); + end = qMax(node->arguments->defaultValues.last()->range().end(), end); } - RangeInRevision range(start.line, start.column, end.line, end.column); + RangeInRevision range(start.line(), start.column(), end.line(), end.column()); // make the range contain the closing and opening parentheses range.start.column -= 1; range.end.column += 1; diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index db8ed69c..5c42bee2 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -75,10 +75,10 @@ class KDEVPYTHONDUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, public * * @param name a dotted name, such as PyQt4.QtCore.QWidget * @param currentDocument the current document, for resolving relative imports - * @return QPair< KUrl, QStringList > the URL if found, and a list of components from + * @return QPair< QUrl, QStringList > the URL if found, and a list of components from * the end of the name which were not yet consumed */ - static QPair findModulePath(const QString& name, const KUrl& currentDocument); + static QPair findModulePath(const QString& name, const QUrl& currentDocument); /** * @brief Get the range which encompasses the given @p node. diff --git a/duchain/correctionhelper.cpp b/duchain/correctionhelper.cpp index 3b28158d..6ad17f21 100644 --- a/duchain/correctionhelper.cpp +++ b/duchain/correctionhelper.cpp @@ -28,7 +28,10 @@ #include #include -#include +#include +#include "duchaindebug.h" + + #include using namespace KDevelop; @@ -38,17 +41,17 @@ namespace Python { CorrectionHelper::CorrectionHelper(const IndexedString& _url, DeclarationBuilder* builder) { m_contextStack.push(0); - KUrl absolutePath = Helper::getCorrectionFile(_url.toUrl()); + auto absolutePath = Helper::getCorrectionFile(_url.toUrl()); if ( !absolutePath.isValid() || absolutePath.isEmpty() || ! QFile::exists(absolutePath.path()) ) { return; } - kDebug() << "Found correction file for " << _url.str() << ": " << absolutePath.path(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found correction file for " << _url.str() << ": " << absolutePath.path(); const IndexedString indexedPath(absolutePath); DUChainReadLocker lock; m_hintTopContext = DUChain::self()->chainForDocument(indexedPath); - kDebug() << "got top context for" << absolutePath << m_hintTopContext; + qCDebug(KDEV_PYTHON_DUCHAIN) << "got top context for" << absolutePath << m_hintTopContext; m_contextStack.top() = m_hintTopContext.data(); if ( ! m_hintTopContext ) { // The file exists, but was not parsed yet. Schedule it, and re-schedule the current one too. @@ -80,7 +83,7 @@ void CorrectionHelper::enter(const KDevelop::Identifier& identifier) return; } - kDebug() << "Looking in " << identifier.toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Looking in " << identifier.toString(); // there's a hint declaration for this object, put it on the stack DUContext* internal = decls.first()->internalContext(); m_contextStack.push(internal); @@ -109,7 +112,7 @@ AbstractType::Ptr CorrectionHelper::hintFor(const KDevelop::Identifier &identifi return hint; } - kDebug() << "Found specified correct type for " << identifier.toString() << decls.first()->abstractType()->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found specified correct type for " << identifier.toString() << decls.first()->abstractType()->toString(); return decls.first()->abstractType(); } diff --git a/duchain/correctionhelper.h b/duchain/correctionhelper.h index ed0a6337..f72ecf79 100644 --- a/duchain/correctionhelper.h +++ b/duchain/correctionhelper.h @@ -27,8 +27,6 @@ #include #include -#include - using namespace KDevelop; namespace Python { diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 06cb9d4b..c20af727 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -48,7 +48,9 @@ #include #include -#include + +#include +#include "duchaindebug.h" #include @@ -63,7 +65,7 @@ DeclarationBuilder::DeclarationBuilder(Python::PythonEditorIntegrator* editor, i , m_ownPriority(ownPriority) { setEditor(editor); - kDebug() << "Building Declarations"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Building Declarations"; } DeclarationBuilder:: ~DeclarationBuilder() @@ -89,18 +91,18 @@ ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url, Ast* // The declaration builder needs to run twice, so it can resolve uses of e.g. functions // which are called before they are defined (which is easily possible, due to python's dynamic nature). if ( ! m_prebuilding ) { - kDebug() << "building, but running pre-builder first"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "building, but running pre-builder first"; DeclarationBuilder* prebuilder = new DeclarationBuilder(editor()); prebuilder->m_ownPriority = m_ownPriority; prebuilder->m_currentlyParsedDocument = currentlyParsedDocument(); prebuilder->setPrebuilding(true); prebuilder->m_futureModificationRevision = m_futureModificationRevision; updateContext = prebuilder->build(url, node, updateContext); - kDebug() << "pre-builder finished"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "pre-builder finished"; delete prebuilder; } else { - kDebug() << "prebuilding"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "prebuilding"; } return DeclarationBuilderBase::build(url, node, updateContext); } @@ -158,7 +160,7 @@ template T* DeclarationBuilder::visitVariableDeclaration(Ast* node, return visitVariableDeclaration(static_cast(node), 0, previous, type); } else { - kWarning() << "cannot create variable declaration for non-(name|identifier) AST, this is a programming error"; + qCWarning(KDEV_PYTHON_DUCHAIN) << "cannot create variable declaration for non-(name|identifier) AST, this is a programming error"; return static_cast(0); } } @@ -213,7 +215,7 @@ template QList DeclarationBuilder::reopenFittingDeclar Declaration* fitting = dynamic_cast(d); if ( ! fitting ) { // Only use a declaration if the type matches - kDebug() << "skipping" << d->toString() << "which could not be cast to the requested type"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "skipping" << d->toString() << "which could not be cast to the requested type"; continue; } // Do not use declarations which have been encountered previously; @@ -236,7 +238,7 @@ template QList DeclarationBuilder::reopenFittingDeclar break; } else { - kDebug() << "Not opening previously existing declaration because it's in another top context"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Not opening previously existing declaration because it's in another top context"; } } else if ( ! invalidType ) { @@ -282,10 +284,10 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* // tells whether there's fitting declarations to update (update is not the same as re-open! one is for // code which uses the same variable twice, the other is for multiple passes of the parser) bool haveFittingDeclaration = false; - if ( ! existingDeclarations.isEmpty() and existingDeclarations.last() ) { + if ( ! existingDeclarations.isEmpty() && existingDeclarations.last() ) { Declaration* d = Helper::resolveAliasDeclaration(existingDeclarations.last()); DUChainReadLocker lock; - if ( d and d->topContext() != topContext() ) { + if ( d && d->topContext() != topContext() ) { inSameTopContext = false; } if ( dynamic_cast(existingDeclarations.last()) ) { @@ -320,7 +322,7 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* if ( currentContext()->type() == DUContext::Function ) { // check for argument type hints (those are created when calling functions) AbstractType::Ptr hints = Helper::extractTypeHints(dec->abstractType(), topContext()); - kDebug() << hints->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << hints->toString(); if ( hints.cast() || hints.cast() ) { // This only happens when the type hint is a tuple, which means the vararg/kwarg of a function is being processed. newType = hints; @@ -354,7 +356,7 @@ template T* DeclarationBuilder::visitVariableDeclaration(Identifier* } T* result = dynamic_cast(dec); - if ( ! result ) kWarning() << "variable declaration does not have the expected type"; + if ( ! result ) qCWarning(KDEV_PYTHON_DUCHAIN) << "variable declaration does not have the expected type"; return result; } @@ -477,8 +479,8 @@ Declaration* DeclarationBuilder::findDeclarationInContext(QStringList dottedName CursorInRevision::invalid(), 0, DUContext::NoFiltering); // break if the list of identifiers is not yet totally worked through and no // declaration with an internal context was found - if ( declarations.isEmpty() or ( not declarations.last()->internalContext() and identifierCount != i ) ) { - kDebug() << "Declaration not found: " << dottedNameIdentifier << "in top context" << ctx->url().toUrl().path(); + if ( declarations.isEmpty() || ( !declarations.last()->internalContext() && identifierCount != i ) ) { + qCDebug(KDEV_PYTHON_DUCHAIN) << "Declaration not found: " << dottedNameIdentifier << "in top context" << ctx->url().toUrl().path(); return 0; } else { @@ -620,7 +622,7 @@ Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameCo Q_ASSERT( ( innerCtx.data() || aliasDeclaration ) && "exactly one of innerCtx or aliasDeclaration must be provided"); Q_ASSERT( ( !innerCtx.data() || !aliasDeclaration ) && "exactly one of innerCtx or aliasDeclaration must be provided"); - kDebug() << "creating declaration tree for" << nameComponents; + qCDebug(KDEV_PYTHON_DUCHAIN) << "creating declaration tree for" << nameComponents; Declaration* lastDeclaration = 0; int depth = 0; @@ -632,7 +634,7 @@ Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameCo currentName.append(nameComponents.at(j)); } lastDeclaration = findDeclarationInContext(currentName, topContext()); - if ( lastDeclaration and lastDeclaration->range() < range ) { + if ( lastDeclaration && lastDeclaration->range() < range ) { depth = i; break; } @@ -641,15 +643,15 @@ Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameCo DUContext* extendingPreviousImportCtx = 0; QStringList remainingNameComponents; bool injectingContext = false; - if ( lastDeclaration and lastDeclaration->internalContext() ) { - kDebug() << "Found existing import statement while creating declaration for " << declarationIdentifier->value; + if ( lastDeclaration && lastDeclaration->internalContext() ) { + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found existing import statement while creating declaration for " << declarationIdentifier->value; for ( int i = depth; i < nameComponents.length(); i++ ) { remainingNameComponents.append(nameComponents.at(i)); } extendingPreviousImportCtx = lastDeclaration->internalContext(); injectContext(extendingPreviousImportCtx); injectingContext = true; - kDebug() << "remaining identifiers:" << remainingNameComponents; + qCDebug(KDEV_PYTHON_DUCHAIN) << "remaining identifiers:" << remainingNameComponents; } else { remainingNameComponents = nameComponents; @@ -712,14 +714,14 @@ Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameCo } d->setAutoDeclaration(true); currentContext()->createUse(d->ownIndex(), displayRange); - kDebug() << "really encountered:" << d << "; scheduled:" << m_scheduledForDeletion; - kDebug() << d->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "really encountered:" << d << "; scheduled:" << m_scheduledForDeletion; + qCDebug(KDEV_PYTHON_DUCHAIN) << d->toString(); scheduleForDeletion(d, false); - kDebug() << "scheduled:" << m_scheduledForDeletion; + qCDebug(KDEV_PYTHON_DUCHAIN) << "scheduled:" << m_scheduledForDeletion; } if ( done ) break; - kDebug() << "creating context for " << component; + qCDebug(KDEV_PYTHON_DUCHAIN) << "creating context for " << component; // otherwise, create a new "level" entry (a pseudo type + context + declaration which contains all imported items) StructureType::Ptr moduleType = StructureType::Ptr(new StructureType()); openType(moduleType); @@ -739,17 +741,17 @@ Declaration* DeclarationBuilder::createDeclarationTree(const QStringList& nameCo openedTypes.append(moduleType); if ( i == remainingNameComponents.length() - 1 ) { if ( innerCtx ) { - kDebug() << "adding imported context to inner declaration"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "adding imported context to inner declaration"; currentContext()->addImportedParentContext(innerCtx); } else if ( aliasDeclaration ) { - kDebug() << "setting alias declaration on inner declaration"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "setting alias declaration on inner declaration"; } } } for ( int i = openedContexts.length() - 1; i >= 0; i-- ) { // Close all the declarations and contexts opened previosly, and assign the types. - kDebug() << "closing context"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "closing context"; closeType(); closeContext(); Declaration* d = openedDeclarations.at(i); @@ -777,7 +779,7 @@ Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleNam ProblemPointer& problemEncountered, Ast* rangeNode) { // Search the disk for a python file which contains the requested declaration - QPair moduleInfo = findModulePath(moduleName, currentlyParsedDocument().toUrl()); + auto moduleInfo = findModulePath(moduleName, currentlyParsedDocument().toUrl()); RangeInRevision range(RangeInRevision::invalid()); if ( rangeNode ) { range = rangeForNode(rangeNode, false); @@ -787,8 +789,8 @@ Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleNam } Q_ASSERT(range.isValid()); - kDebug() << "Found module path [path/path in file]: " << moduleInfo; - kDebug() << "Declaration identifier:" << declarationIdentifier->value; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found module path [path/path in file]: " << moduleInfo; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Declaration identifier:" << declarationIdentifier->value; DUChainWriteLocker lock; const IndexedString modulePath = IndexedString(moduleInfo.first); ReferencedTopDUContext moduleContext = DUChain::self()->chainForDocument(modulePath); @@ -798,18 +800,18 @@ Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleNam // The file was not found -- this is either an error in the user's code, // a missing module, or a C module (.so) which is unreadable for kdevelop // TODO imrpove error handling in case the module exists as a shared object or .pyc file only - kDebug() << "invalid or non-existent URL:" << moduleInfo; + qCDebug(KDEV_PYTHON_DUCHAIN) << "invalid or non-existent URL:" << moduleInfo; KDevelop::Problem *p = new Python::MissingIncludeProblem(moduleName, currentlyParsedDocument()); p->setFinalLocation(DocumentRange(currentlyParsedDocument(), range.castToSimpleRange())); p->setSource(KDevelop::ProblemData::SemanticAnalysis); p->setSeverity(KDevelop::ProblemData::Warning); p->setDescription(i18n("Module \"%1\" not found", moduleName)); - problemEncountered.attach(p); + problemEncountered = p; return 0; } if ( ! moduleContext ) { // schedule the include file for parsing, and schedule the current one for reparsing after that is done - kDebug() << "No module context, recompiling"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "No module context, recompiling"; m_unresolvedImports.append(modulePath); Helper::scheduleDependency(modulePath, m_ownPriority); // parseDocuments() must *not* be called from a background thread! @@ -825,11 +827,11 @@ Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleNam // import a specific declaration from the given file lock.lock(); if ( declarationIdentifier->value == "*" ) { - kDebug() << "Importing * from module"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Importing * from module"; currentContext()->addImportedParentContext(moduleContext); } else { - kDebug() << "Got module, importing declaration: " << moduleInfo.second; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Got module, importing declaration: " << moduleInfo.second; Declaration* originalDeclaration = findDeclarationInContext(moduleInfo.second, moduleContext); if ( originalDeclaration ) { DUChainWriteLocker lock(DUChain::lock()); @@ -843,7 +845,7 @@ Declaration* DeclarationBuilder::createModuleImportDeclaration(QString moduleNam p->setSource(KDevelop::ProblemData::SemanticAnalysis); p->setSeverity(KDevelop::ProblemData::Warning); p->setDescription(i18n("Declaration for \"%1\" not found in specified module", moduleInfo.second.join("."))); - problemEncountered.attach(p); + problemEncountered = p; } } } @@ -933,7 +935,7 @@ void DeclarationBuilder::applyDocstringHints(CallAst* node, FunctionDeclaration: return; } DUChainWriteLocker wlock; - kDebug() << "Adding content type: " << argVisitor.lastType()->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Adding content type: " << argVisitor.lastType()->toString(); container->addContentType(argVisitor.lastType()); v.lastDeclaration()->setType(container); }; @@ -1022,7 +1024,7 @@ void DeclarationBuilder::addArgumentTypeHints(CallAst* node, DeclarationPointer atVararg = true; } - kDebug() << currentParamIndex << currentArgumentIndex << atVararg << lastFunctionDeclaration->vararg(); + qCDebug(KDEV_PYTHON_DUCHAIN) << currentParamIndex << currentArgumentIndex << atVararg << lastFunctionDeclaration->vararg(); ExpressionAst* arg = node->arguments.at(currentArgumentIndex); @@ -1045,8 +1047,7 @@ void DeclarationBuilder::addArgumentTypeHints(CallAst* node, DeclarationPointer indexInVararg++; Declaration* parameter = parameters.at(lastFunctionDeclaration->vararg()+hasSelfArgument); IndexedContainer::Ptr varargContainer = parameter->type(); - kDebug() << "vararg container:" << varargContainer; - kDebug() << "adding" << addType->toString() << "at position" << indexInVararg; + qCDebug(KDEV_PYTHON_DUCHAIN) << "adding" << addType->toString() << "at position" << indexInVararg; if ( ! varargContainer ) continue; if ( varargContainer->typesCount() > indexInVararg ) { AbstractType::Ptr oldType = varargContainer->typeAt(indexInVararg).abstractType(); @@ -1059,7 +1060,6 @@ void DeclarationBuilder::addArgumentTypeHints(CallAst* node, DeclarationPointer parameter->setAbstractType(varargContainer.cast()); } else { - kDebug() << "adding" << argumentType << "at position" << currentArgumentIndex << "/" << currentParamIndex; if ( ! argumentType ) continue; AbstractType::Ptr newType = Helper::mergeTypes(parameters.at(currentParamIndex)->abstractType(), addType.cast()); @@ -1316,7 +1316,7 @@ void DeclarationBuilder::assignToAttribute(AttributeAst* attrib, const Declarati DeclarationPointer parentObjectDeclaration = checkPreviousAttributes.lastDeclaration(); if ( ! parentObjectDeclaration ) { - kDebug() << "No declaration for attribute base, aborting creation of attribute"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "No declaration for attribute base, aborting creation of attribute"; return; } // if foo is a class, this is like foo.bar = 3 @@ -1333,7 +1333,7 @@ void DeclarationBuilder::assignToAttribute(AttributeAst* attrib, const Declarati internal = parentObjectDeclaration->internalContext(); } if ( ! internal ) { - kDebug() << "No internal context for structure type, aborting creation of attribute declaration"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "No internal context for structure type, aborting creation of attribute declaration"; return; } @@ -1358,7 +1358,7 @@ void DeclarationBuilder::assignToAttribute(AttributeAst* attrib, const Declarati DUChainWriteLocker lock; previousContext->createUse(dec->ownIndex(), editorFindRange(attrib, attrib)); } - else kWarning() << "No declaration created for " << attrib->attribute << "as parent is not a class"; + else qCWarning(KDEV_PYTHON_DUCHAIN) << "No declaration created for " << attrib->attribute << "as parent is not a class"; closeInjectedContext(); } @@ -1446,7 +1446,7 @@ void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) lock.lock(); // every python class inherits from "object". // We use this to add all the __str__, __get__, ... methods. - if ( dec->baseClassesSize() == 0 and node->name->value != "object" ) { + if ( dec->baseClassesSize() == 0 && node->name->value != "object" ) { DUChainWriteLocker wlock; ReferencedTopDUContext docContext = Helper::getDocumentationFileContext(); if ( docContext ) { @@ -1476,8 +1476,8 @@ void DeclarationBuilder::visitClassDefinition( ClassDefinitionAst* node ) dec->setInternalContext(currentContext()); lock.unlock(); - foreach ( Ast* node, node->body ) { - AstDefaultVisitor::visitNode(node); + foreach ( Ast* _node, node->body ) { + AstDefaultVisitor::visitNode(_node); } lock.lock(); @@ -1624,7 +1624,7 @@ void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) DUChainWriteLocker lock; KDevelop::Problem *p = new KDevelop::Problem(); // only mark first line - p->setFinalLocation(DocumentRange(currentlyParsedDocument(), SimpleRange(node->startLine, node->startCol, node->startLine, 10000))); + p->setFinalLocation(DocumentRange(currentlyParsedDocument(), KTextEditor::Range(node->startLine, node->startCol, node->startLine, 10000))); p->setSource(KDevelop::ProblemData::SemanticAnalysis); p->setSeverity(KDevelop::ProblemData::Warning); p->setDescription(i18n("Non-static class method without arguments, must have at least one (self)")); @@ -1650,11 +1650,11 @@ void DeclarationBuilder::visitFunctionDefinition( FunctionDefinitionAst* node ) lock.lock(); if ( v.lastType() && v.isAlias() ) { type->setReturnType(Helper::mergeTypes(type->returnType(), v.lastType())); - kDebug() << "updated function return type to " << type->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "updated function return type to " << type->toString(); dec->setType(type); } else if ( ! v.isAlias()) { - kDebug() << "not updating function return type because expression is not a type object"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "not updating function return type because expression is not a type object"; } } @@ -1814,7 +1814,7 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) int parametersCount = node->arguments.length(); int firstDefaultParameterOffset = parametersCount - defaultParametersCount; int currentIndex = 0; - kDebug() << "arguments:" << node->arguments.size(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "arguments:" << node->arguments.size(); foreach ( ArgAst* arg, node->arguments ) { // Iterate over all the function's arguments, create declarations, and add the arguments // to the functions FunctionType. @@ -1824,12 +1824,12 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) continue; } - kDebug() << "visiting argument:" << arg->argumentName->value; + qCDebug(KDEV_PYTHON_DUCHAIN) << "visiting argument:" << arg->argumentName->value; // Create a variable declaration for the parameter, to be used in the function body. Declaration* paramDeclaration = visitVariableDeclaration(arg->argumentName); if ( ! paramDeclaration ) { - kDebug() << "could not create parameter declaration!"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "could not create parameter declaration!"; continue; } @@ -1854,7 +1854,7 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) workingOnDeclaration->addDefaultParameter(IndexedString("...")); } - kDebug() << "is first:" << isFirst << hasCurrentDeclaration() << currentDeclaration(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "is first:" << isFirst << hasCurrentDeclaration() << currentDeclaration(); if ( isFirst && hasCurrentDeclaration() && currentContext() && currentContext()->parentContext() ) { DUChainReadLocker lock; if ( currentContext()->parentContext()->type() == DUContext::Class ) { @@ -1867,7 +1867,7 @@ void DeclarationBuilder::visitArguments( ArgumentsAst* node ) paramDeclaration->setAbstractType(Helper::mergeTypes(paramDeclaration->abstractType(), argumentType)); type->addArgument(argumentType); if ( argumentType ) { - kDebug() << "creating argument with type" << argumentType->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "creating argument with type" << argumentType->toString(); } } // Handle *args, **kwargs, and assign them a list / dictionary type. diff --git a/duchain/declarations/classdeclaration.h b/duchain/declarations/classdeclaration.h index 52684f6c..d93367cb 100644 --- a/duchain/declarations/classdeclaration.h +++ b/duchain/declarations/classdeclaration.h @@ -21,7 +21,7 @@ #define PYTHONCLASSDECLARATION_H #include -#include +#include #include "pythonduchainexport.h" #include "decorator.h" diff --git a/duchain/declarations/decorator.h b/duchain/declarations/decorator.h index 1f4f11a0..32ca761c 100644 --- a/duchain/declarations/decorator.h +++ b/duchain/declarations/decorator.h @@ -22,7 +22,7 @@ #define DECORATOR_H #include -#include +#include using namespace KDevelop; diff --git a/duchain/declarations/functiondeclaration.h b/duchain/declarations/functiondeclaration.h index 39082e2d..ba0ce2fb 100644 --- a/duchain/declarations/functiondeclaration.h +++ b/duchain/declarations/functiondeclaration.h @@ -21,7 +21,7 @@ #define PYTHONFUNCTIONDECLARATION_H #include -#include +#include #include "pythonduchainexport.h" #include "decorator.h" diff --git a/duchain/duchaindebug.cpp b/duchain/duchaindebug.cpp new file mode 100644 index 00000000..f31df9ae --- /dev/null +++ b/duchain/duchaindebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "duchaindebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON_DUCHAIN, "kdev.python.duchain") + + diff --git a/duchain/duchaindebug.h b/duchain/duchaindebug.h new file mode 100644 index 00000000..d407a614 --- /dev/null +++ b/duchain/duchaindebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef DUCHAINDEBUG_H +#define DUCHAINDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON_DUCHAIN) + +#endif + diff --git a/duchain/dumpchain.cpp b/duchain/dumpchain.cpp index 230b84d0..a378bde5 100644 --- a/duchain/dumpchain.cpp +++ b/duchain/dumpchain.cpp @@ -30,6 +30,9 @@ #include #include +#include +#include "duchaindebug.h" + using namespace KDevelop; namespace Python { @@ -44,18 +47,18 @@ void DumpChain::dump( DUContext * context, bool imported ) { if( !context ) return; - kDebug() << QString( indent*2, ' ' ) << (imported ? "==import==> Context " : "New Context ") << context->scopeIdentifier(true) << context->transformFromLocalRevision(context->range()).textRange() << " " << context << " " << (dynamic_cast(context) ? "top-context" : ""); + qCDebug(KDEV_PYTHON_DUCHAIN) << QString( indent*2, ' ' ) << (imported ? "==import==> Context " : "New Context ") << context->scopeIdentifier(true) << context->transformFromLocalRevision(context->range()) << " " << context << " " << (dynamic_cast(context) ? "top-context" : ""); if (!imported) { foreach (Declaration* dec, context->localDeclarations()) { - kDebug() << QString( (indent+1)*2, ' ' ) << "Declaration: " << dec->toString() << " [" << dec->qualifiedIdentifier() << "] "<< dec << "(internal ctx" << dec->internalContext() << ")" << context->transformFromLocalRevision(dec->range()).textRange() << ", "<< ( dec->isDefinition() ? "definition, " : "declaration, " ) << dec->uses().count() << "use(s)"; + qCDebug(KDEV_PYTHON_DUCHAIN) << QString( (indent+1)*2, ' ' ) << "Declaration: " << dec->toString() << " [" << dec->qualifiedIdentifier() << "] "<< dec << "(internal ctx" << dec->internalContext() << ")" << context->transformFromLocalRevision(dec->range()) << ", "<< ( dec->isDefinition() ? "definition, " : "declaration, " ) << dec->uses().count() << "use(s)"; for( QMap >::const_iterator it = dec->uses().constBegin(); it != dec->uses().constEnd(); ++it ) { - kDebug() << QString((indent+1)*2, ' ') << "File:" << it.key().str(); + qCDebug(KDEV_PYTHON_DUCHAIN) << QString((indent+1)*2, ' ') << "File:" << it.key().str(); foreach(const RangeInRevision& r, it.value()) { - kDebug() << QString((indent+2)*2, ' ') << "Use:" << context->transformFromLocalRevision(r).textRange(); + qCDebug(KDEV_PYTHON_DUCHAIN) << QString((indent+2)*2, ' ') << "Use:" << context->transformFromLocalRevision(r); } } } diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp index 86b8d122..308c17c9 100644 --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -37,6 +37,9 @@ #include #include +#include +#include "duchaindebug.h" + #include #include @@ -184,7 +187,7 @@ void ExpressionVisitor::visitCall(CallAst* node) } else { if ( actualDeclaration ) { - kDebug() << "Declaraton is not a class or function declaration"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Declaraton is not a class or function declaration"; } return encounterUnknown(); } @@ -194,7 +197,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f { AbstractType::Ptr type; Declaration* useDeclaration = nullptr; - if ( isConstructor and classDecl ) { + if ( isConstructor && classDecl ) { type = classDecl->abstractType(); useDeclaration = classDecl; } @@ -223,7 +226,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f }; QHash< QString, std::function > knownDecoratorHints; - kDebug() << "Got function declaration with decorators, checking for list content type..."; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Got function declaration with decorators, checking for list content type..."; knownDecoratorHints["getsType"] = [&](QStringList /*arguments*/, QString /*currentHint*/) { if ( node->function->astType != Ast::AttributeAstType ) { return false; @@ -232,7 +235,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f // when calling foo.bar[3].baz.iteritems(), find the type of "foo.bar[3].baz" baseTypeVisitor.visitNode(static_cast(node->function)->value); if ( auto t = baseTypeVisitor.lastType().cast() ) { - kDebug() << "Found container, using type"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found container, using type"; AbstractType::Ptr newType = t->contentType().abstractType(); encounter(newType, DeclarationPointer(useDeclaration)); return true; @@ -249,7 +252,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f baseTypeVisitor.visitNode(static_cast(node->function)->value); DUChainWriteLocker lock; if ( auto t = baseTypeVisitor.lastType().cast() ) { - kDebug() << "Got container:" << t->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Got container:" << t->toString(); auto newType = typeObjectForIntegralType("list", context()); if ( ! newType ) { return false; @@ -286,7 +289,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f }; knownDecoratorHints["getsListOfBoth"] = [&](QStringList /*arguments*/, QString /*currentHint*/) { - kDebug() << "Got getsListOfBoth decorator, checking container"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Got getsListOfBoth decorator, checking container"; if ( node->function->astType != Ast::AttributeAstType ) { return false; } @@ -295,7 +298,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f baseTypeVisitor.visitNode(static_cast(node->function)->value); DUChainWriteLocker lock; if ( auto t = baseTypeVisitor.lastType().cast() ) { - kDebug() << "Got container:" << t->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Got container:" << t->toString(); auto resultingType = listOfTuples(t->keyType().abstractType(), t->contentType().abstractType()); encounter(resultingType, DeclarationPointer(useDeclaration)); return true; @@ -305,7 +308,7 @@ void ExpressionVisitor::checkForDecorators(CallAst* node, FunctionDeclaration* f knownDecoratorHints["returnContentEqualsContentOf"] = [&](QStringList arguments, QString /*currentHint*/) { int argNum = ! arguments.isEmpty() ? arguments.at(0).toInt() : 0; - kDebug() << "Found argument dependent decorator, checking argument type" << argNum; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found argument dependent decorator, checking argument type" << argNum; if ( argNum >= node->arguments.length() ) { return false; } @@ -436,7 +439,7 @@ void ExpressionVisitor::visitList(ListAst* node) } else { encounterUnknown(); - kWarning() << " [ !!! ] did not get a typetrack container object when expecting one! Fix code / setup."; + qCWarning(KDEV_PYTHON_DUCHAIN) << " [ !!! ] did not get a typetrack container object when expecting one! Fix code / setup."; } encounter(AbstractType::Ptr::staticCast(type)); } @@ -525,7 +528,7 @@ void ExpressionVisitor::visitTuple(TupleAst* node) { encounter(AbstractType::Ptr::staticCast(type)); } else { - kWarning() << "tuple type object is not available"; + qCWarning(KDEV_PYTHON_DUCHAIN) << "tuple type object is not available"; return encounterUnknown(); } } @@ -669,10 +672,13 @@ AbstractType::Ptr ExpressionVisitor::fromBinaryOperator(AbstractType::Ptr lhs, A } auto operatorFunctionType = func->type(); DUChainReadLocker lock; - auto object_decl = Helper::getDocumentationFileContext()->findDeclarations(QualifiedIdentifier("object")); - if ( ! object_decl.isEmpty() && object_decl.first()->internalContext() == func->context() ) { - // if the operator is only declared in object(), do not include its type (which is void). - return AbstractType::Ptr(); + auto context = Helper::getDocumentationFileContext(); + if ( context ) { + auto object_decl = context->findDeclarations(QualifiedIdentifier("object")); + if ( ! object_decl.isEmpty() && object_decl.first()->internalContext() == func->context() ) { + // if the operator is only declared in object(), do not include its type (which is void). + return AbstractType::Ptr(); + } } return operatorFunctionType ? operatorFunctionType->returnType() : AbstractType::Ptr(); }; diff --git a/duchain/helpers.cpp b/duchain/helpers.cpp index 4461cdb9..cea55db8 100644 --- a/duchain/helpers.cpp +++ b/duchain/helpers.cpp @@ -20,10 +20,11 @@ #include "helpers.h" #include -#include -#include -#include #include +#include + +#include +#include "duchaindebug.h" #include #include @@ -39,6 +40,10 @@ #include #include #include +#include +#include + +#include #include @@ -53,12 +58,14 @@ using namespace KDevelop; namespace Python { -QList Helper::cachedSearchPaths; +QList Helper::cachedSearchPaths; +QList Helper::cachedCustomIncludes; QStringList Helper::dataDirs; QString Helper::documentationFile; DUChainPointer Helper::documentationFileContext = DUChainPointer(0); QStringList Helper::correctionFileDirs; QString Helper::localCorrectionFileDir; +QMutex Helper::cacheMutex; void Helper::scheduleDependency(const IndexedString& dependency, int betterThanPriority) { @@ -87,13 +94,15 @@ void Helper::scheduleDependency(const IndexedString& dependency, int betterThanP IndexedDeclaration Helper::declarationUnderCursor(bool allowUse) { KDevelop::IDocument* doc = ICore::self()->documentController()->activeDocument(); - if ( doc && doc->textDocument() && doc->textDocument()->activeView() ) { + const auto view = static_cast(ICore::self()->partController())->activeView(); + if ( doc && doc->textDocument() && view ) { DUChainReadLocker lock; + const auto cursor = view->cursorPosition(); if ( allowUse ) { - return DUChainUtils::itemUnderCursor(doc->url(), SimpleCursor(doc->textDocument()->activeView()->cursorPosition())); + return DUChainUtils::itemUnderCursor(doc->url(), cursor); } else { - return DUChainUtils::declarationInLine(SimpleCursor(doc->textDocument()->activeView()->cursorPosition()), DUChainUtils::standardContextForUrl(doc->url())); + return DUChainUtils::declarationInLine(cursor, DUChainUtils::standardContextForUrl(doc->url())); } } @@ -142,14 +151,14 @@ AbstractType::Ptr Helper::extractTypeHints(AbstractType::Ptr type, TopDUContext* } else if ( UnsureType::Ptr unsure = type.cast() ) { int len = unsure->typesSize(); - for ( int i = 0; i < len and i < maxHints; i++ ) { + for ( int i = 0; i < len && i < maxHints; i++ ) { if ( HintedType::Ptr hinted = unsure->types()[i].abstractType().cast() ) { if ( hinted->isValid(current) ) { - kDebug() << "Adding type hint (multi): " << hinted->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Adding type hint (multi): " << hinted->toString(); result->addType(hinted->indexed()); } else { - kDebug() << "Discarding type hint (multi): " << hinted->toString(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Discarding type hint (multi): " << hinted->toString(); maxHints += 1; } } @@ -247,7 +256,7 @@ Declaration* Helper::declarationForName(const QualifiedIdentifier& identifier, c QList importedLocalDeclarations; { DUChainReadLocker lock(DUChain::lock()); - if ( context.data() == context->topContext() and nodeRange.isValid() ) { + if ( context.data() == context->topContext() && nodeRange.isValid() ) { declarations = context->topContext()->findDeclarations(identifier, nodeRange.end); } else { @@ -266,7 +275,7 @@ Declaration* Helper::declarationForName(const QualifiedIdentifier& identifier, c do { declaration = importedLocalDeclarations.last(); importedLocalDeclarations.pop_back(); - if ( not declaration or declaration->context()->type() == DUContext::Class ) { + if ( !declaration || declaration->context()->type() == DUContext::Class ) { declaration = 0; } if ( importedLocalDeclarations.isEmpty() ) { @@ -294,7 +303,7 @@ QList< DUContext* > Helper::internalContextsForClass(StructureType::Ptr klassTyp ClassDeclaration* klass = dynamic_cast(decl); if ( klass ) { FOREACH_FUNCTION ( const BaseClassInstance& base, klass->baseClasses ) { - if ( flags == PublicOnly and base.access == KDevelop::Declaration::Private ) { + if ( flags == PublicOnly && base.access == KDevelop::Declaration::Private ) { continue; } StructureType::Ptr baseClassType = base.baseClass.type(); @@ -320,15 +329,14 @@ Declaration* Helper::resolveAliasDeclaration(Declaration* decl) QStringList Helper::getDataDirs() { if ( Helper::dataDirs.isEmpty() ) { - KStandardDirs d; - Helper::dataDirs = d.findDirs("data", "kdevpythonsupport/documentation_files"); + Helper::dataDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kdevpythonsupport/documentation_files",QStandardPaths::LocateDirectory); } return Helper::dataDirs; } QString Helper::getDocumentationFile() { if ( Helper::documentationFile.isNull() ) { - Helper::documentationFile = KStandardDirs::locate("data", "kdevpythonsupport/documentation_files/builtindocumentation.py"); + Helper::documentationFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevpythonsupport/documentation_files/builtindocumentation.py"); } return Helper::documentationFile; } @@ -340,72 +348,73 @@ ReferencedTopDUContext Helper::getDocumentationFileContext() } else { DUChainReadLocker lock; - ReferencedTopDUContext ctx = ReferencedTopDUContext(DUChain::self()->chainForDocument(Helper::getDocumentationFile())); + qDebug() << "URL:" << Helper::getDocumentationFile(); + auto file = IndexedString(Helper::getDocumentationFile()); + ReferencedTopDUContext ctx = ReferencedTopDUContext(DUChain::self()->chainForDocument(file)); Helper::documentationFileContext = DUChainPointer(ctx.data()); return ctx; } return ReferencedTopDUContext(0); // c++... } -KUrl Helper::getCorrectionFile(KUrl document) +QUrl Helper::getCorrectionFile(const QUrl& document) { if ( Helper::correctionFileDirs.isEmpty() ) { - KStandardDirs d; - Helper::correctionFileDirs = d.findDirs("data", "kdevpythonsupport/correction_files/"); + Helper::correctionFileDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kdevpythonsupport/correction_files/", QStandardPaths::LocateDirectory); } foreach (QString correctionFileDir, correctionFileDirs) { - foreach ( const KUrl& basePath, Helper::getSearchPaths(KUrl()) ) { + foreach ( const QUrl& basePath, Helper::getSearchPaths(QUrl()) ) { if ( ! basePath.isParentOf(document) ) { continue; } - QString path = KUrl::relativePath(basePath.path(), document.path()); - KUrl absolutePath(correctionFileDir + path); - absolutePath.cleanPath(); + QString path = basePath.resolved(document).path(); + auto absolutePath = QUrl::fromLocalFile(correctionFileDir + path); + // TODO QUrl: cleanPath? if ( QFile::exists(absolutePath.path()) ) { return absolutePath; } } } - return KUrl(); + return {}; } -KUrl Helper::getLocalCorrectionFile(KUrl document) +QUrl Helper::getLocalCorrectionFile(const QUrl& document) { if ( Helper::localCorrectionFileDir.isNull() ) { - Helper::localCorrectionFileDir = KStandardDirs::locateLocal("data", "kdevpythonsupport/correction_files/"); + Helper::localCorrectionFileDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kdevpythonsupport/correction_files/"; } - KUrl absolutePath; - foreach ( const KUrl& basePath, Helper::getSearchPaths(KUrl()) ) { + auto absolutePath = QUrl(); + foreach ( const auto& basePath, Helper::getSearchPaths({}) ) { if ( ! basePath.isParentOf(document) ) { continue; } - QString path = KUrl::relativePath(basePath.path(), document.path()); - absolutePath = KUrl(Helper::localCorrectionFileDir + path); - absolutePath.cleanPath(); - + auto path = QDir(basePath.path()).relativeFilePath(document.path()); + absolutePath = Helper::localCorrectionFileDir + path; break; } return absolutePath; } -QList Helper::getSearchPaths(KUrl workingOnDocument) +QList Helper::getSearchPaths(const QUrl& workingOnDocument) { - QList searchPaths; + QMutexLocker lock(&Helper::cacheMutex); + QList searchPaths; // search in the projects, as they're packages and likely to be installed or added to PYTHONPATH later + // and also add custom include paths that are defined in the projects foreach (IProject* project, ICore::self()->projectController()->projects() ) { - searchPaths.append(KUrl(project->folder().url())); + searchPaths.append(project->path().path()); } + searchPaths.append(cachedCustomIncludes); foreach ( const QString& path, getDataDirs() ) { - searchPaths.append(KUrl(path)); + searchPaths.append(QUrl::fromLocalFile(path)); } if ( cachedSearchPaths.isEmpty() ) { - KStandardDirs d; - kDebug() << "*** Gathering search paths..."; + qCDebug(KDEV_PYTHON_DUCHAIN) << "*** Gathering search paths..."; QStringList getpath; getpath << "-c" << "import sys; sys.stdout.write(':'.join(sys.path))"; @@ -422,27 +431,27 @@ QList Helper::getSearchPaths(KUrl workingOnDocument) } } else { - kWarning() << "Could not get search paths! Defaulting to stupid stuff."; - searchPaths.append(KUrl("/usr/lib/python2.7")); - searchPaths.append(KUrl("/usr/lib/python2.7/site-packages")); + qCWarning(KDEV_PYTHON_DUCHAIN) << "Could not get search paths! Defaulting to stupid stuff."; + searchPaths.append(QUrl::fromLocalFile("/usr/lib/python2.7")); + searchPaths.append(QUrl::fromLocalFile("/usr/lib/python2.7/site-packages")); QString path = qgetenv("PYTHONPATH"); QStringList paths = path.split(':'); foreach ( const QString& path, paths ) { cachedSearchPaths.append(path); } } - kDebug() << " *** Done. Got search paths: " << cachedSearchPaths; + qCDebug(KDEV_PYTHON_DUCHAIN) << " *** Done. Got search paths: " << cachedSearchPaths; } else { - kDebug() << " --- Search paths from cache: " << cachedSearchPaths; + qCDebug(KDEV_PYTHON_DUCHAIN) << " --- Search paths from cache: " << cachedSearchPaths; } searchPaths.append(cachedSearchPaths); - const QString& currentDir = workingOnDocument.directory(KUrl::IgnoreTrailingSlash); - if ( ! currentDir.isEmpty() ) { + auto dir = workingOnDocument.adjusted(QUrl::RemoveFilename); + if ( ! dir.isEmpty() ) { // search in the current packages - searchPaths.append(KUrl(currentDir)); + searchPaths.append(dir); } return searchPaths; @@ -483,7 +492,6 @@ AbstractType::Ptr Helper::contentOfIterable(const AbstractType::Ptr iterable) AbstractType::Ptr Helper::mergeTypes(AbstractType::Ptr type, const AbstractType::Ptr newType) { UnsureType::Ptr ret; - ret.count(); return TypeUtils::mergeTypes(type, newType); } diff --git a/duchain/helpers.h b/duchain/helpers.h index d93af3ed..547c5633 100644 --- a/duchain/helpers.h +++ b/duchain/helpers.h @@ -29,15 +29,12 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include @@ -53,7 +50,7 @@ namespace Python { class KDEVPYTHONDUCHAIN_EXPORT Helper { public: /** get search paths for python files **/ - static QList getSearchPaths(KUrl workingOnDocument); + static QList getSearchPaths(const QUrl& workingOnDocument); static QStringList dataDirs; static QString documentationFile; static QStringList correctionFileDirs; @@ -64,10 +61,12 @@ class KDEVPYTHONDUCHAIN_EXPORT Helper { static QString getDocumentationFile(); static ReferencedTopDUContext getDocumentationFileContext(); - static KUrl getCorrectionFile(KUrl document); - static KUrl getLocalCorrectionFile(KUrl document); + static QUrl getCorrectionFile(const QUrl& document); + static QUrl getLocalCorrectionFile(const QUrl& document); - static QList cachedSearchPaths; + static QMutex cacheMutex; + static QList cachedSearchPaths; + static QList cachedCustomIncludes; static AbstractType::Ptr extractTypeHints(AbstractType::Ptr type, TopDUContext* current); diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 980436b9..24660c3f 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -57,7 +57,7 @@ void DeclarationNavigationContext::htmlIdentifiedType(AbstractType::Ptr type, co QString contentType; if ( map ) { if ( auto key = map->keyType().abstractType() ) { - IdentifiedType* identifiedKey = dynamic_cast(key.unsafeData()); + IdentifiedType* identifiedKey = dynamic_cast(key.data()); if ( identifiedKey ) { contentType.append(getLink(key->toString(), DeclarationPointer( identifiedKey->declaration(m_topContext.data())), @@ -71,7 +71,7 @@ void DeclarationNavigationContext::htmlIdentifiedType(AbstractType::Ptr type, co } } if ( AbstractType::Ptr contents = t->contentType().abstractType() ) { - IdentifiedType* identifiedContent = dynamic_cast(contents.unsafeData()); + IdentifiedType* identifiedContent = dynamic_cast(contents.data()); if ( identifiedContent ) { contentType.append(getLink(contents->toString(), DeclarationPointer( identifiedContent->declaration(m_topContext.data())), diff --git a/duchain/pythonduchainexport.h b/duchain/pythonduchainexport.h deleted file mode 100644 index 1dc33dca..00000000 --- a/duchain/pythonduchainexport.h +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2007 Andreas Pakulat * - * Copyright 2006 Matt Rogers * - * Copyright 2004 Jaroslaw Staniek * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License as * - * published by the Free Software Foundation; either version 2 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef PYTHONDUCHAINEXPORT_H -#define PYTHONDUCHAINEXPORT_H - -/* needed for KDE_EXPORT macros */ -#include - - -#ifndef KDEVPYTHONDUCHAIN_EXPORT -# ifdef MAKE_KDEV4PYTHONDUCHAIN_LIB -# define KDEVPYTHONDUCHAIN_EXPORT KDE_EXPORT -# else -# define KDEVPYTHONDUCHAIN_EXPORT KDE_IMPORT -# endif -#endif - -#endif - -//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle; diff --git a/duchain/pythonducontext.cpp b/duchain/pythonducontext.cpp index 23ec0a24..dfceb453 100644 --- a/duchain/pythonducontext.cpp +++ b/duchain/pythonducontext.cpp @@ -26,6 +26,9 @@ #include "navigation/navigationwidget.h" +#include +#include "duchaindebug.h" + using namespace KDevelop; namespace Python { @@ -37,7 +40,7 @@ REGISTER_DUCHAIN_ITEM_WITH_DATA(PythonNormalDUContext, DUContextData); template<> QWidget* PythonTopDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { if ( ! decl ) { - kDebug() << "no declaration, not returning navigationwidget"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "no declaration, not returning navigationwidget"; return 0; } return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); @@ -46,7 +49,7 @@ QWidget* PythonTopDUContext::createNavigationWidget(Declaration* decl, TopDUCont template<> QWidget* PythonNormalDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const { if ( ! decl ) { - kDebug() << "no declaration, not returning navigationwidget"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "no declaration, not returning navigationwidget"; return 0; } return new NavigationWidget(DeclarationPointer(decl), TopDUContextPointer(topContext), htmlPrefix, htmlSuffix); diff --git a/duchain/tests/CMakeLists.txt b/duchain/tests/CMakeLists.txt index 7d892d0c..59b3f118 100644 --- a/duchain/tests/CMakeLists.txt +++ b/duchain/tests/CMakeLists.txt @@ -1,21 +1,33 @@ -automoc4(pyduchaintest waitforupdate.cpp) -kde4_add_unit_test(pyduchaintest pyduchaintest.cpp) -kde4_add_unit_test(duchainbench duchainbench.cpp) +set(pyduchaintest_SRCS + pyduchaintest.cpp + ../duchaindebug.cpp) + +ecm_add_test(${pyduchaintest_SRCS} + TEST_NAME pyduchaintest) + +set(duchainbench_SRCS + duchainbench.cpp + ../duchaindebug.cpp) + +ecm_add_test(${duchainbench_SRCS} + TEST_NAME duchainbench) add_definitions(-DDUCHAIN_PY_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}") target_link_libraries(pyduchaintest - kdev4pythonduchain - kdev4pythonparser - ${kdev4pythonparser_LIBRARIES} - ${QT_QTTEST_LIBRARY} - ${KDEVPLATFORM_TESTS_LIBRARIES} + kdevpythonduchain + kdevpythonparser + ${kdevpythonparser_LIBRARIES} + Qt5::Test + KDev::Tests + KF5::KDELibs4Support ) target_link_libraries(duchainbench - kdev4pythonduchain - kdev4pythonparser - ${kdev4pythonparser_LIBRARIES} - ${QT_QTTEST_LIBRARY} - ${KDEVPLATFORM_TESTS_LIBRARIES} + kdevpythonduchain + kdevpythonparser + ${kdevpythonparser_LIBRARIES} + Qt5::Test + KDev::Tests + KF5::KDELibs4Support ) diff --git a/duchain/tests/duchainbench.cpp b/duchain/tests/duchainbench.cpp index 813614f5..27e33256 100644 --- a/duchain/tests/duchainbench.cpp +++ b/duchain/tests/duchainbench.cpp @@ -21,6 +21,9 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ +#include +#include "duchaindebug.h" + #include "duchainbench.h" #include @@ -29,9 +32,9 @@ #include #include #include -#include #include #include +#include #include "parsesession.h" @@ -48,7 +51,7 @@ DUChainBench::DUChainBench(QObject* parent): QObject(parent) qFatal("Failed to create temp directory, Aboring"); } testDir = QDir(QString(tempdirname)); - kDebug() << "tempdirname" << tempdirname; + qCDebug(KDEV_PYTHON_DUCHAIN) << "tempdirname" << tempdirname; initShell(); } @@ -60,10 +63,8 @@ void DUChainBench::initShell() TestCore* core = new TestCore(); core->initialize(KDevelop::Core::NoUi); - KUrl doc_url = KUrl(KStandardDirs::locate("data", "kdevpythonsupport/documentation_files/builtindocumentation.py")); - doc_url.cleanPath(KUrl::SimplifyDirSeparators); - - kDebug() << doc_url; + auto doc_url = QDir::cleanPath(QStandardPaths::locate(QStandardPaths::GenericDataLocation, + "kdevpythonsupport/documentation_files/builtindocumentation.py")); DUChain::self()->updateContextForUrl(IndexedString(doc_url), KDevelop::TopDUContext::AllDeclarationsContextsAndUses); ICore::self()->languageController()->backgroundParser()->parseDocuments(); @@ -78,7 +79,7 @@ ReferencedTopDUContext DUChainBench::parse(const QString& code) TestFile* testfile = new TestFile(code + "\n", "py", 0, testDir.absolutePath().append("/")); createdFiles << testfile; testfile->parse((TopDUContext::Features) (TopDUContext::ForceUpdate | TopDUContext::AST) ); - testfile->waitForParsed(500); + testfile->waitForParsed(2000); if ( testfile->isReady() ) { m_ast = static_cast(testfile->topContext()->ast().data())->ast; @@ -135,4 +136,4 @@ void DUChainBench::benchSimpleStatements() QBENCHMARK { parse(code); } -} \ No newline at end of file +} diff --git a/duchain/tests/duchainbench.h b/duchain/tests/duchainbench.h index 1a2e6a99..730a694c 100644 --- a/duchain/tests/duchainbench.h +++ b/duchain/tests/duchainbench.h @@ -21,12 +21,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ -#ifndef DUCHAINBENCH_H -#define DUCHAINBENCH_H +#ifndef PY_DUCHAINBENCH_H +#define PY_DUCHAINBENCH_H #include #include "ast.h" -#include +#include #include #include diff --git a/duchain/tests/pyduchaintest.cpp b/duchain/tests/pyduchaintest.cpp index 173a5cbd..a31d6734 100644 --- a/duchain/tests/pyduchaintest.cpp +++ b/duchain/tests/pyduchaintest.cpp @@ -22,6 +22,9 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *****************************************************************************/ +#include +#include "duchaindebug.h" + #include "pyduchaintest.h" #include @@ -32,8 +35,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -42,6 +44,8 @@ #include #include +#include + #include "parsesession.h" #include "pythoneditorintegrator.h" #include "declarationbuilder.h" @@ -71,7 +75,7 @@ PyDUChainTest::PyDUChainTest(QObject* parent): QObject(parent) qFatal("Failed to create temp directory, Aboring"); } testDir = QDir(QString(tempdirname)); - kDebug() << "tempdirname" << tempdirname; + qCDebug(KDEV_PYTHON_DUCHAIN) << "tempdirname" << tempdirname; QByteArray pythonpath = qgetenv("PYTHONPATH"); pythonpath.prepend(":").prepend(assetsDir.absolutePath().toAscii()); @@ -97,35 +101,34 @@ void PyDUChainTest::init() { QString currentTest = QString(QTest::currentTestFunction()); if (lastTest == currentTest) { - kDebug() << "Already prepared assets for " << currentTest << ", skipping"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Already prepared assets for " << currentTest << ", skipping"; return; } else { lastTest = currentTest; } - kDebug() << "Preparing assets for test " << currentTest; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Preparing assets for test " << currentTest; QDir assetModuleDir = QDir(assetsDir.absolutePath()); if (!assetModuleDir.cd(currentTest)) { - kDebug() << "Asset directory " << currentTest + qCDebug(KDEV_PYTHON_DUCHAIN) << "Asset directory " << currentTest << " does not exist under " << assetModuleDir.absolutePath() << ". Skipping it."; return; } - kDebug() << "Searching for python files in " << assetModuleDir.absolutePath(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "Searching for python files in " << assetModuleDir.absolutePath(); QList foundfiles = FindPyFiles(assetModuleDir); - QString correctionFileDir = KStandardDirs::locate("data", "kdevpythonsupport/correction_files/"); - KUrl correctionFileUrl = KUrl(correctionFileDir + "testCorrectionFiles/example.py"); - correctionFileUrl.cleanPath(); + QString correctionFileDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevpythonsupport/correction_files", QStandardPaths::LocateDirectory); + auto correctionFileUrl = QUrl(QDir::cleanPath(correctionFileDir + "/testCorrectionFiles/example.py")); foundfiles.prepend(correctionFileUrl.path()); for ( int i = 0; i < 2; i++ ) { // Parse each file twice, to ensure no parsing-order related bugs appear. // Such bugs will need separate unit tests and should not influence these. foreach(const QString filename, foundfiles) { - kDebug() << "Parsing asset: " << filename; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Parsing asset: " << filename; DUChain::self()->updateContextForUrl(IndexedString(filename), KDevelop::TopDUContext::AllDeclarationsContextsAndUses); ICore::self()->languageController()->backgroundParser()->parseDocuments(); } @@ -146,10 +149,10 @@ void PyDUChainTest::initShell() TestCore* core = new TestCore(); core->initialize(KDevelop::Core::NoUi); - KUrl doc_url = KUrl(KStandardDirs::locate("data", "kdevpythonsupport/documentation_files/builtindocumentation.py")); - doc_url.cleanPath(KUrl::SimplifyDirSeparators); + auto doc_url = QStandardPaths::locate(QStandardPaths::GenericDataLocation, + "kdevpythonsupport/documentation_files/builtindocumentation.py"); - kDebug() << doc_url; + qCDebug(KDEV_PYTHON_DUCHAIN) << doc_url; DUChain::self()->updateContextForUrl(IndexedString(doc_url), KDevelop::TopDUContext::AllDeclarationsContextsAndUses); ICore::self()->languageController()->backgroundParser()->parseDocuments(); @@ -165,9 +168,10 @@ ReferencedTopDUContext PyDUChainTest::parse(const QString& code) createdFiles << testfile; testfile->parse((TopDUContext::Features) (TopDUContext::ForceUpdate | TopDUContext::AST) ); - testfile->waitForParsed(500); + testfile->waitForParsed(2000); if ( testfile->isReady() ) { + Q_ASSERT(testfile->topContext()); m_ast = static_cast(testfile->topContext()->ast().data())->ast; return testfile->topContext(); } @@ -402,7 +406,7 @@ void PyDUChainTest::testClassVariables() if ( useIndex != -1 ) { QVERIFY(useIndex < c->usesCount()); const Use* u = &(c->uses()[useIndex]); - QVERIFY(not u->usedDeclaration(c->topContext())); + QVERIFY(!u->usedDeclaration(c->topContext())); } } @@ -566,7 +570,7 @@ void PyDUChainTest::testSimple() foreach(Declaration* d, declarations) { usesCount += d->uses().size(); - QVERIFY(!d->abstractType().isNull()); + QVERIFY(d->abstractType()); } QCOMPARE(usesCount, uses); @@ -588,10 +592,10 @@ void PyDUChainTest::testSimple_data() class AttributeRangeTestVisitor : public AstDefaultVisitor { public: bool found; - SimpleRange searchingForRange; + KTextEditor::Range searchingForRange; QString searchingForIdentifier; virtual void visitAttribute(AttributeAst* node) { - SimpleRange r(0, node->startCol, 0, node->endCol); + auto r = KTextEditor::Range(0, node->startCol, 0, node->endCol); qDebug() << "Found attr: " << r << node->attribute->value << ", looking for: " << searchingForRange << searchingForIdentifier; if ( r == searchingForRange && node->attribute->value == searchingForIdentifier ) { found = true; @@ -600,7 +604,7 @@ class AttributeRangeTestVisitor : public AstDefaultVisitor { AstDefaultVisitor::visitAttribute(node); } virtual void visitFunctionDefinition(FunctionDefinitionAst* node) { - SimpleRange r(0, node->name->startCol, 0, node->name->endCol); + auto r = KTextEditor::Range(0, node->name->startCol, 0, node->name->endCol); qDebug() << "Found func: " << r << node->name->value << ", looking for: " << searchingForRange << searchingForIdentifier; qDebug() << node->arguments->vararg << node->arguments->kwarg; if ( r == searchingForRange && node->name->value == searchingForIdentifier ) { @@ -608,7 +612,7 @@ class AttributeRangeTestVisitor : public AstDefaultVisitor { return; } if ( node->arguments->vararg ) { - SimpleRange r(0, node->arguments->vararg->startCol, 0, node->arguments->vararg->startCol+node->arguments->vararg->argumentName->value.length()); + auto r = KTextEditor::Range(0, node->arguments->vararg->startCol, 0, node->arguments->vararg->startCol+node->arguments->vararg->argumentName->value.length()); qDebug() << "Found vararg: " << node->arguments->vararg->argumentName->value << r; if ( r == searchingForRange && node->arguments->vararg->argumentName->value == searchingForIdentifier ) { found = true; @@ -616,7 +620,7 @@ class AttributeRangeTestVisitor : public AstDefaultVisitor { } } if ( node->arguments->kwarg ) { - SimpleRange r(0, node->arguments->kwarg->startCol, 0, node->arguments->kwarg->startCol+node->arguments->kwarg->argumentName->value.length()); + auto r = KTextEditor::Range(0, node->arguments->kwarg->startCol, 0, node->arguments->kwarg->startCol+node->arguments->kwarg->argumentName->value.length()); qDebug() << "Found kwarg: " << node->arguments->kwarg->argumentName->value << r; if ( r == searchingForRange && node->arguments->kwarg->argumentName->value == searchingForIdentifier ) { found = true; @@ -626,7 +630,7 @@ class AttributeRangeTestVisitor : public AstDefaultVisitor { AstDefaultVisitor::visitFunctionDefinition(node); } virtual void visitClassDefinition(ClassDefinitionAst* node) { - SimpleRange r(0, node->name->startCol, 0, node->name->endCol); + auto r = KTextEditor::Range(0, node->name->startCol, 0, node->name->endCol); qDebug() << "Found cls: " << r << node->name->value << ", looking for: " << searchingForRange << searchingForIdentifier; if ( r == searchingForRange && node->name->value == searchingForIdentifier ) { found = true; @@ -669,7 +673,7 @@ void PyDUChainTest::testRanges() int scol = column_ranges.at(i).split(",")[0].toInt(); int ecol = column_ranges.at(i).split(",")[1].toInt(); QString identifier = column_ranges.at(i).split(",")[2]; - SimpleRange r(0, scol, 0, ecol); + auto r = KTextEditor::Range(0, scol, 0, ecol); AttributeRangeTestVisitor* visitor = new AttributeRangeTestVisitor(); visitor->searchingForRange = r; @@ -714,13 +718,12 @@ class TypeTestVisitor : public AstDefaultVisitor { if ( node->identifier->value != "checkme" ) return; QList decls = ctx->findDeclarations(QualifiedIdentifier(node->identifier->value)); if ( ! decls.length() ) { - kDebug() << "No declaration found for " << node->identifier->value; + qCDebug(KDEV_PYTHON_DUCHAIN) << "No declaration found for " << node->identifier->value; return; } Declaration* d = decls.last(); - kDebug() << "Declaration: " << node->identifier->value << d->type(); QVERIFY(d->abstractType()); - kDebug() << "found: " << node->identifier->value << "is" << d->abstractType()->toString() << "should be" << searchingForType; + qCDebug(KDEV_PYTHON_DUCHAIN) << "found: " << node->identifier->value << "is" << d->abstractType()->toString() << "should be" << searchingForType; if ( d->abstractType()->toString().replace("__kdevpythondocumentation_builtin_", "").startsWith(searchingForType) ) { found = true; return; @@ -920,13 +923,13 @@ void PyDUChainTest::testImportDeclarations() { bool found = false; QString name = expected; QList decls = ctx->allDeclarations(CursorInRevision::invalid(), ctx->topContext(), false); - kDebug() << "FOUND DECLARATIONS:"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "FOUND DECLARATIONS:"; foreach ( const pair& current, decls ) { - kDebug() << current.first->toString() << current.first->identifier().identifier().byteArray() << name; + qCDebug(KDEV_PYTHON_DUCHAIN) << current.first->toString() << current.first->identifier().identifier().byteArray() << name; } foreach ( const pair& current, decls ) { if ( ! ( current.first->identifier().identifier().byteArray() == name ) ) continue; - kDebug() << "Found: " << current.first->toString() << " for " << name; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Found: " << current.first->toString() << " for " << name; AliasDeclaration* isAliased = dynamic_cast(current.first); if ( isAliased && shouldBeAliased ) { found = true; // TODO fixme @@ -1007,7 +1010,7 @@ void PyDUChainTest::testAutocompletionFlickering() lock.lock(); QList

decls2 = ctx2->allDeclarations(CursorInRevision::invalid(), ctx2->topContext()); foreach ( p d2, decls2 ) { - kDebug() << "@1: " << d2.first->toString() << "::" << d2.first->id().hash() << "<>" << declIds.first().hash(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "@1: " << d2.first->toString() << "::" << d2.first->id().hash() << "<>" << declIds.first().hash(); QVERIFY(d2.first->id() == declIds.first()); declIds.removeFirst(); } @@ -1040,7 +1043,7 @@ void PyDUChainTest::testAutocompletionFlickering() decls2 = ctx2->allDeclarations(CursorInRevision::invalid(), ctx2->topContext(), false).first().first->internalContext() ->allDeclarations(CursorInRevision::invalid(), ctx2->topContext()); foreach ( p d2, decls2 ) { - kDebug() << "@2: " << d2.first->toString() << "::" << d2.first->id().hash() << "<>" << declIds.first().hash(); + qCDebug(KDEV_PYTHON_DUCHAIN) << "@2: " << d2.first->toString() << "::" << d2.first->id().hash() << "<>" << declIds.first().hash(); QVERIFY(d2.first->id() == declIds.first()); declIds.removeFirst(); } @@ -1244,7 +1247,6 @@ void PyDUChainTest::testContainerTypes() QList decls = ctx->findDeclarations(QualifiedIdentifier("checkme")); QVERIFY(decls.length() > 0); QVERIFY(decls.first()->abstractType()); - kDebug() << "TEST type is: " << decls.first()->abstractType().unsafeData()->toString(); if ( ! use_type ) { auto type = ListType::Ptr::dynamicCast(decls.first()->abstractType()); QVERIFY(type); diff --git a/duchain/tests/pyduchaintest.h b/duchain/tests/pyduchaintest.h index 1a2ecdff..4b9110d4 100644 --- a/duchain/tests/pyduchaintest.h +++ b/duchain/tests/pyduchaintest.h @@ -27,7 +27,7 @@ #include #include "ast.h" -#include +#include #include #include diff --git a/duchain/typebuilder.cpp b/duchain/typebuilder.cpp index 1d78b428..68c6cef3 100644 --- a/duchain/typebuilder.cpp +++ b/duchain/typebuilder.cpp @@ -23,13 +23,13 @@ #include using namespace KDevelop; -TypeBuilder::TypeBuilder(ParseSession* session, const KUrl &url) +TypeBuilder::TypeBuilder(ParseSession* session, const QUrl& url) : TypeBuilderBase(session, url) { } -TypeBuilder::TypeBuilder(PythonEditorIntegrator * editor, const KUrl &url) - : TypeBuilderBase(editor,url) +TypeBuilder::TypeBuilder(PythonEditorIntegrator * editor, const QUrl& url) + : TypeBuilderBase(editor, url) { } diff --git a/duchain/types/hintedtype.cpp b/duchain/types/hintedtype.cpp index bd1b859f..b2c24b37 100644 --- a/duchain/types/hintedtype.cpp +++ b/duchain/types/hintedtype.cpp @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -26,6 +26,9 @@ #include #include +#include +#include "../duchaindebug.h" + #include using namespace KDevelop; @@ -56,17 +59,17 @@ bool HintedType::isValid(TopDUContext* /*current*/) if ( ! creator ) { return false; } - KDEBUG_BLOCK +// KDEBUG_BLOCK ModificationRevision rev(creator->parsingEnvironmentFile()->modificationRevision()); - kDebug() << "current: " << rev.revision << "; created:" << d_func()->m_modificationRevision.revision; - kDebug() << "current: " << rev.modificationTime << "; created:" << d_func()->m_modificationRevision.modificationTime; + qCDebug(KDEV_PYTHON_DUCHAIN) << "current: " << rev.revision << "; created:" << d_func()->m_modificationRevision.revision; + qCDebug(KDEV_PYTHON_DUCHAIN) << "current: " << rev.modificationTime << "; created:" << d_func()->m_modificationRevision.modificationTime; if ( d_func()->m_modificationRevision < rev ) { - kDebug() << "modification revision mismatch, invalidating"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "modification revision mismatch, invalidating"; return false; } /// This should not be needed any more since 193f52027fb7 // if ( creator == current && d_func()->m_modificationRevision == rev && rev.revision != 0 ) { -// kDebug() << "modification revision exact match, but same context, invalidating"; +// qCDebug(KDEV_PYTHON_DUCHAIN) << "modification revision exact match, but same context, invalidating"; // return false; // } return true; @@ -76,7 +79,7 @@ void HintedType::setCreatedBy(TopDUContext* context, const ModificationRevision& { d_func_dynamic()->m_createdByContext = context->indexed(); d_func_dynamic()->m_modificationRevision = revision; - kDebug() << "new HintedType with modification time: " << d_func()->m_modificationRevision.modificationTime + qCDebug(KDEV_PYTHON_DUCHAIN) << "new HintedType with modification time: " << d_func()->m_modificationRevision.modificationTime << "; " << d_func()->m_modificationRevision.revision; } diff --git a/duchain/types/hintedtype.h b/duchain/types/hintedtype.h index 9e43d97c..75ebb109 100644 --- a/duchain/types/hintedtype.h +++ b/duchain/types/hintedtype.h @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/duchain/types/indexedcontainer.cpp b/duchain/types/indexedcontainer.cpp index 6589e2f6..5759de40 100644 --- a/duchain/types/indexedcontainer.cpp +++ b/duchain/types/indexedcontainer.cpp @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/duchain/types/indexedcontainer.h b/duchain/types/indexedcontainer.h index bb7fe1a0..ad56cf86 100644 --- a/duchain/types/indexedcontainer.h +++ b/duchain/types/indexedcontainer.h @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/duchain/types/unsuretype.cpp b/duchain/types/unsuretype.cpp index 2042d412..3b76a30e 100644 --- a/duchain/types/unsuretype.cpp +++ b/duchain/types/unsuretype.cpp @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -27,6 +27,8 @@ #include #include #include +#include +#include "../duchaindebug.h" namespace Python { @@ -70,7 +72,7 @@ QString UnsureType::toString() const QList encountered; foreach ( AbstractType::Ptr type, typesRecursive() ) { if ( ! type ) { - kWarning() << "Invalid type: " << type.unsafeData(); + qCWarning(KDEV_PYTHON_DUCHAIN) << "Invalid type: " << type.data(); continue; } diff --git a/duchain/types/unsuretype.h b/duchain/types/unsuretype.h index b5562613..0a2d15de 100644 --- a/duchain/types/unsuretype.h +++ b/duchain/types/unsuretype.h @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -32,13 +32,14 @@ #include #include #include +#include namespace Python { class KDEVPYTHONDUCHAIN_EXPORT UnsureType : public KDevelop::UnsureType { public: - typedef TypePtr Ptr; + typedef KDevelop::TypePtr Ptr; UnsureType(); UnsureType(const UnsureType& rhs); diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index d2eb9fa6..636914cd 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -18,7 +18,8 @@ */ #include "usebuilder.h" -#include +#include +#include "duchaindebug.h" #include #include @@ -108,9 +109,9 @@ void UseBuilder::visitName(NameAst* node) void UseBuilder::visitAttribute(AttributeAst* node) { - kDebug() << "VisitAttribute start"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "VisitAttribute start"; UseBuilderBase::visitAttribute(node); - kDebug() << "Visit Attribute base end"; + qCDebug(KDEV_PYTHON_DUCHAIN) << "Visit Attribute base end"; DUContext* context = contextAtOrCurrent(editorFindPositionSafe(node)); ExpressionVisitor v(context); @@ -124,7 +125,7 @@ void UseBuilder::visitAttribute(AttributeAst* node) // this is the declaration, don't build a use for it return; } - if ( ! declaration && v.isConfident() && ( ! v.lastType() or Helper::isUsefulType(v.lastType()) ) ) { + if ( ! declaration && v.isConfident() && ( ! v.lastType() || Helper::isUsefulType(v.lastType()) ) ) { KDevelop::Problem *p = new KDevelop::Problem(); p->setFinalLocation(DocumentRange(currentlyParsedDocument(), useRange.castToSimpleRange())); p->setSource(KDevelop::ProblemData::SemanticAnalysis); diff --git a/kdevpythonsupport.desktop b/kdevpythonsupport.desktop.cmake similarity index 78% rename from kdevpythonsupport.desktop rename to kdevpythonsupport.desktop.cmake index bb45aeed..f5e9a22c 100644 --- a/kdevpythonsupport.desktop +++ b/kdevpythonsupport.desktop.cmake @@ -2,35 +2,20 @@ Encoding=UTF-8 Type=Service Exec=blubb -Comment=Python Language Support (Python 3 version) -Comment[bg]=Поддръжка на езика Python -Comment[bs]=Podrška za Python jezik +Comment=Python Language Support +Comment[ar]=دعم لغة بايثون Comment[ca]=Implementació del llenguatge Python -Comment[ca@valencia]=Implementació del llenguatge Python -Comment[da]=Sprogunderstøttelse for Python Comment[de]=Sprachunterstützung für Python -Comment[el]=Υποστήριξη γλώσσας Python Comment[en_GB]=Python Language Support Comment[es]=Implementación del lenguaje Python -Comment[et]=Pythoni keele toetus Comment[fi]=Python-kielituki Comment[fr]=Prise en charge du langage Python -Comment[ga]=Tacaíocht Python -Comment[gl]=Compatibilidade coa linguaxe Python. -Comment[hne]=पायथन भाखा समर्थन -Comment[hu]=Python nyelvi támogatás Comment[it]=Supporto per il linguaggio Python -Comment[kk]=Python тілін қолдауы -Comment[mr]=पायथोन भाषा समर्थन Comment[nb]=Støtte for Python-språket -Comment[nds]=Ünnerstütten för Python Comment[nl]=Ondersteuning voor de taal Python -Comment[pa]=ਪਾਈਥਨ ਲੈਗੂਇਜ਼ ਸਹਿਯੋਗ Comment[pl]=Obsługa języka Python Comment[pt]=Suporte para a Linguagem Python Comment[pt_BR]=Suporte à linguagem Python -Comment[ro]=Suport pentru limbajul Python -Comment[ru]=Поддержка языка Python Comment[sk]=Podpora jazyka Python Comment[sl]=Podpora jeziku Python Comment[sv]=Stöd för språket Python @@ -38,8 +23,8 @@ Comment[tr]=Python Dil Desteği Comment[uk]=Підтримка мови Python Comment[x-test]=xxPython Language Supportxx Comment[zh_CN]=Python 语言支持 -Comment[zh_TW]=Python 語言支援 -Name=Python Support (Python 3 version) +Name=Python Support +Name[ar]=دعم بايثون Name[bg]=Поддръжка на Python Name[bs]=Python podrška Name[ca]=Implementació de Python @@ -58,6 +43,7 @@ Name[gl]=Compatibilidade con Python Name[hu]=Python-támogatás Name[it]=Supporto per Python Name[kk]=Python қолдауы +Name[ko]=파이썬 지원 Name[mr]=पायथोन समर्थन Name[nb]=Støtte for Python Name[nds]=Python-Ünnerstütten @@ -76,7 +62,8 @@ Name[uk]=Підтримка Python Name[x-test]=xxPython Supportxx Name[zh_CN]=Python 支持 Name[zh_TW]=Python 支援 -GenericName=Python Support (Python 3 version) +GenericName=Python Support +GenericName[ar]=دعم بايثون GenericName[bg]=Поддръжка на Python GenericName[bs]=Python podrška GenericName[ca]=Implementació de Python @@ -96,6 +83,7 @@ GenericName[hne]=पायथन समर्थन GenericName[hu]=Python-támogatás GenericName[it]=Supporto per Python GenericName[kk]=Python қолдауы +GenericName[ko]=파이썬 지원 GenericName[mr]=पायथोन समर्थन GenericName[nb]=Støtte for Python GenericName[nds]=Python-Ünnerstütten @@ -118,10 +106,10 @@ GenericName[zh_TW]=Python 支援 ServiceTypes=KDevelop/Plugin Icon=text-x-python X-KDE-Library=kdevpythonlanguagesupport -X-KDevelop-Version=18 +X-KDevelop-Version=@KDEV_PLUGIN_VERSION@ X-KDevelop-Language=Python X-KDevelop-Args=PYTHON -X-KDevelop-Interfaces=ILanguageSupport,org.kdevelop.ILanguageCheckProvider +X-KDevelop-Interfaces=ILanguageSupport X-KDevelop-SupportedMimeTypes=text/x-python X-KDE-PluginInfo-Name=kdevpythonsupport X-KDevelop-Mode=NoGUI diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index 1058d76f..a48c48ba 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -11,6 +11,7 @@ set(parser_STAT_SRCS astvisitor.cpp astbuilder.cpp cythonsyntaxremover.cpp + parserdebug.cpp ) find_package(PythonLibs 3.4 REQUIRED) @@ -18,17 +19,21 @@ if ( NOT ${PYTHONLIBS_FOUND} OR ${PYTHON_VERSION_MINOR} GREATER 4 ) message(FATAL_ERROR "Python 3.4 with --enable-shared is required to build kdev-python") endif() -include_directories(kdev4pythonparser ${PYTHON_INCLUDE_DIRS}) +include_directories(kdevpythonparser ${PYTHON_INCLUDE_DIRS}) -kde4_add_library( kdev4pythonparser SHARED ${parser_SRCS} ${parser_STAT_SRCS} ) -target_link_libraries(kdev4pythonparser LINK_PRIVATE - ${KDE4_KDECORE_LIBS} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${QT_QTCORE_LIBRARY} +add_library( kdevpythonparser SHARED ${parser_STAT_SRCS} ) + +generate_export_header(kdevpythonparser EXPORT_MACRO_NAME KDEVPYTHONPARSER_EXPORT + EXPORT_FILE_NAME parserexport.h) + +target_link_libraries(kdevpythonparser LINK_PRIVATE + KF5::KDELibs4Support + KDev::Language + KDev::Util + Qt5::Core ${PYTHON_LIBRARY} ) -add_dependencies(kdev4pythonparser parser) -install(TARGETS kdev4pythonparser DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS kdevpythonparser DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(tests) diff --git a/parser/ast.h b/parser/ast.h index 01294d8e..cf8ce3a7 100644 --- a/parser/ast.h +++ b/parser/ast.h @@ -25,14 +25,9 @@ #define PYTHON_AST_H #include -#include #include -#include -#include #include - -#include - +#include #include "parserexport.h" namespace KDevelop @@ -203,8 +198,8 @@ class KDEVPYTHONPARSER_EXPORT Ast return startLine < other->startLine || ( startLine == other->startLine && startCol < other->startCol ); }; - const KDevelop::SimpleRange range() const { - return KDevelop::SimpleRange(startLine, startCol, endLine, endCol); + const KTextEditor::Range range() const { + return KTextEditor::Range(startLine, startCol, endLine, endCol); }; int startCol; diff --git a/parser/astbuilder.cpp b/parser/astbuilder.cpp index e914877f..db08fcfb 100644 --- a/parser/astbuilder.cpp +++ b/parser/astbuilder.cpp @@ -22,15 +22,7 @@ #include "astbuilder.h" #include "ast.h" -#include - #include -#include -#include -#include -#include -#include -#include #include #include #include @@ -43,6 +35,10 @@ #include #include #include +#include + +#include +#include "parserdebug.h" using namespace KDevelop; extern grammar _PyParser_Grammar; @@ -296,21 +292,21 @@ QString PyUnicodeObjectToQString(PyObject* obj) { #endif // windows } -QPair fileHeaderHack(QString& contents, const KUrl& filename) +QPair fileHeaderHack(QString& contents, const QUrl& filename) { IProject* proj = ICore::self()->projectController()->findProjectForUrl(filename); // the file is not in a project, don't apply hack if ( ! proj ) { return QPair(contents, 0); } - const KUrl headerFileUrl = proj->folder().path(KUrl::AddTrailingSlash) + ".kdev_python_header"; + const QUrl headerFileUrl = proj->path().path() + "/.kdev_python_header"; QFile headerFile(headerFileUrl.path()); QString headerFileContents; if ( headerFile.exists() ) { headerFile.open(QIODevice::ReadOnly); headerFileContents = headerFile.readAll(); headerFile.close(); - kDebug() << "Found header file, applying hack"; + qCDebug(KDEV_PYTHON_PARSER) << "Found header file, applying hack"; int insertAt = 0; bool endOfCommentsReached = false; bool commentSignEncountered = false; @@ -320,15 +316,15 @@ QPair fileHeaderHack(QString& contents, const KUrl& filename) int l = contents.length(); do { if ( insertAt >= l ) { - kDebug() << "File consist only of comments, not applying hack"; + qCDebug(KDEV_PYTHON_PARSER) << "File consist only of comments, not applying hack"; return QPair(contents, 0); } if ( contents.at(insertAt) == '#' ) { commentSignEncountered = true; } - if ( not contents.at(insertAt).isSpace() ) { + if ( !contents.at(insertAt).isSpace() ) { // atLineBeginning = false; - if ( not commentSignEncountered ) { + if ( !commentSignEncountered ) { endOfCommentsReached = true; } } @@ -342,12 +338,12 @@ QPair fileHeaderHack(QString& contents, const KUrl& filename) endOfCommentsReached = true; } insertAt += 1; - } while ( not endOfCommentsReached ); - kDebug() << "Inserting contents at char" << lastLineBeginning << "of file"; + } while ( !endOfCommentsReached ); + qCDebug(KDEV_PYTHON_PARSER) << "Inserting contents at char" << lastLineBeginning << "of file"; contents = contents.left(lastLineBeginning) + "\n" + headerFileContents + "\n#\n" + contents.right(contents.length() - lastLineBeginning); - kDebug() << contents; + qCDebug(KDEV_PYTHON_PARSER) << contents; return QPair(contents, - ( headerFileContents.count('\n') + 3 )); } else { @@ -377,7 +373,7 @@ struct PythonInitializer : private QMutexLocker { }; } -CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) +CodeAst::Ptr AstBuilder::parse(const QUrl& filename, QString &contents) { qDebug() << " ====> AST ====> building abstract syntax tree for " << filename.path(); @@ -400,7 +396,7 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) CythonSyntaxRemover cythonSyntaxRemover; if (filename.fileName().endsWith(".pyx", Qt::CaseInsensitive)) { - kDebug() << filename.fileName() << "is probably Cython file."; + qCDebug(KDEV_PYTHON_PARSER) << filename.fileName() << "is probably Cython file."; contents = cythonSyntaxRemover.stripCythonSyntax(contents); } @@ -410,7 +406,7 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) qDebug() << " ====< parse error, trying to fix"; PyErr_Fetch(&exception, &value, &backtrace); - kDebug() << "Error objects: " << exception << value << backtrace; + qCDebug(KDEV_PYTHON_PARSER) << "Error objects: " << exception << value << backtrace; PyObject_Print(value, stderr, Py_PRINT_RAW); PyObject* errorMessage_str = PyTuple_GetItem(value, 0); @@ -419,7 +415,7 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) PyObject_Print(errorMessage_str, stderr, Py_PRINT_RAW); if ( ! errorDetails_tuple ) { - kWarning() << "Error retrieving error message, not displaying, and not doing anything"; + qCWarning(KDEV_PYTHON_PARSER) << "Error retrieving error message, not displaying, and not doing anything"; return CodeAst::Ptr(); } PyObject* linenoobj = PyTuple_GetItem(errorDetails_tuple, 1); @@ -432,10 +428,10 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) int colno = PyLong_AsLong(colnoobj); ProblemPointer p(new Problem()); - SimpleCursor start(lineno + lineOffset, (colno-4 > 0 ? colno-4 : 0)); - SimpleCursor end(lineno + lineOffset, (colno+4 > 4 ? colno+4 : 4)); - SimpleRange range(start, end); - kDebug() << "Problem range: " << range; + KTextEditor::Cursor start(lineno + lineOffset, (colno-4 > 0 ? colno-4 : 0)); + KTextEditor::Cursor end(lineno + lineOffset, (colno+4 > 4 ? colno+4 : 4)); + KTextEditor::Range range(start, end); + qCDebug(KDEV_PYTHON_PARSER) << "Problem range: " << range; DocumentRange location(IndexedString(filename.path()), range); p->setFinalLocation(location); p->setDescription(PyUnicodeObjectToQString(errorMessage_str)); @@ -494,9 +490,9 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) // we can easily fix that by adding in a "pass" statement. However, we want to add that in the next line, if possible // so context ranges for autocompletion stay intact. if ( contents[emptySince] == QChar(':') ) { - kDebug() << indents.length() << emptySinceLine + 1 << indents; + qCDebug(KDEV_PYTHON_PARSER) << indents.length() << emptySinceLine + 1 << indents; if ( indents.length() > emptySinceLine + 1 && indents.at(emptySinceLine) < indents.at(emptySinceLine + 1) ) { - kDebug() << indents.at(emptySinceLine) << indents.at(emptySinceLine + 1); + qCDebug(KDEV_PYTHON_PARSER) << indents.at(emptySinceLine) << indents.at(emptySinceLine + 1); contents.insert(emptyLinesSince + 1 + indents.at(emptyLinesSinceLine), "\tpass#"); } else { @@ -504,7 +500,7 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) } } else if ( indents.length() >= currentLine && currentLine > 0 ) { - kDebug() << indents << currentLine; + qCDebug(KDEV_PYTHON_PARSER) << indents << currentLine; contents[i+1+indents.at(currentLine - 1)] = QChar('#'); contents.insert(i+1+indents.at(currentLine - 1), "pass"); } @@ -517,8 +513,8 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) currentLineBeginning = qMin(contents.length() - 1, currentLineBeginning); errline = qMax(0, qMin(indents.length()-1, errline)); if ( ! syntaxtree ) { - kWarning() << "Discarding parts of the code to be parsed because of previous errors"; - kDebug() << indents; + qCWarning(KDEV_PYTHON_PARSER) << "Discarding parts of the code to be parsed because of previous errors"; + qCDebug(KDEV_PYTHON_PARSER) << indents; int indentAtError = indents.at(errline); QChar c; bool atLineBeginning = true; @@ -527,13 +523,13 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) int currentLineContentBeginning = currentLineBeginning; for ( int i = currentLineBeginning; i < len; i++ ) { c = contents.at(i); - kDebug() << c; + qCDebug(KDEV_PYTHON_PARSER) << c; if ( c == '\n' ) { if ( currentIndent <= indentAtError && currentIndent != -1 ) { - kDebug() << "Start of error code: " << currentLineBeginning; - kDebug() << "End of error block (current position): " << currentLineBeginning_end; - kDebug() << "Length: " << currentLineBeginning_end - currentLineBeginning; - kDebug() << "indent at error <> current indent:" << indentAtError << "<>" << currentIndent; + qCDebug(KDEV_PYTHON_PARSER) << "Start of error code: " << currentLineBeginning; + qCDebug(KDEV_PYTHON_PARSER) << "End of error block (current position): " << currentLineBeginning_end; + qCDebug(KDEV_PYTHON_PARSER) << "Length: " << currentLineBeginning_end - currentLineBeginning; + qCDebug(KDEV_PYTHON_PARSER) << "indent at error <> current indent:" << indentAtError << "<>" << currentIndent; // contents.remove(currentLineBeginning, currentLineBeginning_end-currentLineBeginning); break; } @@ -553,14 +549,14 @@ CodeAst::Ptr AstBuilder::parse(KUrl filename, QString &contents) } if ( c.isSpace() && atLineBeginning ) currentIndent += 1; } - kDebug() << "This is what is left: " << contents; + qCDebug(KDEV_PYTHON_PARSER) << "This is what is left: " << contents; syntaxtree = PyParser_ASTFromString(contents.toUtf8(), "", file_input, &flags, arena); } if ( ! syntaxtree ) { return CodeAst::Ptr(); // everything fails, so we abort. } } - kDebug() << "Got syntax tree from python parser:" << syntaxtree->kind << Module_kind; + qCDebug(KDEV_PYTHON_PARSER) << "Got syntax tree from python parser:" << syntaxtree->kind << Module_kind; PythonAstTransformer t(lineOffset); t.run(syntaxtree, filename.fileName().replace(".py", "")); diff --git a/parser/astbuilder.h b/parser/astbuilder.h index 21adc81d..2430112e 100644 --- a/parser/astbuilder.h +++ b/parser/astbuilder.h @@ -25,8 +25,7 @@ #include "ast.h" #include "parserexport.h" -#include -#include +#include #include "astdefaultvisitor.h" #include @@ -47,14 +46,14 @@ class CodeAst; typedef QMap stringDictionary; -QPair fileHeaderHack(QString& contents, const KUrl& filename); +QPair fileHeaderHack(QString& contents, const QUrl& filename); QString PyUnicodeObjectToQString(PyObject* obj); class KDEVPYTHONPARSER_EXPORT AstBuilder { public: - CodeAst::Ptr parse(KUrl filename, QString &contents); + CodeAst::Ptr parse(const QUrl& filename, QString &contents); QList m_problems; private: static QMutex pyInitLock; diff --git a/parser/astdefaultvisitor.cpp b/parser/astdefaultvisitor.cpp index 63b01c45..94355e53 100644 --- a/parser/astdefaultvisitor.cpp +++ b/parser/astdefaultvisitor.cpp @@ -22,7 +22,6 @@ #include "astdefaultvisitor.h" #include "ast.h" -#include namespace Python { diff --git a/parser/codehelpers.cpp b/parser/codehelpers.cpp index f9be2954..4b11dbfd 100644 --- a/parser/codehelpers.cpp +++ b/parser/codehelpers.cpp @@ -109,7 +109,7 @@ CodeHelpers::EndLocation CodeHelpers::endsInside(const QString &code) stringDelimiters << "\"\"\"" << "\'\'\'" << "'" << "\""; QStack stringStack; const int max_len = code.length(); - kDebug() << "Checking for comment line:" << code; + qDebug() << "Checking for comment line:" << code; for ( int atChar = 0; atChar < max_len; atChar++ ) { const QChar c = code.at(atChar); if ( c == ' ' || c.isLetterOrNumber() ) { @@ -208,7 +208,7 @@ QString CodeHelpers::expressionUnderCursor(Python::LazyLineFetcher& lineFetcher, while ( start >= 0 ) { QChar c = line[start]; int bracket = closingBrackets.indexOf(c); - kDebug() << bracket << c; + qDebug() << bracket << c; if ( ! brackets.isEmpty() && brackets.top() == c ) { brackets.pop(); } @@ -265,13 +265,13 @@ QString CodeHelpers::expressionUnderCursor(Python::LazyLineFetcher& lineFetcher, linePart = QString(); } else { - kDebug() << line << start << end << end-start << line.length(); + qDebug() << line << start << end << end-start << line.length(); linePart = line.mid(start, end-start + 1); } QString expression(linePart + text); expression = expression.trimmed(); - kDebug() << "expression found:" << expression; + qDebug() << "expression found:" << expression; return expression; } @@ -296,7 +296,7 @@ QString CodeHelpers::extractStringUnderCursor(const QString &code, KTextEditor:: while ( start >= 0 ) { QChar c = beforeAndAfter.first.at(start); int quote = quoteCharacters.indexOf(c); -// kDebug() << quote << c; +// qDebug() << quote << c; // if we've found a quote character and we're either at the beginning of the code or the previous char is not a backslash if ( quote != -1 && (start == 0 || (start != 0 && beforeAndAfter.first.at(start - 1) != '\\')) ) { @@ -337,7 +337,7 @@ QString CodeHelpers::extractStringUnderCursor(const QString &code, KTextEditor:: *cursorPositionInString = beforeAndAfter.first.size() - start; } - kDebug() << "string found:" << string; + qDebug() << "string found:" << string; return string; } diff --git a/parser/codehelpers.h b/parser/codehelpers.h index 414eef44..1ee7ac1d 100644 --- a/parser/codehelpers.h +++ b/parser/codehelpers.h @@ -20,6 +20,7 @@ #ifndef CODEHELPERS_H #define CODEHELPERS_H #include +#include #include #include "parserexport.h" diff --git a/parser/conversionGenerator.py b/parser/conversionGenerator.py index 06fe43c3..e35c4fcc 100644 --- a/parser/conversionGenerator.py +++ b/parser/conversionGenerator.py @@ -1,5 +1,8 @@ #!/usr/bin/env python +# Copyright 2014 by Sven Brauch +# License: GPL v2+ + # Transforms a conversion definition file (.sdef) into C++ code. To be copied over manually. :) # sdef example line: # RULE_FOR _stmt;KIND Expr_kind;ACTIONS create|ExpressionAst set|value->ExpressionAst,value;CODE;; diff --git a/parser/cythonsyntaxremover.cpp b/parser/cythonsyntaxremover.cpp index e9d8ce85..dd547586 100644 --- a/parser/cythonsyntaxremover.cpp +++ b/parser/cythonsyntaxremover.cpp @@ -23,7 +23,11 @@ #include "astdefaultvisitor.h" #include "codehelpers.h" #include -#include + +#include + +#include +#include "parserdebug.h" using namespace KDevelop; @@ -35,10 +39,11 @@ class CythonDeletionFixVisitor : public AstDefaultVisitor { public: CythonDeletionFixVisitor(const QVector& deletedRanges) : m_deletedRanges() { + for (const auto& del: deletedRanges) { // TODO: Multi-line deletes, handle them, possible? - if (del.range.start.line == del.range.end.line) { - m_deletedRanges[del.range.start.line].append(del.range); + if (del.range.start().line() == del.range.end().line()) { + m_deletedRanges[del.range.start().line()].append(del.range); } } // sort by column for faster access @@ -60,10 +65,10 @@ class CythonDeletionFixVisitor : public AstDefaultVisitor { return; } for (auto range: m_deletedRanges[name->startLine]) { - if (name->startCol >= range.start.column) { - name->startCol += range.end.column-range.start.column; + if (name->startCol >= range.start().column()) { + name->startCol += range.end().column() - range.start().column(); if (name->startLine == name->endLine) { - name->endCol += range.end.column-range.start.column; + name->endCol += range.end().column() - range.start().column(); } } else { @@ -75,7 +80,7 @@ class CythonDeletionFixVisitor : public AstDefaultVisitor { private: // Key is the line number of the ranges to delete. - QMap> m_deletedRanges; + QMap> m_deletedRanges; }; @@ -92,10 +97,10 @@ QString CythonSyntaxRemover::stripCythonSyntax(const QString& code) // Check every line quickly for hints that Cython syntax // is used and then find the correct replacement via // regular expressions. - for (m_offset.column = m_offset.line = 0; - m_offset.line < m_code.length(); - m_offset.line++, m_offset.column = 0) { - QString& line = m_code[m_offset.line]; + for (m_offset.setPosition(0, 0); + m_offset.line() < m_code.length(); + m_offset.setLine(m_offset.line()+1), m_offset.setColumn(0)) { + QString& line = m_code[m_offset.line()]; if (fixFunctionDefinitions(line)) continue; if (fixExtensionClasses(line)) continue; if (fixVariableTypes(line)) continue; @@ -125,41 +130,41 @@ bool CythonSyntaxRemover::fixFunctionDefinitions(QString& line) // a class definition for a derived class. return false; } - kDebug() << "Function, replace" << definition + qCDebug(KDEV_PYTHON_PARSER) << "Function, replace" << definition << "and remove return type: " << returnType; // from the beginning of the argument list (open paren), // replace type specifiers (if available). - m_offset.column = wholeMatch.length(); - kDebug() << "Regex ended at offset" << m_offset; + m_offset.setColumn(wholeMatch.length()); + qCDebug(KDEV_PYTHON_PARSER) << "Regex ended at offset" << m_offset; auto types = getArgumentListTypes(); for (int i = types.size()-1; i >= 0; i--) { auto range = types[i]; - kDebug() << "Replace" << range.start.line << ":" << range.start.column << " to " << range.end.line << ":" << range.end.column << m_code[range.start.line].mid(range.start.column, range.end.column - range.start.column); - QString white = QString(" ").repeated(range.end.column - range.start.column); - m_code[range.start.line].replace(range.start.column, white.length(), white); + qCDebug(KDEV_PYTHON_PARSER) << "Replace" << range.start().line() << ":" << range.start().column() << " to " << range.end().line() << ":" << range.end().column() << m_code[range.start().line()].mid(range.start().column(), range.end().column() - range.start().column()); + QString white = QString(" ").repeated(range.end().column() - range.start().column()); + m_code[range.start().line()].replace(range.start().column(), white.length(), white); } // Find range of syntax for return values in case an exception occurs // Syntax: "cdef foo(bar) except (EXPRESSION,*):" - SimpleCursor start = m_offset; - while (m_code[m_offset.line][m_offset.column] != ':') { - m_offset.column++; - if (m_offset.column >= m_code[m_offset.line].length()) { - m_offset.line++; - m_offset.column = 0; - if(m_offset.line >= m_code.length()) { - m_offset.line = m_code.length() - 1; - m_offset.column = m_code[m_offset.line].length() - 1; + auto start = m_offset; + while (m_code[m_offset.line()][m_offset.column()] != ':') { + m_offset.setColumn(m_offset.column() + 1); + if (m_offset.column() >= m_code.at(m_offset.line()).length()) { + m_offset.setLine(m_offset.line()+1); + m_offset.setColumn(0); + if(m_offset.line() >= m_code.length()) { + m_offset.setLine(m_code.length() - 1); + m_offset.setColumn(m_code[m_offset.line()].length() - 1); break; } } } // replace the exception definition - if (start.line == m_offset.line && start.column < m_offset.column) { - auto exceptionDefLen = m_offset.column-start.column; - auto exceptionDef = m_code[m_offset.line].mid(start.column, exceptionDefLen); + if (start.line() == m_offset.line() && start.column() < m_offset.column()) { + auto exceptionDefLen = m_offset.column() - start.column(); + auto exceptionDef = m_code.at(m_offset.line()).mid(start.column(), exceptionDefLen); if(exceptionDef.indexOf(QString("except")) != -1) { - m_deletions.append(DeletedCode{exceptionDef, SimpleRange(start, m_offset)}); - m_code[start.line].remove(start.column, exceptionDefLen); + m_deletions.append(DeletedCode{exceptionDef, {start, m_offset}}); + m_code[start.line()].remove(start.column(), exceptionDefLen); } else { // probably the closing ":" was not typed yet, recover m_offset @@ -167,20 +172,20 @@ bool CythonSyntaxRemover::fixFunctionDefinitions(QString& line) } } // replace multiline expression... - else if (start.line < m_offset.line) { + else if (start.line() < m_offset.line()) { auto pos = start; QString exceptionDef; bool foundExceptKeyword = false; - for (; pos.line < m_offset.line && pos.line < m_code.length(); pos.line++, pos.column = 0) { - QString& curLine = m_code[pos.line]; - exceptionDef.append(curLine.mid(pos.column, curLine.length()-pos.column)); + for (; pos.line() < m_offset.line() && pos.line() < m_code.length(); pos.setLine(pos.line()+1), pos.setColumn(0)) { + QString& curLine = m_code[pos.line()]; + exceptionDef.append(curLine.mid(pos.column(), curLine.length() - pos.column())); // replace with ":" if there is an offset to start of line. This is the // case for the first line - kDebug() << "foundExceptKeyword?" << foundExceptKeyword << "curLine.indexOf(\"except\")" << curLine.indexOf("except"); + qCDebug(KDEV_PYTHON_PARSER) << "foundExceptKeyword?" << foundExceptKeyword << "curLine.indexOf(\"except\")" << curLine.indexOf("except"); if(foundExceptKeyword || curLine.indexOf("except") != -1) { foundExceptKeyword = true; - curLine.replace(pos.column, curLine.length()-pos.column, - pos.column ? QString(":") : QString()); + curLine.replace(pos.column(), curLine.length() - pos.column(), + pos.column() ? QStringLiteral(":") : QString()); } else { // first line of "exception def" did not contain except @@ -191,27 +196,27 @@ bool CythonSyntaxRemover::fixFunctionDefinitions(QString& line) } } if(foundExceptKeyword) { - QString& curLine = m_code[m_offset.line]; + QString& curLine = m_code[m_offset.line()]; // remove one more char than offset points to, we don't want to keep // the : in the multiline case - m_offset.column++; - exceptionDef.append(curLine.mid(0, m_offset.column)); - curLine.remove(0, m_offset.column); - m_deletions.append(DeletedCode{exceptionDef, SimpleRange(start, m_offset)}); + m_offset.setColumn(m_offset.column() + 1); + exceptionDef.append(curLine.mid(0, m_offset.column())); + curLine.remove(0, m_offset.column()); + m_deletions.append(DeletedCode{exceptionDef, {start, m_offset}}); } } // if a return type was specified, delete it from code if (returnTypePos != -1) { - SimpleRange delrange(start.line, returnTypePos, - start.line, returnTypePos + returnType.length()); + auto delrange = KTextEditor::Range(start.line(), returnTypePos, + start.line(), returnTypePos + returnType.length()); m_deletions.append(DeletedCode{returnType, delrange}); line.remove(returnTypePos, returnType.length()); } // if the keyword is not def (but cdef, cpdef ...), replace it if (definition != QString("def")) { - SimpleRange delrange(start.line, definitionPos, - start.line, definitionPos + definition.length()-3); + auto delrange = KTextEditor::Range(start.line(), definitionPos, + start.line(), definitionPos + definition.length()-3); m_deletions.append(DeletedCode{definition, delrange}); line.replace(definitionPos, definition.length(), @@ -231,9 +236,9 @@ bool CythonSyntaxRemover::fixExtensionClasses(QString& line) if (regexp_cdef_class.indexIn(line) != -1) { auto definition = regexp_cdef_class.cap(1); auto definition_pos = regexp_cdef_class.pos(1); - kDebug() << "Extension class, remove " << definition; - SimpleRange delrange(m_offset.line, definition_pos, - m_offset.line, definition_pos+definition.length()); + qCDebug(KDEV_PYTHON_PARSER) << "Extension class, remove " << definition; + auto delrange = KTextEditor::Range(m_offset.line(), definition_pos, + m_offset.line(), definition_pos+definition.length()); m_deletions.append(DeletedCode{regexp_cdef_class.cap(1), delrange}); line.remove(definition_pos, definition.length()); @@ -252,9 +257,9 @@ bool CythonSyntaxRemover::fixVariableTypes(QString& line) // cdef TYPE Var1=0, Var2=4 static QRegExp regexp_cdef_variable("^(\\s*)cdef\\s+[\\.a-zA-Z0-9_]+(\\[[^\\]]+\\])?\\s*\\**\\s*[a-zA-Z0-9_]+\\s*(,\\s*[a-zA-Z0-9_]+\\s*)*"); if (regexp_cdef_variable.indexIn(line) != -1) { - kDebug() << "Variable cdef -> pass"; - SimpleRange delrange(m_offset.line, 0, - m_offset.line, line.length()-regexp_cdef_variable.cap(1).length()-4); + qCDebug(KDEV_PYTHON_PARSER) << "Variable cdef -> pass"; + auto delrange = KTextEditor::Range(m_offset.line(), 0, + m_offset.line(), line.length()-regexp_cdef_variable.cap(1).length()-4); m_deletions.append(DeletedCode{line, delrange}); line = regexp_cdef_variable.cap(1); line += QString("pass"); @@ -272,9 +277,9 @@ bool CythonSyntaxRemover::fixCimports(QString& line) regexp_cimport_a.setMinimal(true); if (regexp_cimport_a.indexIn(line) != -1 || regexp_cimport_b.indexIn(line) != -1) { - SimpleRange delrange(m_offset.line, 0, m_offset.line, line.length()); + auto delrange = KTextEditor::Range(m_offset.line(), 0, m_offset.line(), line.length()); m_deletions.append(DeletedCode{line, delrange}); - line = QString(); + line.clear(); return true; } return false; @@ -292,17 +297,17 @@ bool CythonSyntaxRemover::fixCtypedefs(QString& line) regexp_ctypedef.cap(1).length()); auto typeDef = regexp_ctypedef.cap(1); auto typeDefPos = regexp_ctypedef.pos(1); - SimpleRange delrange(m_offset.line, typeDefPos, - m_offset.line, regexp_ctypedef.pos(1) + typeDef.length()); + auto delrange = KTextEditor::Range(m_offset.line(), typeDefPos, + m_offset.line(), regexp_ctypedef.pos(1) + typeDef.length()); m_deletions.append(DeletedCode{typeDef, delrange}); return true; } return false; } -QVector CythonSyntaxRemover::getArgumentListTypes() +QVector CythonSyntaxRemover::getArgumentListTypes() { - QVector type_specifiers; + QVector type_specifiers; auto token_list(getArgumentListTokens()); // if there are consecutive IDs, the first ID is the type specifier for (int i = 0; i < token_list.size()-1; i++) { @@ -314,51 +319,54 @@ QVector CythonSyntaxRemover::getArgumentListTypes() return type_specifiers; } -QVector< CythonSyntaxRemover::Token > CythonSyntaxRemover::getArgumentListTokens() +QVector CythonSyntaxRemover::getArgumentListTokens() { - SimpleRange range(m_offset, m_offset); + auto range = KTextEditor::Range(m_offset, m_offset); QVector token_list; bool stop_tokenizer = false; while (!stop_tokenizer) { // did we reach end of line? // continue to next line until we hit non-empty line - while (m_offset.column >= m_code[m_offset.line].length()) { - if (m_offset.line >= m_code.length()-1) + while (m_offset.column() >= m_code[m_offset.line()].length()) { + if (m_offset.line() >= m_code.length()-1) { break; - m_offset.column = 0; - m_offset.line++; - range.start = m_offset; - range.end = m_offset; + } + m_offset.setColumn(0); + m_offset.setLine(m_offset.line() + 1); + range.setStart(m_offset); + range.setEnd(m_offset); } - QChar c = m_code[m_offset.line][m_offset.column++]; + QChar c = m_code.at(m_offset.line()).at(m_offset.column()); + m_offset.setColumn(m_offset.column() + 1); if (c.isSpace()) { - range.start = m_offset; - range.end = m_offset; + range.setStart(m_offset); + range.setEnd(m_offset); } else if (c == '=') { - range.end.column++; + range.setEnd(range.end() + KTextEditor::Cursor(0, 1)); int open_paren_count = 0; bool in_string = false; // while there are open parenthesis or if we are in // string mode and the current character does not terminate // the token, consume! - c = m_code[m_offset.line][m_offset.column++]; + c = m_code.at(m_offset.line()).at(m_offset.column()); + m_offset.setColumn(m_offset.column() + 1); while (open_paren_count > 0 || in_string || !(c == ',' || c == ')')) { - if (m_offset.column >= m_code[m_offset.line].length()) { - if (m_offset.line >= m_code.length()) { - m_offset.column--; + if (m_offset.column() >= m_code.at(m_offset.line()).length()) { + if (m_offset.line() >= m_code.length()) { + m_offset.setColumn(m_offset.column() - 1); break; } - m_offset.line++; - m_offset.column = 0; + m_offset.setLine(m_offset.line() + 1); + m_offset.setColumn(0); } - range.end = m_offset; + range.setEnd(m_offset); // TODO: Support for """ """ multiline strings. // Maybe implicitly contained? if (c == '"') { - if (in_string && m_offset.column >= 2) - in_string = (m_code[m_offset.line][m_offset.column-2] == '\\'); + if (in_string && m_offset.column() >= 2) + in_string = (m_code.at(m_offset.line()).at(m_offset.column()-2) == '\\'); else in_string = !in_string; } @@ -366,43 +374,48 @@ QVector< CythonSyntaxRemover::Token > CythonSyntaxRemover::getArgumentListTokens open_paren_count++; else if (!in_string && c == ')') open_paren_count--; - c = m_code[m_offset.line][m_offset.column++]; + c = m_code.at(m_offset.line()).at(m_offset.column()); + m_offset.setColumn(m_offset.column() + 1); } - m_offset.column--; - range.end = m_offset; + m_offset.setColumn(m_offset.column() - 1); + range.setEnd(m_offset); token_list.append({TOKEN_DEFAULT_ARGUMENT, range}); - range.start = range.end; + range.setStart(range.end()); } else if (c == ',') { - range.end = m_offset; + range.setEnd(m_offset); token_list.append({TOKEN_COMMA, range}); - range.start = range.end; + range.setStart(range.end()); } else if (c == ')') { stop_tokenizer = true; - range.end = m_offset; + range.setEnd(m_offset); token_list.append({TOKEN_END, range}); - range.start = range.end; + range.setStart(range.end()); } else { int open_bracket_count = 0; - c = m_code[m_offset.line][m_offset.column++]; + c = m_code.at(m_offset.line()).at(m_offset.column()); + m_offset.setColumn(m_offset.column()+1); // stop consuming the input if there are no closing // square brackets left and the current character is // whitespace, =, ,, ) or the end of line. while ((!c.isSpace() - && m_offset.column < m_code[m_offset.line].length() + && m_offset.column() < m_code.at(m_offset.line()).length() && c != ')' && c != ',' && c != '=') || open_bracket_count > 0) { - if (c == '[') + if (c == '[') { open_bracket_count++; - else if (c == ']') + } + else if (c == ']') { open_bracket_count--; - c = m_code[m_offset.line][m_offset.column++]; + } + c = m_code.at(m_offset.line()).at(m_offset.column()); + m_offset.setColumn(m_offset.column() + 1); } - m_offset.column--; - range.end = m_offset; + m_offset.setColumn(m_offset.column() - 1); + range.setEnd(m_offset); token_list.append({TOKEN_ID, range}); - range.start = range.end; + range.setStart(range.end()); } } return token_list; diff --git a/parser/cythonsyntaxremover.h b/parser/cythonsyntaxremover.h index 4183f385..b0369829 100644 --- a/parser/cythonsyntaxremover.h +++ b/parser/cythonsyntaxremover.h @@ -26,8 +26,7 @@ #include "parserexport.h" #include #include -#include - +#include namespace Python { @@ -50,12 +49,12 @@ class KDEVPYTHONPARSER_EXPORT CythonSyntaxRemover { struct Token { TOKEN_TYPE type; - KDevelop::SimpleRange range; + KTextEditor::Range range; }; struct DeletedCode { QString code; - KDevelop::SimpleRange range; + KTextEditor::Range range; }; QString stripCythonSyntax(const QString& code); @@ -68,12 +67,12 @@ class KDEVPYTHONPARSER_EXPORT CythonSyntaxRemover { bool fixCimports(QString& line); bool fixCtypedefs(QString& line); - QVector getArgumentListTypes(); + QVector getArgumentListTypes(); QVector getArgumentListTokens(); QStringList m_code; QString m_strippedCode; - KDevelop::SimpleCursor m_offset; + KTextEditor::Cursor m_offset; QVector m_deletions; }; diff --git a/parser/generated.h b/parser/generated.h index 128d2b18..bc3a31f7 100644 --- a/parser/generated.h +++ b/parser/generated.h @@ -251,7 +251,7 @@ class PythonAstTransformer { break; } default: - kWarning() << "Unsupported statement AST type: " << node->kind; + qCWarning(KDEV_PYTHON_PARSER) << "Unsupported statement AST type: " << node->kind; Q_ASSERT(false); } @@ -315,7 +315,7 @@ class PythonAstTransformer { break; } default: - kWarning() << "Unsupported statement AST type: " << node->kind; + qCWarning(KDEV_PYTHON_PARSER) << "Unsupported statement AST type: " << node->kind; Q_ASSERT(false); } @@ -574,7 +574,7 @@ class PythonAstTransformer { break; } default: - kWarning() << "Unsupported statement AST type: " << node->kind; + qCWarning(KDEV_PYTHON_PARSER) << "Unsupported statement AST type: " << node->kind; Q_ASSERT(false); } @@ -643,7 +643,7 @@ class PythonAstTransformer { break; } default: - kWarning() << "Unsupported statement AST type: " << node->kind; + qCWarning(KDEV_PYTHON_PARSER) << "Unsupported statement AST type: " << node->kind; Q_ASSERT(false); } diff --git a/parser/parserdebug.cpp b/parser/parserdebug.cpp new file mode 100644 index 00000000..429fca3d --- /dev/null +++ b/parser/parserdebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "parserdebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON_PARSER, "kdev.python.parser") + + diff --git a/parser/parserdebug.h b/parser/parserdebug.h new file mode 100644 index 00000000..13839069 --- /dev/null +++ b/parser/parserdebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PARSERDEBUG_H +#define PARSERDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON_PARSER) + +#endif + diff --git a/parser/parserexport.h b/parser/parserexport.h deleted file mode 100644 index 12b139a3..00000000 --- a/parser/parserexport.h +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2007 Andreas Pakulat * - * Copyright 2006 Matt Rogers * - * Copyright 2004 Jaroslaw Staniek * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Library General Public License as * - * published by the Free Software Foundation; either version 2 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef PARSEREXPORT_H -#define PARSEREXPORT_H - -/* needed for KDE_EXPORT macros */ -#include - - -#ifndef KDEVPYTHONPARSER_EXPORT -# ifdef MAKE_KDEV4PYTHONPARSER_LIB -# define KDEVPYTHONPARSER_EXPORT KDE_EXPORT -# else -# define KDEVPYTHONPARSER_EXPORT KDE_IMPORT -# endif -#endif - -#endif - -//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle; diff --git a/parser/parsesession.cpp b/parser/parsesession.cpp index 12615762..2ab9418d 100644 --- a/parser/parsesession.cpp +++ b/parser/parsesession.cpp @@ -18,12 +18,11 @@ ***************************************************************************** */ #include "parsesession.h" - -#include -#include - #include "astbuilder.h" +#include +#include "parserdebug.h" + using namespace KDevelop; namespace Python @@ -81,11 +80,11 @@ QPair ParseSession::parse() if( matched.second ) { - kDebug() << "Sucessfully parsed"; + qCDebug(KDEV_PYTHON_PARSER) << "Sucessfully parsed"; }else { matched.first.clear(); - kDebug() << "Couldn't parse content"; + qCDebug(KDEV_PYTHON_PARSER) << "Couldn't parse content"; } return matched; } diff --git a/parser/parsesession.h b/parser/parsesession.h index d5afae61..c4c31dbd 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -18,21 +18,21 @@ */ #ifndef PYTHON_PARSESESSION_H #define PYTHON_PARSESESSION_H + #include + #include "parserexport.h" -#include #include #include -#include #include -#include "ast.h" -#include "kurl.h" -#include "astdefaultvisitor.h" #include #include #include +#include "ast.h" +#include "astdefaultvisitor.h" + using namespace KDevelop; typedef QPair SimpleUse; diff --git a/parser/tests/CMakeLists.txt b/parser/tests/CMakeLists.txt index 7b24f98f..928e2c3c 100644 --- a/parser/tests/CMakeLists.txt +++ b/parser/tests/CMakeLists.txt @@ -1,5 +1,11 @@ -kde4_add_unit_test(pyasttest pyasttest.cpp) -target_link_libraries(pyasttest kdev4pythonparser ${QT_QTTEST_LIBRARY} ${KDEVPLATFORM_TESTS_LIBRARIES}) +set(pyasttest_SRCS pyasttest.cpp ../parserdebug.cpp) -kde4_add_unit_test(pycythontest pycythontest.cpp) -target_link_libraries(pycythontest kdev4pythonparser ${QT_QTTEST_LIBRARY} ${KDEVPLATFORM_TESTS_LIBRARIES}) \ No newline at end of file +include_directories(${CMAKE_BINARY_DIR}/duchain) +ecm_add_test(${pyasttest_SRCS} + TEST_NAME pyasttest + LINK_LIBRARIES kdevpythonparser Qt5::Test KDev::Tests KF5::KDELibs4Support) + +set(pycythontest_SRCS pycythontest.cpp ../parserdebug.cpp) +ecm_add_test(${pycythontest_SRCS} + TEST_NAME pycythontest + LINK_LIBRARIES kdevpythonparser Qt5::Test KDev::Tests KF5::KDELibs4Support) diff --git a/parser/tests/pyasttest.cpp b/parser/tests/pyasttest.cpp index f8929f8e..441cec90 100644 --- a/parser/tests/pyasttest.cpp +++ b/parser/tests/pyasttest.cpp @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -40,6 +39,9 @@ #include "pyasttest.h" #include "../astbuilder.h" +#include +#include "../parserdebug.h" + using namespace Python; QTEST_MAIN(PyAstTest) @@ -61,7 +63,7 @@ void PyAstTest::initShell() CodeAst::Ptr PyAstTest::getAst(QString code) { QSharedPointer builder(new AstBuilder); - CodeAst::Ptr result = builder->parse(KUrl(""), code); + CodeAst::Ptr result = builder->parse(QUrl(""), code); return result; } @@ -211,12 +213,12 @@ void PyAstTest::testExpressions_data() QTest::newRow("True") << "True"; } -Q_DECLARE_METATYPE(SimpleRange); +Q_DECLARE_METATYPE(KTextEditor::Range); void PyAstTest::testCorrectedFuncRanges() { QFETCH(QString, code); - QFETCH(SimpleRange, range); + QFETCH(KTextEditor::Range, range); CodeAst::Ptr ast = getAst(code); QVERIFY(ast); @@ -226,7 +228,7 @@ void PyAstTest::testCorrectedFuncRanges() } FunctionDefinitionAst* func = static_cast(node); QVERIFY(func->name); - kDebug() << func->name->range() << range; + qCDebug(KDEV_PYTHON_PARSER) << func->name->range() << range; QCOMPARE(func->name->range(), range); } } @@ -234,12 +236,12 @@ void PyAstTest::testCorrectedFuncRanges() void PyAstTest::testCorrectedFuncRanges_data() { QTest::addColumn("code"); - QTest::addColumn("range"); + QTest::addColumn("range"); - QTest::newRow("decorator") << "@decorate\ndef func(arg): pass" << SimpleRange(1, 4, 1, 7); - QTest::newRow("decorator_arg") << "@decorate(yomama=3)\ndef func(arg): pass" << SimpleRange(1, 4, 1, 7); - QTest::newRow("two_decorators") << "@decorate2\n@decorate\ndef func(arg): pass" << SimpleRange(2, 4, 2, 7); - QTest::newRow("decorate_class") << "class foo:\n @decorate2\n @decorate\n def func(arg): pass" << SimpleRange(3, 5, 3, 8); + QTest::newRow("decorator") << "@decorate\ndef func(arg): pass" << KTextEditor::Range(1, 4, 1, 7); + QTest::newRow("decorator_arg") << "@decorate(yomama=3)\ndef func(arg): pass" << KTextEditor::Range(1, 4, 1, 7); + QTest::newRow("two_decorators") << "@decorate2\n@decorate\ndef func(arg): pass" << KTextEditor::Range(2, 4, 2, 7); + QTest::newRow("decorate_class") << "class foo:\n @decorate2\n @decorate\n def func(arg): pass" << KTextEditor::Range(3, 5, 3, 8); } void PyAstTest::testNewPython3() diff --git a/parser/tests/pyasttest.h b/parser/tests/pyasttest.h index 560d5b5a..a7cf5c9c 100644 --- a/parser/tests/pyasttest.h +++ b/parser/tests/pyasttest.h @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/parser/tests/pycythontest.cpp b/parser/tests/pycythontest.cpp index ea83a8bd..d7a5d502 100644 --- a/parser/tests/pycythontest.cpp +++ b/parser/tests/pycythontest.cpp @@ -4,7 +4,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -18,12 +18,10 @@ #include #include -#include #include #include #include #include -#include #include #include "pythoneditorintegrator.h" @@ -34,10 +32,13 @@ #include "../cythonsyntaxremover.h" #include "../astbuilder.h" +#include +#include "../parserdebug.h" + using namespace Python; QTEST_MAIN(PyCythonTest) -Q_DECLARE_METATYPE(KDevelop::SimpleRange); +Q_DECLARE_METATYPE(KTextEditor::Range); PyCythonTest::PyCythonTest(QObject* parent): QObject(parent) { @@ -53,7 +54,7 @@ void PyCythonTest::initShell() KDevelop::CodeRepresentation::setDiskChangesForbidden(true); } -CodeAst::Ptr PyCythonTest::getAst(QString code, KUrl filename) +CodeAst::Ptr PyCythonTest::getAst(QString code, const QUrl& filename) { QSharedPointer builder(new AstBuilder); m_builder = builder; @@ -89,7 +90,7 @@ void PyCythonTest::testCythonReplacement() CythonSyntaxRemover stripper; QCOMPARE(stripper.stripCythonSyntax(input), output); if(do_python_test) { - CodeAst::Ptr ast = getAst(input, KUrl("test.pyx")); + CodeAst::Ptr ast = getAst(input, QUrl("test.pyx")); VerifyVisitor v; v.visitCode(ast.data()); QVERIFY(m_builder->m_problems.isEmpty()); @@ -132,9 +133,9 @@ void PyCythonTest::testCythonReplacement_data() void PyCythonTest::testCythonRanges() { QFETCH(QString, code); - QFETCH(SimpleRange, range); + QFETCH(KTextEditor::Range, range); - CodeAst::Ptr ast = getAst(code, KUrl("test.pyx")); + CodeAst::Ptr ast = getAst(code, QUrl("test.pyx")); QVERIFY(ast); foreach ( Ast* node, ast->body ) { if ( node->astType != Ast::FunctionDefinitionAstType ) { @@ -142,7 +143,7 @@ void PyCythonTest::testCythonRanges() { } FunctionDefinitionAst* func = static_cast(node); QVERIFY(func->name); - kDebug() << func->name->range() << range; + qCDebug(KDEV_PYTHON_PARSER) << func->name->range() << range; QCOMPARE(func->name->range(), range); } } @@ -150,11 +151,11 @@ void PyCythonTest::testCythonRanges() { void PyCythonTest::testCythonRanges_data() { QTest::addColumn("code"); - QTest::addColumn("range"); + QTest::addColumn("range"); - QTest::newRow("cdef") << "cdef foobar(arg): pass" << SimpleRange(0, 5, 0, 10); - QTest::newRow("cdef_return") << "cdef float* foobar(arg): pass" << SimpleRange(0, 12, 0, 17); - QTest::newRow("normal_def") << "def foobar(arg): pass" << SimpleRange(0, 4, 0, 9); + QTest::newRow("cdef") << "cdef foobar(arg): pass" << KTextEditor::Range(0, 5, 0, 10); + QTest::newRow("cdef_return") << "cdef float* foobar(arg): pass" << KTextEditor::Range(0, 12, 0, 17); + QTest::newRow("normal_def") << "def foobar(arg): pass" << KTextEditor::Range(0, 4, 0, 9); } diff --git a/parser/tests/pycythontest.h b/parser/tests/pycythontest.h index 5bb46ae0..199efb8d 100644 --- a/parser/tests/pycythontest.h +++ b/parser/tests/pycythontest.h @@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -39,7 +39,7 @@ Q_OBJECT public: explicit PyCythonTest(QObject* parent = 0); void initShell(); - CodeAst::Ptr getAst(QString code, KUrl filename); + CodeAst::Ptr getAst(QString code, const QUrl& filename); private: QSharedPointer m_builder; diff --git a/pep8kcm/CMakeLists.txt b/pep8kcm/CMakeLists.txt index cc438845..807a7509 100644 --- a/pep8kcm/CMakeLists.txt +++ b/pep8kcm/CMakeLists.txt @@ -2,16 +2,16 @@ set(kcm_pep8_SRCS kcm_pep8.cpp ) -kde4_add_plugin(kcm_pep8 ${kcm_pep8_SRCS}) +add_library(kcm_pep8 MODULE ${kcm_pep8_SRCS}) target_link_libraries(kcm_pep8 - ${KDE4_KIO_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDEVPLATFORM_UTIL_LIBRARIES} - ${KDE4_KNEWSTUFF3_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} + KF5::KIOCore + KDev::Interfaces + KDev::Language + KDev::Project + KDev::Util + KF5::NewStuff + KF5::KCMUtils ) install(TARGETS kcm_pep8 diff --git a/pep8kcm/kcm_kdevpythonpep8.desktop b/pep8kcm/kcm_kdevpythonpep8.desktop index cd5b6ff1..19e4fa90 100644 --- a/pep8kcm/kcm_kdevpythonpep8.desktop +++ b/pep8kcm/kcm_kdevpythonpep8.desktop @@ -10,12 +10,14 @@ X-KDE-ParentComponents=kdevplatform X-KDE-CfgDlgHierarchy=GENERAL Name=Python style checking +Name[ar]=فحص نمط بايثون Name[bs]=Provjera Python stila Name[ca]=Comprovació de l'estil de Python Name[ca@valencia]=Comprovació de l'estil de Python Name[da]=Python stiltjek Name[de]=Python-Stilüberprüfung Name[el]=Έλεγχος στιλ Python +Name[en_GB]=Python style checking Name[es]=Comprobación del estilo de Python Name[fi]=Pythonin tyylin tarkistus Name[fr]=Contrôle de styles de Python @@ -23,6 +25,7 @@ Name[gl]=Comprobación do estilo de Python Name[hu]=Python stílus ellenőrzés Name[it]=Controllo stile Python Name[kk]=Python стилін тексеру +Name[ko]=파이썬 문법 검사 Name[mr]=पायथोन शैली तपासणी Name[nb]=Sjekk Python-stil Name[nl]=Controleren in de stijl van Python @@ -36,4 +39,5 @@ Name[sv]=Python-stilkontroll Name[tr]=Python biçem denetimi Name[uk]=Перевірка стилю програмування Python Name[x-test]=xxPython style checkingxx +Name[zh_CN]=Python 样式检查 Name[zh_TW]=Python 樣式檢查 diff --git a/pep8kcm/kcm_pep8.cpp b/pep8kcm/kcm_pep8.cpp index 71a23a3e..16ba0c2e 100644 --- a/pep8kcm/kcm_pep8.cpp +++ b/pep8kcm/kcm_pep8.cpp @@ -24,16 +24,14 @@ #include #include #include -#include -#include #include +#include -K_PLUGIN_FACTORY(PEP8KCModuleFactory, registerPlugin(); ) -K_EXPORT_PLUGIN(PEP8KCModuleFactory("kcm_pep8", "kdevpythonsupport")) +K_PLUGIN_FACTORY(PEP8KCModuleFactory, registerPlugin();) PEP8KCModule::PEP8KCModule(QWidget* parent, const QVariantList& args) - : KCModule(PEP8KCModuleFactory::componentData(), parent, args) + : KCModule(parent, args) { KConfig* config = new KConfig("kdevpythonsupportrc"); configGroup = config->group("pep8"); @@ -46,7 +44,7 @@ PEP8KCModule::PEP8KCModule(QWidget* parent, const QVariantList& args) QLabel* argumentlabel = new QLabel(i18n("PEP8 checker arguments:")); QLabel* enablelabel = new QLabel(i18n("Enable PEP8 checking:")); pep8url = new QLineEdit(configGroup.readEntry("pep8url", "/usr/bin/pep8-python2")); - pep8arguments = new QLineEdit(configGroup.readEntry("pap8arguments", "")); + pep8arguments = new QLineEdit(configGroup.readEntry("pep8arguments", "")); enableChecking = new QCheckBox; enableChecking->setChecked(configGroup.readEntry("pep8enabled", false)); formlayout->addRow(urllabel, pep8url); @@ -62,7 +60,7 @@ PEP8KCModule::PEP8KCModule(QWidget* parent, const QVariantList& args) void PEP8KCModule::save() { configGroup.writeEntry("pep8url", pep8url->text()); - configGroup.writeEntry("pap8arguments", pep8arguments->text()); + configGroup.writeEntry("pep8arguments", pep8arguments->text()); configGroup.writeEntry("pep8enabled", enableChecking->isChecked()); KCModule::save(); } @@ -72,3 +70,4 @@ PEP8KCModule::~PEP8KCModule() delete configGroup.config(); } +#include "kcm_pep8.moc" diff --git a/pep8kcm/kcm_pep8.h b/pep8kcm/kcm_pep8.h index e837d102..24d885ce 100644 --- a/pep8kcm/kcm_pep8.h +++ b/pep8kcm/kcm_pep8.h @@ -25,8 +25,11 @@ #include #include +#include + class PEP8KCModule : public KCModule { +Q_OBJECT public: PEP8KCModule( QWidget* parent, const QVariantList& args = QVariantList() ); virtual void save(); diff --git a/pythondebug.cpp b/pythondebug.cpp new file mode 100644 index 00000000..4c845f30 --- /dev/null +++ b/pythondebug.cpp @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "pythondebug.h" +Q_LOGGING_CATEGORY(KDEV_PYTHON, "kdev.python") + + diff --git a/pythondebug.h b/pythondebug.h new file mode 100644 index 00000000..5851dc46 --- /dev/null +++ b/pythondebug.h @@ -0,0 +1,27 @@ +/* This file is part of the KDE project + Copyright (C) 2014 Laurent Navet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PYTHONDEBUG_H +#define PYTHONDEBUG_H + +#include +Q_DECLARE_LOGGING_CATEGORY(KDEV_PYTHON) + +#endif + diff --git a/pythonlanguagesupport.cpp b/pythonlanguagesupport.cpp index d8a720f6..9ac3e500 100644 --- a/pythonlanguagesupport.cpp +++ b/pythonlanguagesupport.cpp @@ -22,16 +22,14 @@ #include -#include #include -#include + #include #include #include #include #include -#include #include #include #include @@ -40,6 +38,8 @@ #include #include #include +#include +#include #include #include #include @@ -55,6 +55,9 @@ #include "kdevpythonversion.h" #include "checks/basiccheck.h" +#include +#include "pythondebug.h" + using namespace KDevelop; K_PLUGIN_FACTORY( KDevPythonSupportFactory, registerPlugin(); ) @@ -74,7 +77,7 @@ KDevelop::ContextMenuExtension LanguageSupport::contextMenuExtension(KDevelop::C ContextMenuExtension cm; EditorContext *ec = dynamic_cast(context); - if (ec && ICore::self()->languageController()->languagesForUrl(ec->url()).contains(language())) { + if (ec && ICore::self()->languageController()->languagesForUrl(ec->url()).contains(this)) { // It's a Python file, let's add our context menu. m_refactoring->fillContextMenu(cm, context); TypeCorrection::self().doContextMenu(cm, context); @@ -83,26 +86,29 @@ KDevelop::ContextMenuExtension LanguageSupport::contextMenuExtension(KDevelop::C } LanguageSupport::LanguageSupport( QObject* parent, const QVariantList& /*args*/ ) - : KDevelop::IPlugin( KDevPythonSupportFactory::componentData(), parent ), - KDevelop::ILanguageSupport() + : KDevelop::IPlugin("pythonlanguagesupport", parent ) + , KDevelop::ILanguageSupport() + , m_highlighting( new Highlighting( this ) ) + , m_refactoring( new Refactoring( this ) ) { KDEV_USE_EXTENSION_INTERFACE( KDevelop::ILanguageSupport ) KDEV_USE_EXTENSION_INTERFACE( KDevelop::ILanguageCheckProvider ) m_self = this; - m_highlighting = new Highlighting( this ); - m_refactoring = new Refactoring(this); PythonCodeCompletionModel* codeCompletion = new PythonCodeCompletionModel(this); new KDevelop::CodeCompletion(this, codeCompletion, "Python"); + auto assistantsManager = core()->languageController()->staticAssistantsManager(); + assistantsManager->registerAssistant(StaticAssistant::Ptr(new RenameAssistant(this))); + QObject::connect(ICore::self()->documentController(), SIGNAL(documentOpened(KDevelop::IDocument*)), this, SLOT(documentOpened(KDevelop::IDocument*))); } void LanguageSupport::documentOpened(IDocument* doc) { - if ( ! ICore::self()->languageController()->languagesForUrl(doc->url()).contains(language()) ) { + if ( ! ICore::self()->languageController()->languagesForUrl(doc->url()).contains(this) ) { // not a python file return; } @@ -139,15 +145,15 @@ LanguageSupport* LanguageSupport::self() return m_self; } -bool LanguageSupport::enabledForFile(const KUrl& url) +bool LanguageSupport::enabledForFile(const QUrl& url) { // This is a bit more general than it would need to be, // but that way we can have the same code for both branches. - QList< ILanguage* > enabledLanguages = ICore::self()->languageController()->languagesForUrl(url); + const auto enabledLanguages = ICore::self()->languageController()->languagesForUrl(url); const QString& name = LanguageSupport::self()->name(); static const QString otherName = ( name == "Python3" ? "Python" : "Python3" ); bool haveBoth = false; - foreach ( const ILanguage* lang, enabledLanguages ) { + foreach ( const auto lang, enabledLanguages ) { if ( lang->name() == otherName ) { // both py2 and py3 plugins are installed haveBoth = true; @@ -189,15 +195,14 @@ SourceFormatterItemList LanguageSupport::sourceFormatterItems() const return SourceFormatterItemList{SourceFormatterStyleItem{"customscript", autopep8}}; } -KDevelop::ILanguage *LanguageSupport::language() +KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const { - kDebug() << core()->languageController()->language( name() ); - return core()->languageController()->language( name() ); + return m_highlighting; } -KDevelop::ICodeHighlighting* LanguageSupport::codeHighlighting() const +BasicRefactoring* LanguageSupport::refactoring() const { - return m_highlighting; + return m_refactoring; } ILanguageSupport::WhitespaceSensitivity LanguageSupport::whitespaceSensititivy() const diff --git a/pythonlanguagesupport.h b/pythonlanguagesupport.h index 0219612d..c431131a 100644 --- a/pythonlanguagesupport.h +++ b/pythonlanguagesupport.h @@ -59,10 +59,9 @@ class LanguageSupport QString name() const; /*Parsejob used by background parser to parse given Url*/ KDevelop::ParseJob *createParseJob( const KDevelop::IndexedString &url ); - /*the actual language object*/ - KDevelop::ILanguage *language(); /*the code highlighter*/ KDevelop::ICodeHighlighting* codeHighlighting() const; + virtual KDevelop::BasicRefactoring* refactoring() const override; KDevelop::ContextMenuExtension contextMenuExtension(KDevelop::Context* context); @@ -73,7 +72,7 @@ class LanguageSupport virtual KDevelop::SourceFormatterItemList sourceFormatterItems() const; /// Tells whether this plugin is enabled for the given file. - static bool enabledForFile(const KUrl& url); + static bool enabledForFile(const QUrl& url); virtual QList providedChecks(); diff --git a/pythonparsejob.cpp b/pythonparsejob.cpp index dd449b9f..3571ed27 100644 --- a/pythonparsejob.cpp +++ b/pythonparsejob.cpp @@ -29,12 +29,13 @@ #include "checks/controlflowgraphbuilder.h" #include "checks/dataaccessvisitor.h" #include "kshell.h" +#include "duchain/helpers.h" #include #include #include #include -#include +#include #include #include #include @@ -42,11 +43,13 @@ #include #include #include -#include #include #include #include +#include #include +#include +#include #include @@ -55,10 +58,12 @@ #include #include #include -#include +#include #include #include +#include + using namespace KDevelop; namespace Python @@ -69,6 +74,12 @@ ParseJob::ParseJob(const IndexedString &url, ILanguageSupport* languageSupport) , m_ast(0) , m_duContext(0) { + IDefinesAndIncludesManager* iface = IDefinesAndIncludesManager::manager(); + foreach (IProject* project, ICore::self()->projectController()->projects() ) { + foreach (Path path, iface->includes(project->projectItem(), IDefinesAndIncludesManager::UserDefined)) { + m_cachedCustomIncludes.append(path.toUrl()); + } + } } ParseJob::~ParseJob() @@ -81,7 +92,8 @@ CodeAst *ParseJob::ast() const return m_ast.data(); } -void ParseJob::run() + +void ParseJob::run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread* thread) { if ( abortRequested() || ICore::self()->shuttingDown() ) { return abortJob(); @@ -90,9 +102,14 @@ void ParseJob::run() qDebug() << " ====> PARSING ====> parsing file " << document().toUrl() << "; has priority" << parsePriority(); // lock the URL so no other parse job can run on this document - QReadLocker parselock(languageSupport()->language()->parseLock()); + QReadLocker parselock(languageSupport()->parseLock()); UrlParseLock urlLock(document()); - + + { + QMutexLocker lock(&Helper::cacheMutex); + Helper::cachedCustomIncludes = m_cachedCustomIncludes; + } + readContents(); if ( !(minimumFeatures() & TopDUContext::ForceUpdate || minimumFeatures() & Rescheduled) ) { @@ -157,7 +174,7 @@ void ParseJob::run() // check whether any unresolved imports were encountered bool needsReparse = ! builder.unresolvedImports().isEmpty(); - kDebug() << "Document needs update because of unresolved identifiers: " << needsReparse; + qDebug() << "Document needs update because of unresolved identifiers: " << needsReparse; if ( needsReparse ) { // check whether one of the imports is queued for parsing, this is to avoid deadlocks // it's also ok if the duchain is now available (and thus has been parsed before already) @@ -189,7 +206,7 @@ void ParseJob::run() DUChain::self()->updateContextEnvironment(m_duContext, parsingEnvironmentFile.data()); } - kDebug() << "---- Parsing Succeeded ----"; + qDebug() << "---- Parsing Succeeded ----"; if ( abortRequested() ) { return abortJob(); @@ -200,7 +217,7 @@ void ParseJob::run() } else { // No syntax tree was received from the parser, the expected reason for this is a syntax error in the document. - kWarning() << "---- Parsing FAILED ----"; + qWarning() << "---- Parsing FAILED ----"; DUChainWriteLocker lock; m_duContext = toUpdate.data(); // if there's already a chain for the document, do some cleanup. @@ -241,7 +258,7 @@ void ParseJob::run() if ( minimumFeatures() & TopDUContext::AST ) { DUChainWriteLocker lock; m_currentSession->ast = m_ast; - m_duContext->setAst(KSharedPtr::staticCast(m_currentSession)); + m_duContext->setAst(QExplicitlySharedDataPointer(m_currentSession.data())); } setDuChain(m_duContext); @@ -285,7 +302,7 @@ void ParseJob::eventuallyDoPEP8Checking(const IndexedString document, TopDUConte DUChainWriteLocker lock; topContext->setFeatures((TopDUContext::Features) ( topContext->features() | PEP8Checking )); } - kDebug() << "doing pep8 checking"; + qDebug() << "doing pep8 checking"; // TODO that's not very elegant, better would be making pep8 read from stdin -- but it doesn't support that atm QTemporaryFile tempfile; tempfile.open(); @@ -322,12 +339,12 @@ void ParseJob::eventuallyDoPEP8Checking(const IndexedString document, TopDUConte int lineno = texts.at(2).toInt(&lineno_ok); int colno = texts.at(3).toInt(&colno_ok); if ( ! lineno_ok || ! colno_ok ) { - kDebug() << "invalid line / col number:" << texts; + qDebug() << "invalid line / col number:" << texts; continue; } QString error = texts.at(4); KDevelop::Problem *p = new KDevelop::Problem(); - p->setFinalLocation(DocumentRange(document, SimpleRange(lineno - 1, qMax(colno - 4, 0), + p->setFinalLocation(DocumentRange(document, KTextEditor::Range(lineno - 1, qMax(colno - 4, 0), lineno - 1, colno + 4))); p->setSource(KDevelop::ProblemData::Preprocessor); p->setSeverity(KDevelop::ProblemData::Warning); @@ -336,14 +353,14 @@ void ParseJob::eventuallyDoPEP8Checking(const IndexedString document, TopDUConte topContext->addProblem(ptr); } else { - kDebug() << "invalid pep8 error line:" << error; + qDebug() << "invalid pep8 error line:" << error; } } } if ( error ) { DUChainWriteLocker lock; KDevelop::Problem *p = new KDevelop::Problem(); - p->setFinalLocation(DocumentRange(document, SimpleRange(0, 0, 0, 0))); + p->setFinalLocation(DocumentRange(document, KTextEditor::Range(0, 0, 0, 0))); p->setSource(KDevelop::ProblemData::Preprocessor); p->setSeverity(KDevelop::ProblemData::Warning); p->setDescription(i18n("The selected PEP8 syntax checker \"%1\" does not seem to work correctly.", url)); diff --git a/pythonparsejob.h b/pythonparsejob.h index 29ce2084..6b59176f 100644 --- a/pythonparsejob.h +++ b/pythonparsejob.h @@ -60,9 +60,10 @@ class ParseJob : public KDevelop::ParseJob virtual DataAccessRepository* dataAccessInformation(); protected: - virtual void run(); + virtual void run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread* thread) override; private: + QList m_cachedCustomIncludes; CodeAst::Ptr m_ast; bool m_readFromDisk; KDevelop::ReferencedTopDUContext m_duContext; diff --git a/runtest.py b/runtest.py index 7498e92c..e9939919 100755 --- a/runtest.py +++ b/runtest.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +# Copyright 2014 by Sven Brauch +# License: GPL v2+ + import sys import subprocess