diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6fcc3e24dd..76e842cb90 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,177 +1,168 @@
cmake_minimum_required(VERSION 3.0)
project(KDevelop)
# KDevelop version
set(KDEVELOP_VERSION_MAJOR 5)
set(KDEVELOP_VERSION_MINOR 1)
set(KDEVELOP_VERSION_PATCH 40)
set( KDEVELOP_VERSION "${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}.${KDEVELOP_VERSION_PATCH}" )
# plugin versions listed in the .desktop files
set(KDEV_PLUGIN_VERSION 30)
# we need some parts of the ECM CMake helpers
find_package (ECM 5.14.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${KDevelop_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH})
include(KDECompilerSettings NO_POLICY_SCOPE) # needs to be first, as set policies influence following macros
include(ECMOptionalAddSubdirectory)
include(ECMInstallIcons)
include(ECMAddAppIcon)
include(ECMSetupVersion)
include(ECMAddTests)
include(ECMMarkNonGuiExecutable)
include(ECMGenerateHeaders)
include(ECMQtDeclareLoggingCategory)
include(GenerateExportHeader)
include(CMakePackageConfigHelpers)
include(FeatureSummary)
include(WriteBasicConfigVersionFile)
include(CheckFunctionExists)
include(KDEInstallDirs)
include(KDECMakeSettings)
set(QT_MIN_VERSION "5.5.0")
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Widgets Concurrent Quick QuickWidgets)
if(BUILD_TESTING)
find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED)
endif()
set(KF5_DEP_VERSION "5.15.0") # we need KCrash::initialize
find_package(KF5 ${KF5_DEP_VERSION} REQUIRED COMPONENTS
Config
Declarative
DocTools
IconThemes
I18n
ItemModels
ItemViews
JobWidgets
KCMUtils
KIO
NewStuff
NotifyConfig
Parts
Service
TextEditor
ThreadWeaver
XmlGui
WindowSystem
Crash
GuiAddons
Archive
Notifications
)
find_package(KF5SysGuard CONFIG)
set_package_properties(KF5SysGuard PROPERTIES
PURPOSE "Framework for process listing. Required for the 'Attach to Process' feature"
TYPE RECOMMENDED
)
find_package(KDevelop-PG-Qt 1.90.90 CONFIG)
set_package_properties(KDevelop-PG-Qt PROPERTIES
PURPOSE "KDevelop parser generator library. Required for the QMake Builder/Manager plugin."
TYPE RECOMMENDED
)
find_package(SharedMimeInfo REQUIRED)
add_definitions(
-DQT_DEPRECATED_WARNINGS
-DQT_DISABLE_DEPRECATED_BEFORE=0x050500
-DQT_NO_SIGNALS_SLOTS_KEYWORDS
-DQT_NO_URL_CAST_FROM_STRING
-DQT_STRICT_ITERATORS
-DQT_USE_QSTRINGBUILDER
)
function(add_compile_flag_if_supported _flag)
unset(_have_flag CACHE)
string(REGEX REPLACE "[-=]" "_" _varname ${_flag})
string(TOUPPER ${_varname} _varname)
set(_varname "HAVE${_varname}")
check_cxx_compiler_flag("${_flag}" "${_varname}")
if (${${_varname}})
add_compile_options(${_flag})
endif()
endfunction()
# Turn off missing-field-initializers warning for GCC to avoid noise from false positives with empty {}
# See discussion: http://mail.kde.org/pipermail/kdevelop-devel/2014-February/046910.html
add_compile_flag_if_supported(-Wno-missing-field-initializers)
add_compile_flag_if_supported(-Werror=undefined-bool-conversion)
add_compile_flag_if_supported(-Werror=tautological-undefined-compare)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_flag_if_supported(-Wdocumentation)
# This warning is triggered by every call to qCDebug()
add_compile_flag_if_supported(-Wno-gnu-zero-variadic-macro-arguments)
endif()
if (CMAKE_COMPILER_CXX_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_flag_if_supported(-pedantic)
endif()
include_directories(${KDevelop_SOURCE_DIR} ${KDevelop_BINARY_DIR})
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER)
if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug"
OR CMAKE_BUILD_TYPE_TOLOWER STREQUAL "")
set(COMPILER_OPTIMIZATIONS_DISABLED TRUE)
else()
set(COMPILER_OPTIMIZATIONS_DISABLED FALSE)
endif()
# create config-kdevelop.h
configure_file(config-kdevelop.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kdevelop.h)
add_subdirectory(kdevplatform)
+add_subdirectory(plugins)
+
add_subdirectory(pics)
add_subdirectory(app)
-add_subdirectory(analyzers)
-add_subdirectory(formatters)
-add_subdirectory(languages)
-add_subdirectory(projectbuilders)
-add_subdirectory(projectmanagers)
-add_subdirectory(debuggers)
add_subdirectory(app_templates)
-add_subdirectory(documentation)
-add_subdirectory(kdeintegration)
-add_subdirectory(utils)
add_subdirectory(file_templates)
-add_subdirectory(providers)
-add_subdirectory(runtimes)
add_subdirectory(shortcuts)
add_subdirectory(doc)
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KDevelop")
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KDevelopConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KDevelopConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
ecm_setup_version(${KDEVELOP_VERSION_MAJOR}.${KDEVELOP_VERSION_MINOR}.${KDEVELOP_VERSION_PATCH}
VARIABLE_PREFIX KDEVELOP
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdevelop_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDevelopConfigVersion.cmake"
SOVERSION ${KDEVELOP_LIB_SOVERSION}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/kdevelop_version.h"
DESTINATION "${KDE_INSTALL_INCLUDEDIR}/kdevelop")
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KDevelopConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KDevelopConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}" )
install(EXPORT KDevelopTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" NAMESPACE KDev:: FILE KDevelopTargets.cmake)
# kdebugsettings file
install(FILES kdevelop.categories DESTINATION ${KDE_INSTALL_CONFDIR})
# CTestCustom.cmake has to be in the CTEST_BINARY_DIR.
# in the KDE build system, this is the same as CMAKE_BINARY_DIR.
configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_BINARY_DIR}/CTestCustom.cmake)
install(FILES org.kde.kdevelop.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
# Make it possible to use the po files fetched by the fetch-translations step
ki18n_install("${CMAKE_CURRENT_BINARY_DIR}/po")
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/analyzers/CMakeLists.txt b/analyzers/CMakeLists.txt
deleted file mode 100644
index e2ecc53151..0000000000
--- a/analyzers/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-add_subdirectory(cppcheck)
-add_subdirectory(heaptrack)
diff --git a/app_templates/cpp/CMake/cmake_qt5guiapp/src/%{APPNAMELC}.ui b/app_templates/cpp/CMake/cmake_qt5guiapp/src/%{APPNAMELC}.ui
index 069982a1b2..9016e2e08c 100644
--- a/app_templates/cpp/CMake/cmake_qt5guiapp/src/%{APPNAMELC}.ui
+++ b/app_templates/cpp/CMake/cmake_qt5guiapp/src/%{APPNAMELC}.ui
@@ -1,24 +1,30 @@
+
%{APPNAME}
-
-
+
+
0
0
400
300
-
+
%{APPNAME}
-
-
-
-
+
+
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
-
-
diff --git a/app_templates/cpp/QMake/qmake_qt5guiapp/mainwindow.ui b/app_templates/cpp/QMake/qmake_qt5guiapp/mainwindow.ui
index b068b73b28..59e0bcac66 100644
--- a/app_templates/cpp/QMake/qmake_qt5guiapp/mainwindow.ui
+++ b/app_templates/cpp/QMake/qmake_qt5guiapp/mainwindow.ui
@@ -1,19 +1,20 @@
-
+
+
MainWindow
-
-
+
+
0
0
800
600
-
+
%{APPNAME}
-
+
diff --git a/kdevplatform/cmake/modules/FindSubversionLibrary.cmake b/cmake/modules/FindSubversionLibrary.cmake
similarity index 100%
rename from kdevplatform/cmake/modules/FindSubversionLibrary.cmake
rename to cmake/modules/FindSubversionLibrary.cmake
diff --git a/debuggers/CMakeLists.txt b/debuggers/CMakeLists.txt
deleted file mode 100644
index bb6f2b7a8d..0000000000
--- a/debuggers/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-include_directories(common)
-
-include_directories(${CMAKE_CURRENT_BINARY_DIR}) # for config files in common
-
-if(NOT WIN32)
- # TODO: Make compile under Windows
- add_subdirectory(common)
- add_subdirectory(lldb)
- add_subdirectory(gdb)
-endif()
diff --git a/kdeintegration/CMakeLists.txt b/kdeintegration/CMakeLists.txt
deleted file mode 100644
index 68d9999f60..0000000000
--- a/kdeintegration/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-ecm_optional_add_subdirectory(executeplasmoid)
diff --git a/kdevplatform/CMakeLists.txt b/kdevplatform/CMakeLists.txt
index 7cdfceab47..12724fab97 100644
--- a/kdevplatform/CMakeLists.txt
+++ b/kdevplatform/CMakeLists.txt
@@ -1,95 +1,94 @@
# kdevplatform version
set(KDEVPLATFORM_VERSION_MAJOR 5)
set(KDEVPLATFORM_VERSION_MINOR 1)
set(KDEVPLATFORM_VERSION_PATCH 40)
set(KDEVPLATFORM_VERSION "${KDEVPLATFORM_VERSION_MAJOR}.${KDEVPLATFORM_VERSION_MINOR}.${KDEVPLATFORM_VERSION_PATCH}")
# Increase this to reset incompatible item-repositories
set(KDEV_ITEMREPOSITORY_VERSION 87)
# library version / SO version
set(KDEVPLATFORM_LIB_SOVERSION 10)
set(KDevPlatform_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(KDevPlatform_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_MODULE_PATH ${KDevPlatform_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH})
include(KDevPlatformMacros)
include(KDevPlatformMacrosInternal)
find_package(Grantlee5 CONFIG)
set_package_properties(Grantlee5 PROPERTIES
PURPOSE "Grantlee templating library, needed for file templates"
URL "http://www.grantlee.org/"
TYPE REQUIRED)
set(Boost_ADDITIONAL_VERSIONS 1.39.0 1.39)
find_package(Boost 1.35.0)
set_package_properties(Boost PROPERTIES
PURPOSE "Boost libraries for enabling the classbrowser"
URL "http://www.boost.org"
TYPE REQUIRED)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config-kdevplatform.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config-kdevplatform.h )
include_directories(${KDevPlatform_SOURCE_DIR} ${KDevPlatform_BINARY_DIR})
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER)
if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug"
OR CMAKE_BUILD_TYPE_TOLOWER STREQUAL "")
set(COMPILER_OPTIMIZATIONS_DISABLED TRUE)
else()
set(COMPILER_OPTIMIZATIONS_DISABLED FALSE)
endif()
add_subdirectory(sublime)
add_subdirectory(interfaces)
add_subdirectory(project)
add_subdirectory(language)
add_subdirectory(shell)
add_subdirectory(util)
add_subdirectory(outputview)
add_subdirectory(vcs)
add_subdirectory(pics)
add_subdirectory(debugger)
add_subdirectory(documentation)
add_subdirectory(serialization)
add_subdirectory(template)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
-add_subdirectory(plugins)
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KDevPlatform")
if(BUILD_TESTING)
set(KDEV_FIND_DEP_QT5TEST "find_dependency(Qt5Test \"${QT_MIN_VERSION}\")")
endif()
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KDevPlatformConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KDevPlatformConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
ecm_setup_version(${KDEVPLATFORM_VERSION_MAJOR}.${KDEVPLATFORM_VERSION_MINOR}.${KDEVPLATFORM_VERSION_PATCH}
VARIABLE_PREFIX KDEVPLATFORM
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdevplatform_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDevPlatformConfigVersion.cmake"
SOVERSION ${KDEVPLATFORM_LIB_SOVERSION})
install( FILES
"${KDevPlatform_BINARY_DIR}/kdevplatform_version.h"
"${KDevPlatform_BINARY_DIR}/config-kdevplatform.h"
DESTINATION "${KDE_INSTALL_INCLUDEDIR}/kdevplatform" )
install( FILES
"${KDevPlatform_BINARY_DIR}/KDevPlatformConfig.cmake"
"${KDevPlatform_BINARY_DIR}/KDevPlatformConfigVersion.cmake"
cmake/modules/KDevPlatformMacros.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}" )
install( EXPORT KDevPlatformTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
NAMESPACE KDev::
FILE KDevPlatformTargets.cmake )
# kdebugsettings file
install( FILES kdevplatform.categories DESTINATION ${KDE_INSTALL_CONFDIR} )
diff --git a/kdevplatform/plugins/CMakeLists.txt b/kdevplatform/plugins/CMakeLists.txt
deleted file mode 100644
index 3ff1506963..0000000000
--- a/kdevplatform/plugins/CMakeLists.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-ecm_optional_add_subdirectory(konsole)
-add_subdirectory(filemanager)
-add_subdirectory(appwizard)
-add_subdirectory(projectmanagerview)
-add_subdirectory(genericprojectmanager)
-add_subdirectory(standardoutputview)
-add_subdirectory(documentview)
-add_subdirectory(quickopen)
-add_subdirectory(executescript)
-add_subdirectory(contextbrowser)
-ecm_optional_add_subdirectory(cvs)
-add_subdirectory(problemreporter)
-add_subdirectory(execute)
-add_subdirectory(externalscript)
-add_subdirectory(documentswitcher)
-add_subdirectory(sourceformatter)
-add_subdirectory(patchreview)
-add_subdirectory(openwith)
-add_subdirectory(grepview)
-ecm_optional_add_subdirectory(git)
-ecm_optional_add_subdirectory(bazaar)
-ecm_optional_add_subdirectory(perforce)
-add_subdirectory(vcschangesview)
-if (UNIX)
- add_subdirectory(flatpak)
- add_subdirectory(docker)
-endif ()
-add_subdirectory(filetemplates)
-add_subdirectory(codeutils)
-add_subdirectory(testview)
-add_subdirectory(switchtobuddy)
-add_subdirectory(projectfilter)
-if (Qt5QuickWidgets_FOUND)
- add_subdirectory(welcomepage)
-endif()
-add_subdirectory(outlineview)
-
-ecm_optional_add_subdirectory(classbrowser)
-
-find_package(SubversionLibrary)
-set_package_properties(SubversionLibrary PROPERTIES
- PURPOSE "Support for Subversion integration"
- URL "http://subversion.tigris.org"
- TYPE OPTIONAL)
-
-if(SubversionLibrary_FOUND)
- ecm_optional_add_subdirectory(subversion)
-endif()
diff --git a/languages/.krazy b/languages/.krazy
deleted file mode 100644
index dae47df223..0000000000
--- a/languages/.krazy
+++ /dev/null
@@ -1 +0,0 @@
-SKIP /cpp/app_templates/
diff --git a/languages/CMakeLists.txt b/languages/CMakeLists.txt
deleted file mode 100644
index 72327d2b2e..0000000000
--- a/languages/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-ecm_optional_add_subdirectory(plugins)
-ecm_optional_add_subdirectory(qmljs)
-
-find_package(Clang 3.8)
-set(clangSearchHint "")
-if (NOT CLANG_FOUND)
- set(clangSearchHint "Please install a package providing libclang. Either pass -DLLVM_ROOT=/path/to/llvm-prefix or install the 'llvm-config' command-line utility for auto-detection.")
-endif()
-set_package_properties(Clang PROPERTIES
- DESCRIPTION "Clang libraries from the LLVM project. ${clangSearchHint}"
- PURPOSE "Used for KDevelop's C++/C support plugin."
- TYPE REQUIRED
-)
-
-if (CLANG_FOUND)
- if (NOT CLANG_LIBCLANG_LIB)
- message(FATAL_ERROR "Could not find the Clang C library: libclang")
- endif()
-
- ecm_optional_add_subdirectory(clang)
-endif()
diff --git a/languages/plugins/CMakeLists.txt b/languages/plugins/CMakeLists.txt
deleted file mode 100644
index b8ede3f5df..0000000000
--- a/languages/plugins/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-ecm_optional_add_subdirectory(custom-definesandincludes)
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644
index 0000000000..bac6ae7bae
--- /dev/null
+++ b/plugins/CMakeLists.txt
@@ -0,0 +1,150 @@
+# BEGIN: Analyzers
+add_subdirectory(cppcheck)
+add_subdirectory(heaptrack)
+# END: Analyzers
+
+# BEGIN: Debuggers
+if(NOT WIN32)
+ # TODO: Make compile under Windows
+ add_subdirectory(debuggercommon)
+ add_subdirectory(lldb)
+ add_subdirectory(gdb)
+endif()
+# END: Debuggers
+
+# BEGIN: Documentation
+find_package(Qt5Help CONFIG)
+set_package_properties(Qt5Help PROPERTIES
+ PURPOSE "The Help module for the Qt toolkit, needed for the qthelp plugin"
+ URL "https://www.qt.io/"
+ TYPE OPTIONAL)
+if(Qt5Help_FOUND)
+ ecm_optional_add_subdirectory(qthelp)
+endif()
+ecm_optional_add_subdirectory(manpage)
+# END: Documentation
+
+# BEGIN: Formatters
+add_subdirectory(astyle)
+add_subdirectory(customscript)
+# END: Formatters
+
+# BEGIN: Languages
+ecm_optional_add_subdirectory(custom-definesandincludes)
+ecm_optional_add_subdirectory(qmljs)
+
+find_package(Clang 3.8)
+set(clangSearchHint "")
+if (NOT CLANG_FOUND)
+ set(clangSearchHint "Please install a package providing libclang. Either pass -DLLVM_ROOT=/path/to/llvm-prefix or install the 'llvm-config' command-line utility for auto-detection.")
+endif()
+set_package_properties(Clang PROPERTIES
+ DESCRIPTION "Clang libraries from the LLVM project. ${clangSearchHint}"
+ PURPOSE "Used for KDevelop's C++/C support plugin."
+ TYPE REQUIRED
+)
+
+if (CLANG_FOUND)
+ if (NOT CLANG_LIBCLANG_LIB)
+ message(FATAL_ERROR "Could not find the Clang C library: libclang")
+ endif()
+
+ ecm_optional_add_subdirectory(clang)
+endif()
+# END: Languages
+
+# BEGIN: Project builders
+add_subdirectory(makebuilder)
+add_subdirectory(ninjabuilder)
+ecm_optional_add_subdirectory(cmakebuilder)
+if (KDevelop-PG-Qt_FOUND)
+ ecm_optional_add_subdirectory(qmakebuilder)
+endif()
+# END: Project builders
+
+# BEGIN: Project managers
+ecm_optional_add_subdirectory(cmake)
+ecm_optional_add_subdirectory(custommake)
+ecm_optional_add_subdirectory(custom-buildsystem)
+if (KDevelop-PG-Qt_FOUND)
+ ecm_optional_add_subdirectory(qmakemanager)
+endif()
+ecm_optional_add_subdirectory(genericprojectmanager)
+# END: Project managers
+
+# BEGIN: Runtimes
+add_subdirectory(android)
+if (UNIX)
+ add_subdirectory(docker)
+ add_subdirectory(flatpak)
+endif()
+# END: Runtimes
+
+# BEGIN: VCS
+ecm_optional_add_subdirectory(bazaar)
+ecm_optional_add_subdirectory(cvs)
+ecm_optional_add_subdirectory(git)
+ecm_optional_add_subdirectory(perforce)
+
+find_package(SubversionLibrary)
+set_package_properties(SubversionLibrary PROPERTIES
+ PURPOSE "Support for Subversion integration"
+ URL "http://subversion.tigris.org"
+ TYPE OPTIONAL)
+
+if(SubversionLibrary_FOUND)
+ ecm_optional_add_subdirectory(subversion)
+endif()
+
+add_subdirectory(vcschangesview)
+# END: VCS
+
+# BEGIN: Others
+add_subdirectory(appwizard)
+add_subdirectory(codeutils)
+add_subdirectory(contextbrowser)
+add_subdirectory(documentswitcher)
+add_subdirectory(documentview)
+add_subdirectory(execute)
+add_subdirectory(executescript)
+add_subdirectory(externalscript)
+add_subdirectory(filemanager)
+add_subdirectory(filetemplates)
+add_subdirectory(grepview)
+add_subdirectory(openwith)
+add_subdirectory(outlineview)
+add_subdirectory(patchreview)
+add_subdirectory(problemreporter)
+add_subdirectory(projectfilter)
+add_subdirectory(projectmanagerview)
+add_subdirectory(quickopen)
+add_subdirectory(sourceformatter)
+add_subdirectory(standardoutputview)
+add_subdirectory(switchtobuddy)
+add_subdirectory(testview)
+ecm_optional_add_subdirectory(classbrowser)
+ecm_optional_add_subdirectory(executeplasmoid)
+ecm_optional_add_subdirectory(ghprovider)
+ecm_optional_add_subdirectory(kdeprovider)
+ecm_optional_add_subdirectory(konsole)
+if (Qt5QuickWidgets_FOUND)
+ add_subdirectory(welcomepage)
+endif()
+
+find_package(OktetaKastenControllers 0.3.1)
+set_package_properties(OktetaKastenControllers PROPERTIES
+ PURPOSE "Required for building Okteta KDevelop plugin."
+ URL "http://kde.org/"
+ TYPE OPTIONAL)
+if (OktetaKastenControllers_FOUND)
+ find_package( KastenControllers )
+
+ set_package_properties(KastenControllers PROPERTIES
+ PURPOSE "Required for building Okteta KDevelop plugin."
+ URL "http://kde.org/"
+ TYPE OPTIONAL)
+endif()
+if (OktetaKastenControllers_FOUND AND KastenControllers_FOUND)
+ add_subdirectory(okteta)
+endif()
+# END: Others
diff --git a/runtimes/android/CMakeLists.txt b/plugins/android/CMakeLists.txt
similarity index 100%
rename from runtimes/android/CMakeLists.txt
rename to plugins/android/CMakeLists.txt
diff --git a/runtimes/android/Messages.sh b/plugins/android/Messages.sh
similarity index 100%
rename from runtimes/android/Messages.sh
rename to plugins/android/Messages.sh
diff --git a/runtimes/android/androidplugin.cpp b/plugins/android/androidplugin.cpp
similarity index 100%
rename from runtimes/android/androidplugin.cpp
rename to plugins/android/androidplugin.cpp
diff --git a/runtimes/android/androidplugin.h b/plugins/android/androidplugin.h
similarity index 100%
rename from runtimes/android/androidplugin.h
rename to plugins/android/androidplugin.h
diff --git a/runtimes/android/androidpreferences.cpp b/plugins/android/androidpreferences.cpp
similarity index 100%
rename from runtimes/android/androidpreferences.cpp
rename to plugins/android/androidpreferences.cpp
diff --git a/runtimes/android/androidpreferences.h b/plugins/android/androidpreferences.h
similarity index 100%
rename from runtimes/android/androidpreferences.h
rename to plugins/android/androidpreferences.h
diff --git a/runtimes/android/androidpreferences.ui b/plugins/android/androidpreferences.ui
similarity index 100%
rename from runtimes/android/androidpreferences.ui
rename to plugins/android/androidpreferences.ui
diff --git a/runtimes/android/androidpreferencessettings.kcfg b/plugins/android/androidpreferencessettings.kcfg
similarity index 100%
rename from runtimes/android/androidpreferencessettings.kcfg
rename to plugins/android/androidpreferencessettings.kcfg
diff --git a/runtimes/android/androidpreferencessettings.kcfgc b/plugins/android/androidpreferencessettings.kcfgc
similarity index 100%
rename from runtimes/android/androidpreferencessettings.kcfgc
rename to plugins/android/androidpreferencessettings.kcfgc
diff --git a/runtimes/android/androidruntime.cpp b/plugins/android/androidruntime.cpp
similarity index 100%
rename from runtimes/android/androidruntime.cpp
rename to plugins/android/androidruntime.cpp
diff --git a/runtimes/android/androidruntime.h b/plugins/android/androidruntime.h
similarity index 100%
rename from runtimes/android/androidruntime.h
rename to plugins/android/androidruntime.h
diff --git a/runtimes/android/kdevandroid.json b/plugins/android/kdevandroid.json
similarity index 100%
rename from runtimes/android/kdevandroid.json
rename to plugins/android/kdevandroid.json
diff --git a/runtimes/android/kdevandroidplugin.qrc b/plugins/android/kdevandroidplugin.qrc
similarity index 100%
rename from runtimes/android/kdevandroidplugin.qrc
rename to plugins/android/kdevandroidplugin.qrc
diff --git a/runtimes/android/kdevandroidplugin.rc b/plugins/android/kdevandroidplugin.rc
similarity index 100%
rename from runtimes/android/kdevandroidplugin.rc
rename to plugins/android/kdevandroidplugin.rc
diff --git a/kdevplatform/plugins/appwizard/CMakeLists.txt b/plugins/appwizard/CMakeLists.txt
similarity index 100%
rename from kdevplatform/plugins/appwizard/CMakeLists.txt
rename to plugins/appwizard/CMakeLists.txt
diff --git a/kdevplatform/plugins/appwizard/Messages.sh b/plugins/appwizard/Messages.sh
similarity index 100%
rename from kdevplatform/plugins/appwizard/Messages.sh
rename to plugins/appwizard/Messages.sh
diff --git a/kdevplatform/plugins/appwizard/README.dox b/plugins/appwizard/README.dox
similarity index 100%
rename from kdevplatform/plugins/appwizard/README.dox
rename to plugins/appwizard/README.dox
diff --git a/kdevplatform/plugins/appwizard/appwizarddialog.cpp b/plugins/appwizard/appwizarddialog.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizarddialog.cpp
rename to plugins/appwizard/appwizarddialog.cpp
diff --git a/kdevplatform/plugins/appwizard/appwizarddialog.h b/plugins/appwizard/appwizarddialog.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizarddialog.h
rename to plugins/appwizard/appwizarddialog.h
diff --git a/kdevplatform/plugins/appwizard/appwizardpagewidget.cpp b/plugins/appwizard/appwizardpagewidget.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizardpagewidget.cpp
rename to plugins/appwizard/appwizardpagewidget.cpp
diff --git a/kdevplatform/plugins/appwizard/appwizardpagewidget.h b/plugins/appwizard/appwizardpagewidget.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizardpagewidget.h
rename to plugins/appwizard/appwizardpagewidget.h
diff --git a/kdevplatform/plugins/appwizard/appwizardplugin.cpp b/plugins/appwizard/appwizardplugin.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizardplugin.cpp
rename to plugins/appwizard/appwizardplugin.cpp
diff --git a/kdevplatform/plugins/appwizard/appwizardplugin.h b/plugins/appwizard/appwizardplugin.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/appwizardplugin.h
rename to plugins/appwizard/appwizardplugin.h
diff --git a/kdevplatform/plugins/appwizard/kdevappwizard.json b/plugins/appwizard/kdevappwizard.json
similarity index 100%
rename from kdevplatform/plugins/appwizard/kdevappwizard.json
rename to plugins/appwizard/kdevappwizard.json
diff --git a/kdevplatform/plugins/appwizard/kdevappwizard.knsrc b/plugins/appwizard/kdevappwizard.knsrc
similarity index 100%
rename from kdevplatform/plugins/appwizard/kdevappwizard.knsrc
rename to plugins/appwizard/kdevappwizard.knsrc
diff --git a/kdevplatform/plugins/appwizard/kdevappwizard.qrc b/plugins/appwizard/kdevappwizard.qrc
similarity index 100%
rename from kdevplatform/plugins/appwizard/kdevappwizard.qrc
rename to plugins/appwizard/kdevappwizard.qrc
diff --git a/kdevplatform/plugins/appwizard/kdevappwizard.rc b/plugins/appwizard/kdevappwizard.rc
similarity index 100%
rename from kdevplatform/plugins/appwizard/kdevappwizard.rc
rename to plugins/appwizard/kdevappwizard.rc
diff --git a/kdevplatform/plugins/appwizard/projectselectionpage.cpp b/plugins/appwizard/projectselectionpage.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectselectionpage.cpp
rename to plugins/appwizard/projectselectionpage.cpp
diff --git a/kdevplatform/plugins/appwizard/projectselectionpage.h b/plugins/appwizard/projectselectionpage.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectselectionpage.h
rename to plugins/appwizard/projectselectionpage.h
diff --git a/kdevplatform/plugins/appwizard/projectselectionpage.ui b/plugins/appwizard/projectselectionpage.ui
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectselectionpage.ui
rename to plugins/appwizard/projectselectionpage.ui
diff --git a/kdevplatform/plugins/appwizard/projecttemplatesmodel.cpp b/plugins/appwizard/projecttemplatesmodel.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/projecttemplatesmodel.cpp
rename to plugins/appwizard/projecttemplatesmodel.cpp
diff --git a/kdevplatform/plugins/appwizard/projecttemplatesmodel.h b/plugins/appwizard/projecttemplatesmodel.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/projecttemplatesmodel.h
rename to plugins/appwizard/projecttemplatesmodel.h
diff --git a/kdevplatform/plugins/appwizard/projectvcspage.cpp b/plugins/appwizard/projectvcspage.cpp
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectvcspage.cpp
rename to plugins/appwizard/projectvcspage.cpp
diff --git a/kdevplatform/plugins/appwizard/projectvcspage.h b/plugins/appwizard/projectvcspage.h
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectvcspage.h
rename to plugins/appwizard/projectvcspage.h
diff --git a/kdevplatform/plugins/appwizard/projectvcspage.ui b/plugins/appwizard/projectvcspage.ui
similarity index 100%
rename from kdevplatform/plugins/appwizard/projectvcspage.ui
rename to plugins/appwizard/projectvcspage.ui
diff --git a/formatters/astyle/3rdparty/libastyle/ASBeautifier.cpp b/plugins/astyle/3rdparty/libastyle/ASBeautifier.cpp
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASBeautifier.cpp
rename to plugins/astyle/3rdparty/libastyle/ASBeautifier.cpp
diff --git a/formatters/astyle/3rdparty/libastyle/ASEnhancer.cpp b/plugins/astyle/3rdparty/libastyle/ASEnhancer.cpp
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASEnhancer.cpp
rename to plugins/astyle/3rdparty/libastyle/ASEnhancer.cpp
diff --git a/formatters/astyle/3rdparty/libastyle/ASFormatter.cpp b/plugins/astyle/3rdparty/libastyle/ASFormatter.cpp
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASFormatter.cpp
rename to plugins/astyle/3rdparty/libastyle/ASFormatter.cpp
diff --git a/formatters/astyle/3rdparty/libastyle/ASLocalizer.cpp b/plugins/astyle/3rdparty/libastyle/ASLocalizer.cpp
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASLocalizer.cpp
rename to plugins/astyle/3rdparty/libastyle/ASLocalizer.cpp
diff --git a/formatters/astyle/3rdparty/libastyle/ASLocalizer.h b/plugins/astyle/3rdparty/libastyle/ASLocalizer.h
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASLocalizer.h
rename to plugins/astyle/3rdparty/libastyle/ASLocalizer.h
diff --git a/formatters/astyle/3rdparty/libastyle/ASResource.cpp b/plugins/astyle/3rdparty/libastyle/ASResource.cpp
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/ASResource.cpp
rename to plugins/astyle/3rdparty/libastyle/ASResource.cpp
diff --git a/formatters/astyle/3rdparty/libastyle/CMakeLists.txt b/plugins/astyle/3rdparty/libastyle/CMakeLists.txt
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/CMakeLists.txt
rename to plugins/astyle/3rdparty/libastyle/CMakeLists.txt
diff --git a/formatters/astyle/3rdparty/libastyle/README b/plugins/astyle/3rdparty/libastyle/README
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/README
rename to plugins/astyle/3rdparty/libastyle/README
diff --git a/formatters/astyle/3rdparty/libastyle/astyle.h b/plugins/astyle/3rdparty/libastyle/astyle.h
similarity index 100%
rename from formatters/astyle/3rdparty/libastyle/astyle.h
rename to plugins/astyle/3rdparty/libastyle/astyle.h
diff --git a/formatters/astyle/CMakeLists.txt b/plugins/astyle/CMakeLists.txt
similarity index 93%
rename from formatters/astyle/CMakeLists.txt
rename to plugins/astyle/CMakeLists.txt
index 78cba0a68b..6d144ec453 100644
--- a/formatters/astyle/CMakeLists.txt
+++ b/plugins/astyle/CMakeLists.txt
@@ -1,36 +1,38 @@
include_directories(lib)
+add_definitions(-DTRANSLATION_DOMAIN=\"kdevastyle\")
+
ecm_qt_declare_logging_category(kdevastyle_LOG_SRCS
HEADER debug.h
IDENTIFIER KDEV_ASTYLE
CATEGORY_NAME "kdevelop.formatters.astyle"
)
set(kdevastyle_PART_SRCS
astyle_plugin.cpp
astyle_preferences.cpp
astyle_formatter.cpp
astyle_stringiterator.cpp
${kdevastyle_LOG_SRCS}
)
set(astyle_preferences_UI
astyle_preferences.ui
)
ki18n_wrap_ui(kdevastyle_PART_SRCS ${astyle_preferences_UI} )
kdevplatform_add_plugin(kdevastyle JSON kdevastyle.json SOURCES ${kdevastyle_PART_SRCS})
target_link_libraries(kdevastyle
astylelib
KF5::Parts
KF5::KIOWidgets
KF5::TextEditor
KDev::Interfaces
KDev::Util)
add_subdirectory(3rdparty/libastyle)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
diff --git a/analyzers/cppcheck/Messages.sh b/plugins/astyle/Messages.sh
similarity index 86%
copy from analyzers/cppcheck/Messages.sh
copy to plugins/astyle/Messages.sh
index 31ca95b09b..05ce893819 100644
--- a/analyzers/cppcheck/Messages.sh
+++ b/plugins/astyle/Messages.sh
@@ -1,4 +1,4 @@
#!/bin/sh
$EXTRACTRC `find . -name \*.rc` `find . -name \*.ui` >>rc.cpp
-$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/kdevcppcheck.pot
+$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/kdevastyle.pot
rm -f rc.cpp
diff --git a/formatters/astyle/astyle_formatter.cpp b/plugins/astyle/astyle_formatter.cpp
similarity index 100%
rename from formatters/astyle/astyle_formatter.cpp
rename to plugins/astyle/astyle_formatter.cpp
diff --git a/formatters/astyle/astyle_formatter.h b/plugins/astyle/astyle_formatter.h
similarity index 100%
rename from formatters/astyle/astyle_formatter.h
rename to plugins/astyle/astyle_formatter.h
diff --git a/formatters/astyle/astyle_plugin.cpp b/plugins/astyle/astyle_plugin.cpp
similarity index 100%
rename from formatters/astyle/astyle_plugin.cpp
rename to plugins/astyle/astyle_plugin.cpp
diff --git a/formatters/astyle/astyle_plugin.h b/plugins/astyle/astyle_plugin.h
similarity index 100%
rename from formatters/astyle/astyle_plugin.h
rename to plugins/astyle/astyle_plugin.h
diff --git a/formatters/astyle/astyle_preferences.cpp b/plugins/astyle/astyle_preferences.cpp
similarity index 100%
rename from formatters/astyle/astyle_preferences.cpp
rename to plugins/astyle/astyle_preferences.cpp
diff --git a/formatters/astyle/astyle_preferences.h b/plugins/astyle/astyle_preferences.h
similarity index 100%
rename from formatters/astyle/astyle_preferences.h
rename to plugins/astyle/astyle_preferences.h
diff --git a/formatters/astyle/astyle_preferences.ui b/plugins/astyle/astyle_preferences.ui
similarity index 100%
rename from formatters/astyle/astyle_preferences.ui
rename to plugins/astyle/astyle_preferences.ui
diff --git a/formatters/astyle/astyle_stringiterator.cpp b/plugins/astyle/astyle_stringiterator.cpp
similarity index 100%
rename from formatters/astyle/astyle_stringiterator.cpp
rename to plugins/astyle/astyle_stringiterator.cpp
diff --git a/formatters/astyle/astyle_stringiterator.h b/plugins/astyle/astyle_stringiterator.h
similarity index 100%
rename from formatters/astyle/astyle_stringiterator.h
rename to plugins/astyle/astyle_stringiterator.h
diff --git a/formatters/astyle/kdevastyle.json b/plugins/astyle/kdevastyle.json
similarity index 100%
rename from formatters/astyle/kdevastyle.json
rename to plugins/astyle/kdevastyle.json
diff --git a/formatters/astyle/tests/CMakeLists.txt b/plugins/astyle/tests/CMakeLists.txt
similarity index 100%
rename from formatters/astyle/tests/CMakeLists.txt
rename to plugins/astyle/tests/CMakeLists.txt
diff --git a/formatters/astyle/tests/test_astyle.cpp b/plugins/astyle/tests/test_astyle.cpp
similarity index 100%
rename from formatters/astyle/tests/test_astyle.cpp
rename to plugins/astyle/tests/test_astyle.cpp
diff --git a/formatters/astyle/tests/test_astyle.h b/plugins/astyle/tests/test_astyle.h
similarity index 100%
rename from formatters/astyle/tests/test_astyle.h
rename to plugins/astyle/tests/test_astyle.h
diff --git a/kdevplatform/plugins/bazaar/CMakeLists.txt b/plugins/bazaar/CMakeLists.txt
similarity index 100%
rename from kdevplatform/plugins/bazaar/CMakeLists.txt
rename to plugins/bazaar/CMakeLists.txt
diff --git a/kdevplatform/plugins/bazaar/bazaar.kdev4 b/plugins/bazaar/bazaar.kdev4
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaar.kdev4
rename to plugins/bazaar/bazaar.kdev4
diff --git a/kdevplatform/plugins/bazaar/bazaarplugin.cpp b/plugins/bazaar/bazaarplugin.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaarplugin.cpp
rename to plugins/bazaar/bazaarplugin.cpp
diff --git a/kdevplatform/plugins/bazaar/bazaarplugin.h b/plugins/bazaar/bazaarplugin.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaarplugin.h
rename to plugins/bazaar/bazaarplugin.h
diff --git a/kdevplatform/plugins/bazaar/bazaarpluginmetadata.cpp b/plugins/bazaar/bazaarpluginmetadata.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaarpluginmetadata.cpp
rename to plugins/bazaar/bazaarpluginmetadata.cpp
diff --git a/kdevplatform/plugins/bazaar/bazaarutils.cpp b/plugins/bazaar/bazaarutils.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaarutils.cpp
rename to plugins/bazaar/bazaarutils.cpp
diff --git a/kdevplatform/plugins/bazaar/bazaarutils.h b/plugins/bazaar/bazaarutils.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/bazaarutils.h
rename to plugins/bazaar/bazaarutils.h
diff --git a/kdevplatform/plugins/bazaar/bzrannotatejob.cpp b/plugins/bazaar/bzrannotatejob.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/bzrannotatejob.cpp
rename to plugins/bazaar/bzrannotatejob.cpp
diff --git a/kdevplatform/plugins/bazaar/bzrannotatejob.h b/plugins/bazaar/bzrannotatejob.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/bzrannotatejob.h
rename to plugins/bazaar/bzrannotatejob.h
diff --git a/kdevplatform/plugins/bazaar/copyjob.cpp b/plugins/bazaar/copyjob.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/copyjob.cpp
rename to plugins/bazaar/copyjob.cpp
diff --git a/kdevplatform/plugins/bazaar/copyjob.h b/plugins/bazaar/copyjob.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/copyjob.h
rename to plugins/bazaar/copyjob.h
diff --git a/kdevplatform/plugins/bazaar/diffjob.cpp b/plugins/bazaar/diffjob.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/diffjob.cpp
rename to plugins/bazaar/diffjob.cpp
diff --git a/kdevplatform/plugins/bazaar/diffjob.h b/plugins/bazaar/diffjob.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/diffjob.h
rename to plugins/bazaar/diffjob.h
diff --git a/kdevplatform/plugins/bazaar/icons/128-apps-bazaar.png b/plugins/bazaar/icons/128-apps-bazaar.png
similarity index 100%
rename from kdevplatform/plugins/bazaar/icons/128-apps-bazaar.png
rename to plugins/bazaar/icons/128-apps-bazaar.png
diff --git a/kdevplatform/plugins/bazaar/icons/CMakeLists.txt b/plugins/bazaar/icons/CMakeLists.txt
similarity index 100%
rename from kdevplatform/plugins/bazaar/icons/CMakeLists.txt
rename to plugins/bazaar/icons/CMakeLists.txt
diff --git a/kdevplatform/plugins/bazaar/kdevbazaar.json b/plugins/bazaar/kdevbazaar.json
similarity index 100%
rename from kdevplatform/plugins/bazaar/kdevbazaar.json
rename to plugins/bazaar/kdevbazaar.json
diff --git a/kdevplatform/plugins/bazaar/tests/CMakeLists.txt b/plugins/bazaar/tests/CMakeLists.txt
similarity index 100%
rename from kdevplatform/plugins/bazaar/tests/CMakeLists.txt
rename to plugins/bazaar/tests/CMakeLists.txt
diff --git a/kdevplatform/plugins/bazaar/tests/test_bazaar.cpp b/plugins/bazaar/tests/test_bazaar.cpp
similarity index 100%
rename from kdevplatform/plugins/bazaar/tests/test_bazaar.cpp
rename to plugins/bazaar/tests/test_bazaar.cpp
diff --git a/kdevplatform/plugins/bazaar/tests/test_bazaar.h b/plugins/bazaar/tests/test_bazaar.h
similarity index 100%
rename from kdevplatform/plugins/bazaar/tests/test_bazaar.h
rename to plugins/bazaar/tests/test_bazaar.h
diff --git a/debuggers/gdb/.kateconfig b/plugins/clang/.kateconfig
similarity index 100%
rename from debuggers/gdb/.kateconfig
rename to plugins/clang/.kateconfig
diff --git a/languages/clang/.reviewboardrc b/plugins/clang/.reviewboardrc
similarity index 100%
rename from languages/clang/.reviewboardrc
rename to plugins/clang/.reviewboardrc
diff --git a/languages/clang/CMakeLists.txt b/plugins/clang/CMakeLists.txt
similarity index 98%
rename from languages/clang/CMakeLists.txt
rename to plugins/clang/CMakeLists.txt
index 7bfe334bcf..cbf6b2c9ce 100644
--- a/languages/clang/CMakeLists.txt
+++ b/plugins/clang/CMakeLists.txt
@@ -1,136 +1,138 @@
add_definitions(-DTRANSLATION_DOMAIN=\"kdevclang\")
add_definitions(${LLVM_CFLAGS})
include_directories(${CLANG_INCLUDE_DIRS})
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/version.h"
@ONLY
)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
add_definitions(
-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII -DQT_NO_CAST_FROM_BYTEARRAY
)
# TODO: Move to kdevplatform
function(add_private_library target)
set(options)
set(oneValueArgs)
set(multiValueArgs SOURCES)
cmake_parse_arguments(KDEV_ADD_PRIVATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
string(REPLACE "KDev" "" shortTargetName ${target})
if (${shortTargetName} STREQUAL ${target})
message(FATAL_ERROR "Target passed to add_private_library needs to start with \"KDev\", was \"${target}\"")
endif()
string(TOLOWER ${shortTargetName} shortTargetNameToLower)
add_library(${target} SHARED ${KDEV_ADD_PRIVATE_SOURCES})
generate_export_header(${target} EXPORT_FILE_NAME ${shortTargetNameToLower}export.h)
set_target_properties(${target} PROPERTIES
VERSION ${KDEV_PLUGIN_VERSION}
SOVERSION ${KDEV_PLUGIN_VERSION}
)
install(TARGETS ${target} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
endfunction()
set(kdevclangprivate_SRCS
clangsettings/clangsettingsmanager.cpp
clangsettings/sessionsettings/sessionsettings.cpp
codecompletion/completionhelper.cpp
codecompletion/context.cpp
codecompletion/includepathcompletioncontext.cpp
codecompletion/model.cpp
codegen/adaptsignatureaction.cpp
codegen/adaptsignatureassistant.cpp
codegen/codegenhelper.cpp
codegen/clangrefactoring.cpp
codegen/clangclasshelper.cpp
codegen/sourcemanipulation.cpp
duchain/builder.cpp
duchain/clangdiagnosticevaluator.cpp
duchain/clangducontext.cpp
duchain/clanghelpers.cpp
duchain/clangindex.cpp
duchain/clangparsingenvironment.cpp
duchain/clangparsingenvironmentfile.cpp
duchain/clangpch.cpp
duchain/clangproblem.cpp
duchain/debugvisitor.cpp
duchain/documentfinderhelpers.cpp
duchain/duchainutils.cpp
duchain/macrodefinition.cpp
duchain/macronavigationcontext.cpp
duchain/missingincludepathproblem.cpp
duchain/navigationwidget.cpp
duchain/parsesession.cpp
duchain/todoextractor.cpp
duchain/types/classspecializationtype.cpp
duchain/unknowndeclarationproblem.cpp
duchain/unsavedfile.cpp
util/clangdebug.cpp
util/clangtypes.cpp
util/clangutils.cpp
)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
ki18n_wrap_ui(kdevclangprivate_SRCS
clangsettings/sessionsettings/sessionsettings.ui
)
kconfig_add_kcfg_files(kdevclangprivate_SRCS clangsettings/sessionsettings/sessionconfig.kcfgc)
add_private_library(KDevClangPrivate SOURCES ${kdevclangprivate_SRCS})
target_link_libraries(KDevClangPrivate
LINK_PRIVATE
Qt5::Core
KF5::TextEditor
KF5::ThreadWeaver
+ KDev::DefinesAndIncludesManager
KDev::Util
LINK_PUBLIC
KDev::Language
KDev::Project
KDev::Util
${CLANG_LIBCLANG_LIB}
)
install(FILES duchain/gcc_compat.h DESTINATION ${KDE_INSTALL_DATADIR}/kdevclangsupport PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
install(DIRECTORY duchain/wrappedQtHeaders DESTINATION ${KDE_INSTALL_DATADIR}/kdevclangsupport
DIRECTORY_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_WRITE GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
set(kdevclangsupport_SRCS
clangparsejob.cpp
clangsupport.cpp
clanghighlighting.cpp
)
qt5_add_resources(kdevclangsupport_SRCS kdevclangsupport.qrc)
kdevplatform_add_plugin(kdevclangsupport JSON kdevclangsupport.json SOURCES ${kdevclangsupport_SRCS})
target_link_libraries(kdevclangsupport
KDevClangPrivate
KF5::ThreadWeaver
KF5::TextEditor
KDev::Util
KDev::Project
+ KDev::DefinesAndIncludesManager
)
install(FILES kdevclang.xml DESTINATION ${KDE_INSTALL_MIMEDIR})
update_xdg_mimetypes(${KDE_INSTALL_MIMEDIR})
diff --git a/languages/clang/Messages.sh b/plugins/clang/Messages.sh
similarity index 100%
rename from languages/clang/Messages.sh
rename to plugins/clang/Messages.sh
diff --git a/languages/clang/XmlMessages.sh b/plugins/clang/XmlMessages.sh
similarity index 100%
rename from languages/clang/XmlMessages.sh
rename to plugins/clang/XmlMessages.sh
diff --git a/languages/clang/clanghighlighting.cpp b/plugins/clang/clanghighlighting.cpp
similarity index 100%
rename from languages/clang/clanghighlighting.cpp
rename to plugins/clang/clanghighlighting.cpp
diff --git a/languages/clang/clanghighlighting.h b/plugins/clang/clanghighlighting.h
similarity index 100%
rename from languages/clang/clanghighlighting.h
rename to plugins/clang/clanghighlighting.h
diff --git a/languages/clang/clangparsejob.cpp b/plugins/clang/clangparsejob.cpp
similarity index 99%
rename from languages/clang/clangparsejob.cpp
rename to plugins/clang/clangparsejob.cpp
index c59398a82d..200772dc2c 100644
--- a/languages/clang/clangparsejob.cpp
+++ b/plugins/clang/clangparsejob.cpp
@@ -1,385 +1,385 @@
/*
This file is part of KDevelop
Copyright 2013 Olivier de Gaalon
Copyright 2013 Milian Wolff
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 "clangparsejob.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include "clangsettings/clangsettingsmanager.h"
#include "duchain/clanghelpers.h"
#include "duchain/clangpch.h"
#include "duchain/duchainutils.h"
#include "duchain/parsesession.h"
#include "duchain/clangindex.h"
#include "duchain/clangparsingenvironmentfile.h"
#include "util/clangdebug.h"
#include "util/clangtypes.h"
#include "util/clangutils.h"
#include "clangsupport.h"
#include "duchain/documentfinderhelpers.h"
#include
#include
#include
#include
#include
using namespace KDevelop;
namespace {
QString findConfigFile(const QString& forFile, const QString& configFileName)
{
QDir dir = QFileInfo(forFile).dir();
while (dir.exists()) {
const QFileInfo customIncludePaths(dir, configFileName);
if (customIncludePaths.exists()) {
return customIncludePaths.absoluteFilePath();
}
if (!dir.cdUp()) {
break;
}
}
return {};
}
Path::List readPathListFile(const QString& filepath)
{
if (filepath.isEmpty()) {
return {};
}
QFile f(filepath);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
return {};
}
const QString text = QString::fromLocal8Bit(f.readAll());
const QStringList lines = text.split(QLatin1Char('\n'), QString::SkipEmptyParts);
Path::List paths;
paths.reserve(lines.length());
for (const auto& line : lines) {
paths << Path(line);
}
return paths;
}
/**
* File should contain the header to precompile and use while parsing
* @returns the first path in the file
*/
Path userDefinedPchIncludeForFile(const QString& sourcefile)
{
static const QString pchIncludeFilename = QStringLiteral(".kdev_pch_include");
const auto paths = readPathListFile(findConfigFile(sourcefile, pchIncludeFilename));
return paths.isEmpty() ? Path() : paths.first();
}
ProjectFileItem* findProjectFileItem(const IndexedString& url, bool* hasBuildSystemInfo)
{
ProjectFileItem* file = nullptr;
*hasBuildSystemInfo = false;
for (auto project: ICore::self()->projectController()->projects()) {
auto files = project->filesForPath(url);
if (files.isEmpty()) {
continue;
}
file = files.last();
// A file might be defined in different targets.
// Prefer file items defined inside a target with non-empty includes.
for (auto f: files) {
if (!dynamic_cast(f->parent())) {
continue;
}
file = f;
if (!IDefinesAndIncludesManager::manager()->includes(f, IDefinesAndIncludesManager::ProjectSpecific).isEmpty()) {
break;
}
}
}
if (file && file->project()) {
if (auto bsm = file->project()->buildSystemManager()) {
*hasBuildSystemInfo = bsm->hasBuildInfo(file);
}
}
return file;
}
ClangParsingEnvironmentFile* parsingEnvironmentFile(const TopDUContext* context)
{
return dynamic_cast(context->parsingEnvironmentFile().data());
}
DocumentChangeTracker* trackerForUrl(const IndexedString& url)
{
return ICore::self()->languageController()->backgroundParser()->trackerForUrl(url);
}
}
ClangParseJob::ClangParseJob(const IndexedString& url, ILanguageSupport* languageSupport)
: ParseJob(url, languageSupport)
{
const auto tuUrl = clang()->index()->translationUnitForUrl(url);
bool hasBuildSystemInfo;
if (auto file = findProjectFileItem(tuUrl, &hasBuildSystemInfo)) {
m_environment.addIncludes(IDefinesAndIncludesManager::manager()->includes(file));
m_environment.addFrameworkDirectories(IDefinesAndIncludesManager::manager()->frameworkDirectories(file));
m_environment.addDefines(IDefinesAndIncludesManager::manager()->defines(file));
m_environment.setParserSettings(ClangSettingsManager::self()->parserSettings(file));
} else {
m_environment.addIncludes(IDefinesAndIncludesManager::manager()->includes(tuUrl.str()));
m_environment.addFrameworkDirectories(IDefinesAndIncludesManager::manager()->frameworkDirectories(tuUrl.str()));
m_environment.addDefines(IDefinesAndIncludesManager::manager()->defines(tuUrl.str()));
m_environment.setParserSettings(ClangSettingsManager::self()->parserSettings(tuUrl.str()));
}
const bool isSource = ClangHelpers::isSource(tuUrl.str());
m_environment.setQuality(
isSource ? (hasBuildSystemInfo ? ClangParsingEnvironment::BuildSystem : ClangParsingEnvironment::Source)
: ClangParsingEnvironment::Unknown
);
m_environment.setTranslationUnitUrl(tuUrl);
Path::List projectPaths;
const auto& projects = ICore::self()->projectController()->projects();
projectPaths.reserve(projects.size());
foreach (auto project, projects) {
projectPaths.append(project->path());
}
m_environment.setProjectPaths(projectPaths);
m_unsavedFiles = ClangUtils::unsavedFiles();
foreach(auto document, ICore::self()->documentController()->openDocuments()) {
auto textDocument = document->textDocument();
if ( !textDocument ) {
continue;
}
const IndexedString indexedUrl(textDocument->url());
if (indexedUrl == tuUrl) {
m_tuDocumentIsUnsaved = true;
}
m_unsavedRevisions.insert(indexedUrl, ModificationRevision::revisionForFile(indexedUrl));
}
if (auto tracker = trackerForUrl(url)) {
tracker->reset();
}
}
ClangSupport* ClangParseJob::clang() const
{
return static_cast(languageSupport());
}
void ClangParseJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread* /*thread*/)
{
QReadLocker parseLock(languageSupport()->parseLock());
if (abortRequested()) {
return;
}
{
const auto tuUrlStr = m_environment.translationUnitUrl().str();
if (!m_tuDocumentIsUnsaved && !QFile::exists(tuUrlStr)) {
// maybe we requested a parse job some time ago but now the file
// does not exist anymore. return early then
clang()->index()->unpinTranslationUnitForUrl(document());
return;
}
m_environment.addIncludes(IDefinesAndIncludesManager::manager()->includesInBackground(tuUrlStr));
m_environment.addFrameworkDirectories(IDefinesAndIncludesManager::manager()->frameworkDirectoriesInBackground(tuUrlStr));
m_environment.addDefines(IDefinesAndIncludesManager::manager()->definesInBackground(tuUrlStr));
m_environment.setPchInclude(userDefinedPchIncludeForFile(tuUrlStr));
}
if (abortRequested()) {
return;
}
// NOTE: we must have all declarations, contexts and uses available for files that are opened in the editor
// it is very hard to check this for all included files of this TU, and previously lead to problems
// when we tried to skip function bodies as an optimization for files that where not open in the editor.
// now, we always build everything, which is correct but a tad bit slower. we can try to optimize later.
setMinimumFeatures(static_cast(minimumFeatures() | TopDUContext::AllDeclarationsContextsAndUses));
if (minimumFeatures() & AttachASTWithoutUpdating) {
// The context doesn't need to be updated, but has no AST attached (restored from disk),
// so attach AST to it, without updating DUChain
ParseSession session(createSessionData());
DUChainWriteLocker lock;
auto ctx = DUChainUtils::standardContextForUrl(document().toUrl());
if (!ctx) {
clangDebug() << "Lost context while attaching AST";
return;
}
ctx->setAst(IAstContainer::Ptr(session.data()));
if (minimumFeatures() & UpdateHighlighting) {
lock.unlock();
languageSupport()->codeHighlighting()->highlightDUChain(ctx);
}
return;
}
{
UrlParseLock urlLock(document());
if (abortRequested() || !isUpdateRequired(ParseSession::languageString())) {
return;
}
}
ParseSession session(ClangIntegration::DUChainUtils::findParseSessionData(document(), m_environment.translationUnitUrl()));
if (abortRequested()) {
return;
}
if (!session.data() || !session.reparse(m_unsavedFiles, m_environment)) {
session.setData(createSessionData());
}
if (!session.unit()) {
// failed to parse file, unpin and don't try again
clang()->index()->unpinTranslationUnitForUrl(document());
return;
}
if (!clang_getFile(session.unit(), document().byteArray().constData())) {
// this parse job's document does not exist in the pinned translation unit
// so we need to unpin and re-add this document
// Ideally we'd reset m_environment and session, but this is much simpler
// and shouldn't be a common case
clang()->index()->unpinTranslationUnitForUrl(document());
if (!(minimumFeatures() & Rescheduled)) {
auto features = static_cast(minimumFeatures() | Rescheduled);
ICore::self()->languageController()->backgroundParser()->addDocument(document(), features, priority());
}
return;
}
Imports imports = ClangHelpers::tuImports(session.unit());
IncludeFileContexts includedFiles;
if (auto pch = clang()->index()->pch(m_environment)) {
auto pchFile = pch->mapFile(session.unit());
includedFiles = pch->mapIncludes(session.unit());
includedFiles.insert(pchFile, pch->context());
auto tuFile = clang_getFile(session.unit(), m_environment.translationUnitUrl().byteArray().constData());
imports.insert(tuFile, { pchFile, CursorInRevision(0, 0) } );
}
if (abortRequested()) {
return;
}
auto context = ClangHelpers::buildDUChain(session.mainFile(), imports, session,
minimumFeatures(), includedFiles,
clang()->index(), [this] { return abortRequested(); });
setDuChain(context);
if (abortRequested()) {
return;
}
if (context) {
if (minimumFeatures() & TopDUContext::AST) {
DUChainWriteLocker lock;
context->setAst(IAstContainer::Ptr(session.data()));
}
#ifdef QT_DEBUG
DUChainReadLocker lock;
auto file = parsingEnvironmentFile(context);
Q_ASSERT(file);
// verify that features and environment where properly set in ClangHelpers::buildDUChain
Q_ASSERT(file->featuresSatisfied(TopDUContext::Features(minimumFeatures() & ~TopDUContext::ForceUpdateRecursive)));
if (trackerForUrl(context->url())) {
Q_ASSERT(file->featuresSatisfied(TopDUContext::AllDeclarationsContextsAndUses));
}
#endif
}
foreach(const auto& context, includedFiles) {
if (!context) {
continue;
}
{
// prefer the editor modification revision, instead of the on-disk revision
auto it = m_unsavedRevisions.find(context->url());
if (it != m_unsavedRevisions.end()) {
DUChainWriteLocker lock;
auto file = parsingEnvironmentFile(context);
Q_ASSERT(file);
file->setModificationRevision(it.value());
}
}
if (trackerForUrl(context->url())) {
if (clang()->index()->translationUnitForUrl(context->url()) == m_environment.translationUnitUrl()) {
// cache the parse session and the contained translation unit for this chain
// this then allows us to quickly reparse the document if it is changed by
// the user
// otherwise no editor component is open for this document and we can dispose
// the TU to save memory
// share the session data with all contexts that are pinned to this TU
DUChainWriteLocker lock;
context->setAst(IAstContainer::Ptr(session.data()));
}
languageSupport()->codeHighlighting()->highlightDUChain(context);
}
}
}
ParseSessionData::Ptr ClangParseJob::createSessionData() const
{
return ParseSessionData::Ptr(new ParseSessionData(m_unsavedFiles, clang()->index(), m_environment, ParseSessionData::NoOption));
}
const ParsingEnvironment* ClangParseJob::environment() const
{
return &m_environment;
}
diff --git a/languages/clang/clangparsejob.h b/plugins/clang/clangparsejob.h
similarity index 100%
rename from languages/clang/clangparsejob.h
rename to plugins/clang/clangparsejob.h
diff --git a/languages/clang/clangsettings/clangsettingsmanager.cpp b/plugins/clang/clangsettings/clangsettingsmanager.cpp
similarity index 97%
rename from languages/clang/clangsettings/clangsettingsmanager.cpp
rename to plugins/clang/clangsettings/clangsettingsmanager.cpp
index 980c056771..48d6fc4e3f 100644
--- a/languages/clang/clangsettings/clangsettingsmanager.cpp
+++ b/plugins/clang/clangsettings/clangsettingsmanager.cpp
@@ -1,130 +1,130 @@
/*
* This file is part of KDevelop
*
* Copyright 2015 Sergey Kalinichev
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 .
*
*/
#include "clangsettingsmanager.h"
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
using namespace KDevelop;
namespace
{
const QString settingsGroup = QStringLiteral("Clang Settings");
const QString macros = QStringLiteral("macros");
const QString lookAhead = QStringLiteral("lookAhead");
const QString forwardDeclare = QStringLiteral("forwardDeclare");
AssistantsSettings readAssistantsSettings(KConfig* cfg)
{
auto grp = cfg->group(settingsGroup);
AssistantsSettings settings;
settings.forwardDeclare = grp.readEntry(forwardDeclare, true);
return settings;
}
CodeCompletionSettings readCodeCompletionSettings(KConfig* cfg)
{
auto grp = cfg->group(settingsGroup);
CodeCompletionSettings settings;
settings.macros = grp.readEntry(macros, true);
settings.lookAhead = grp.readEntry(lookAhead, false);
return settings;
}
}
ClangSettingsManager* ClangSettingsManager::self()
{
static ClangSettingsManager manager;
return &manager;
}
AssistantsSettings ClangSettingsManager::assistantsSettings() const
{
auto cfg = ICore::self()->activeSession()->config();
return readAssistantsSettings(cfg.data());
}
CodeCompletionSettings ClangSettingsManager::codeCompletionSettings() const
{
if (m_enableTesting) {
CodeCompletionSettings settings;
settings.lookAhead = true;
settings.macros = true;
return settings;
}
auto cfg = ICore::self()->activeSession()->config();
return readCodeCompletionSettings(cfg.data());
}
ParserSettings ClangSettingsManager::parserSettings(KDevelop::ProjectBaseItem* item) const
{
return {IDefinesAndIncludesManager::manager()->parserArguments(item)};
}
ParserSettings ClangSettingsManager::parserSettings(const QString& path) const
{
return {IDefinesAndIncludesManager::manager()->parserArguments(path)};
}
ClangSettingsManager::ClangSettingsManager()
{}
bool ParserSettings::isCpp() const
{
return parserOptions.contains(QStringLiteral("-std=c++"));
}
QVector ParserSettings::toClangAPI() const
{
// TODO: This is not efficient.
auto list = parserOptions.splitRef(QLatin1Char(' '), QString::SkipEmptyParts);
QVector result;
result.reserve(list.size());
std::transform(list.constBegin(), list.constEnd(),
std::back_inserter(result),
[] (const QStringRef &argument) { return argument.toUtf8(); });
return result;
}
bool ParserSettings::operator==(const ParserSettings& rhs) const
{
return parserOptions == rhs.parserOptions;
}
diff --git a/languages/clang/clangsettings/clangsettingsmanager.h b/plugins/clang/clangsettings/clangsettingsmanager.h
similarity index 100%
rename from languages/clang/clangsettings/clangsettingsmanager.h
rename to plugins/clang/clangsettings/clangsettingsmanager.h
diff --git a/languages/clang/clangsettings/sessionsettings/sessionconfig.kcfg b/plugins/clang/clangsettings/sessionsettings/sessionconfig.kcfg
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionconfig.kcfg
rename to plugins/clang/clangsettings/sessionsettings/sessionconfig.kcfg
diff --git a/languages/clang/clangsettings/sessionsettings/sessionconfig.kcfgc b/plugins/clang/clangsettings/sessionsettings/sessionconfig.kcfgc
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionconfig.kcfgc
rename to plugins/clang/clangsettings/sessionsettings/sessionconfig.kcfgc
diff --git a/languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h b/plugins/clang/clangsettings/sessionsettings/sessionconfigskeleton.h
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionconfigskeleton.h
rename to plugins/clang/clangsettings/sessionsettings/sessionconfigskeleton.h
diff --git a/languages/clang/clangsettings/sessionsettings/sessionsettings.cpp b/plugins/clang/clangsettings/sessionsettings/sessionsettings.cpp
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionsettings.cpp
rename to plugins/clang/clangsettings/sessionsettings/sessionsettings.cpp
diff --git a/languages/clang/clangsettings/sessionsettings/sessionsettings.h b/plugins/clang/clangsettings/sessionsettings/sessionsettings.h
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionsettings.h
rename to plugins/clang/clangsettings/sessionsettings/sessionsettings.h
diff --git a/languages/clang/clangsettings/sessionsettings/sessionsettings.ui b/plugins/clang/clangsettings/sessionsettings/sessionsettings.ui
similarity index 100%
rename from languages/clang/clangsettings/sessionsettings/sessionsettings.ui
rename to plugins/clang/clangsettings/sessionsettings/sessionsettings.ui
diff --git a/languages/clang/clangsupport.cpp b/plugins/clang/clangsupport.cpp
similarity index 100%
rename from languages/clang/clangsupport.cpp
rename to plugins/clang/clangsupport.cpp
diff --git a/languages/clang/clangsupport.h b/plugins/clang/clangsupport.h
similarity index 100%
rename from languages/clang/clangsupport.h
rename to plugins/clang/clangsupport.h
diff --git a/languages/clang/codecompletion/completionhelper.cpp b/plugins/clang/codecompletion/completionhelper.cpp
similarity index 100%
rename from languages/clang/codecompletion/completionhelper.cpp
rename to plugins/clang/codecompletion/completionhelper.cpp
diff --git a/languages/clang/codecompletion/completionhelper.h b/plugins/clang/codecompletion/completionhelper.h
similarity index 100%
rename from languages/clang/codecompletion/completionhelper.h
rename to plugins/clang/codecompletion/completionhelper.h
diff --git a/languages/clang/codecompletion/context.cpp b/plugins/clang/codecompletion/context.cpp
similarity index 100%
rename from languages/clang/codecompletion/context.cpp
rename to plugins/clang/codecompletion/context.cpp
diff --git a/languages/clang/codecompletion/context.h b/plugins/clang/codecompletion/context.h
similarity index 100%
rename from languages/clang/codecompletion/context.h
rename to plugins/clang/codecompletion/context.h
diff --git a/languages/clang/codecompletion/includepathcompletioncontext.cpp b/plugins/clang/codecompletion/includepathcompletioncontext.cpp
similarity index 100%
rename from languages/clang/codecompletion/includepathcompletioncontext.cpp
rename to plugins/clang/codecompletion/includepathcompletioncontext.cpp
diff --git a/languages/clang/codecompletion/includepathcompletioncontext.h b/plugins/clang/codecompletion/includepathcompletioncontext.h
similarity index 100%
rename from languages/clang/codecompletion/includepathcompletioncontext.h
rename to plugins/clang/codecompletion/includepathcompletioncontext.h
diff --git a/languages/clang/codecompletion/model.cpp b/plugins/clang/codecompletion/model.cpp
similarity index 100%
rename from languages/clang/codecompletion/model.cpp
rename to plugins/clang/codecompletion/model.cpp
diff --git a/languages/clang/codecompletion/model.h b/plugins/clang/codecompletion/model.h
similarity index 100%
rename from languages/clang/codecompletion/model.h
rename to plugins/clang/codecompletion/model.h
diff --git a/languages/clang/codegen/adaptsignatureaction.cpp b/plugins/clang/codegen/adaptsignatureaction.cpp
similarity index 100%
rename from languages/clang/codegen/adaptsignatureaction.cpp
rename to plugins/clang/codegen/adaptsignatureaction.cpp
diff --git a/languages/clang/codegen/adaptsignatureaction.h b/plugins/clang/codegen/adaptsignatureaction.h
similarity index 100%
rename from languages/clang/codegen/adaptsignatureaction.h
rename to plugins/clang/codegen/adaptsignatureaction.h
diff --git a/languages/clang/codegen/adaptsignatureassistant.cpp b/plugins/clang/codegen/adaptsignatureassistant.cpp
similarity index 100%
rename from languages/clang/codegen/adaptsignatureassistant.cpp
rename to plugins/clang/codegen/adaptsignatureassistant.cpp
diff --git a/languages/clang/codegen/adaptsignatureassistant.h b/plugins/clang/codegen/adaptsignatureassistant.h
similarity index 100%
rename from languages/clang/codegen/adaptsignatureassistant.h
rename to plugins/clang/codegen/adaptsignatureassistant.h
diff --git a/languages/clang/codegen/clangclasshelper.cpp b/plugins/clang/codegen/clangclasshelper.cpp
similarity index 99%
rename from languages/clang/codegen/clangclasshelper.cpp
rename to plugins/clang/codegen/clangclasshelper.cpp
index fe2e5c5a2f..9cf34bca0b 100644
--- a/languages/clang/codegen/clangclasshelper.cpp
+++ b/plugins/clang/codegen/clangclasshelper.cpp
@@ -1,305 +1,305 @@
/*
* KDevelop C++ Language Support
*
* Copyright 2008 Hamish Rodda
* Copyright 2012 Miha Čančula
* Copyright 2017 Friedrich W. H. Kossebau
*
* 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 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.
*/
#include "clangclasshelper.h"
#include "util/clangdebug.h"
#include "duchain/unknowndeclarationproblem.h"
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
using namespace KDevelop;
ClangClassHelper::ClangClassHelper()
{
}
ClangClassHelper::~ClangClassHelper() = default;
TemplateClassGenerator* ClangClassHelper::createGenerator(const QUrl& baseUrl)
{
return new ClangTemplateNewClass(baseUrl);
}
QList ClangClassHelper::defaultMethods(const QString& name) const
{
// TODO: this is the oldcpp approach, perhaps clang provides this directly?
// TODO: default destructor misses info about virtualness, possible needs ICreateClassHelper change?
QTemporaryFile file(QDir::tempPath() + QLatin1String("/class_") + name + QLatin1String("_XXXXXX.cpp"));
file.open();
QTextStream stream(&file);
stream << "class " << name << " {\n"
<< " public:\n"
// default ctor
<< " " << name << "();\n"
// copy ctor
<< " " << name << "(const " << name << "& other);\n"
// default dtor
<< " ~" << name << "();\n"
// assignment operator
<< " " << name << "& operator=(const " << name << "& other);\n"
// equality operators
<< " bool operator==(const " << name << "& other) const;\n"
<< " bool operator!=(const " << name << "& other) const;\n"
<< "};\n";
file.close();
ReferencedTopDUContext context(DUChain::self()->waitForUpdate(IndexedString(file.fileName()),
TopDUContext::AllDeclarationsAndContexts));
QList methods;
{
DUChainReadLocker lock;
if (context && context->childContexts().size() == 1) {
for (auto* declaration : context->childContexts().first()->localDeclarations()) {
methods << DeclarationPointer(declaration);
}
}
}
return methods;
}
ClangTemplateNewClass::ClangTemplateNewClass(const QUrl& url)
: TemplateClassGenerator(url)
{
}
ClangTemplateNewClass::~ClangTemplateNewClass() = default;
namespace {
QString includeArgumentForFile(const QString& includefile, const Path::List& includePaths,
const Path& source)
{
const auto sourceFolder = source.parent();
const Path canonicalFile(QFileInfo(includefile).canonicalFilePath());
QString shortestDirective;
bool isRelative = false;
// we can include the file directly
if (sourceFolder == canonicalFile.parent()) {
shortestDirective = canonicalFile.lastPathSegment();
isRelative = true;
} else {
// find the include directive with the shortest length
for (const auto& includePath : includePaths) {
QString relative = includePath.relativePath(canonicalFile);
if (relative.startsWith(QLatin1String("./"))) {
relative.remove(0, 2);
}
if (shortestDirective.isEmpty() || relative.length() < shortestDirective.length()) {
shortestDirective = relative;
isRelative = (includePath == sourceFolder);
}
}
}
// Item not found in include path?
if (shortestDirective.isEmpty()) {
return {};
}
if (isRelative) {
return QLatin1Char('\"') + shortestDirective + QLatin1Char('\"');
}
return QLatin1Char('<') + shortestDirective + QLatin1Char('>');
}
QString includeDirectiveArgumentFromPath(const Path& file,
const DeclarationPointer& declaration)
{
const auto includeManager = IDefinesAndIncludesManager::manager();
const auto filePath = file.toLocalFile();
const auto projectModel = ICore::self()->projectController()->projectModel();
auto item = projectModel->itemForPath(IndexedString(filePath));
if (!item) {
// try the folder where the file is placed and guess includes from there
// prefer target over file
const auto folderPath = IndexedString(file.parent().toLocalFile());
clangDebug() << "File not known, guessing includes from items in folder:" << folderPath.str();
// default to the folder, if no targets or files
item = projectModel->itemForPath(folderPath);
if (item) {
const auto targetItems = item->targetList();
bool itemChosen = false;
// Prefer items defined inside a target with non-empty includes.
for (const auto& targetItem : targetItems) {
item = targetItem;
if (!includeManager->includes(targetItem, IDefinesAndIncludesManager::ProjectSpecific).isEmpty()) {
clangDebug() << "Guessing includes from target" << targetItem->baseName();
itemChosen = true;
break;
}
}
if (!itemChosen) {
const auto fileItems = item->fileList();
// Prefer items defined inside a target with non-empty includes.
for (const auto& fileItem : fileItems) {
item = fileItem;
if (!includeManager->includes(fileItem, IDefinesAndIncludesManager::ProjectSpecific).isEmpty()) {
clangDebug() << "Guessing includes from file" << fileItem->baseName();
break;
}
}
}
}
}
const auto includePaths = includeManager->includes(item);
if (includePaths.isEmpty()) {
clangDebug() << "Include path is empty";
return {};
}
clangDebug() << "found include paths for" << file << ":" << includePaths;
const auto includeFiles = UnknownDeclarationProblem::findMatchingIncludeFiles(QVector {declaration.data()});
if (includeFiles.isEmpty()) {
// return early as the computation of the include paths is quite expensive
return {};
}
// create include arguments for all candidates
QStringList includeArguments;
for (const auto& includeFile : includeFiles) {
const auto includeArgument = includeArgumentForFile(includeFile, includePaths, file);
if (includeArgument.isEmpty()) {
clangDebug() << "unable to create include argument for" << includeFile << "in" << file.toLocalFile();
}
includeArguments << includeArgument;
}
if (includeArguments.isEmpty()) {
return {};
}
std::sort(includeArguments.begin(), includeArguments.end(),
[](const QString& lhs, const QString& rhs) {
return lhs.length() < rhs.length();
});
return includeArguments.at(0);
}
template
void addVariables(QVariantHash* variables, QLatin1String suffix, const Map& map)
{
for (auto it = map.begin(), end = map.end(); it != end; ++it) {
variables->insert(it.key() + suffix, CodeDescription::toVariantList(it.value()));
}
}
}
QVariantHash ClangTemplateNewClass::extraVariables() const
{
QVariantHash variables;
const QString publicAccess = QStringLiteral("public");
QHash variableDescriptions;
QHash functionDescriptions;
QHash slotDescriptions;
FunctionDescriptionList signalDescriptions;
const auto desc = description();
for (const auto& function : desc.methods) {
const QString& access = function.access.isEmpty() ? publicAccess : function.access;
if (function.isSignal) {
signalDescriptions << function;
} else if (function.isSlot) {
slotDescriptions[access] << function;
} else {
functionDescriptions[access] << function;
}
}
for (const auto& variable : desc.members) {
const QString& access = variable.access.isEmpty() ? publicAccess : variable.access;
variableDescriptions[access] << variable;
}
::addVariables(&variables, QLatin1String("_members"), variableDescriptions);
::addVariables(&variables, QLatin1String("_functions"), functionDescriptions);
::addVariables(&variables, QLatin1String("_slots"), slotDescriptions);
variables[QStringLiteral("signals")] = CodeDescription::toVariantList(signalDescriptions);
variables[QStringLiteral("needs_qobject_macro")] = !slotDescriptions.isEmpty() || !signalDescriptions.isEmpty();
QStringList includedFiles;
DUChainReadLocker locker(DUChain::lock());
QUrl sourceUrl;
const auto urls = fileUrls();
if (!urls.isEmpty()) {
sourceUrl = urls.constBegin().value();
} else {
// includeDirectiveArgumentFromPath() expects a path to the folder where includes are used from
sourceUrl = baseUrl();
sourceUrl.setPath(sourceUrl.path() + QLatin1String("/.h"));
}
const Path sourcePath(sourceUrl);
for (const auto& baseClass : directBaseClasses()) {
if (!baseClass) {
continue;
}
clangDebug() << "Looking for includes for class" << baseClass->identifier().toString();
const QString includeDirective = includeDirectiveArgumentFromPath(sourcePath, baseClass);
if (!includeDirective.isEmpty()) {
includedFiles << includeDirective;
}
}
variables[QStringLiteral("included_files")] = includedFiles;
return variables;
}
DocumentChangeSet ClangTemplateNewClass::generate()
{
addVariables(extraVariables());
return TemplateClassGenerator::generate();
}
diff --git a/languages/clang/codegen/clangclasshelper.h b/plugins/clang/codegen/clangclasshelper.h
similarity index 100%
rename from languages/clang/codegen/clangclasshelper.h
rename to plugins/clang/codegen/clangclasshelper.h
diff --git a/languages/clang/codegen/clangrefactoring.cpp b/plugins/clang/codegen/clangrefactoring.cpp
similarity index 100%
rename from languages/clang/codegen/clangrefactoring.cpp
rename to plugins/clang/codegen/clangrefactoring.cpp
diff --git a/languages/clang/codegen/clangrefactoring.h b/plugins/clang/codegen/clangrefactoring.h
similarity index 100%
rename from languages/clang/codegen/clangrefactoring.h
rename to plugins/clang/codegen/clangrefactoring.h
diff --git a/languages/clang/codegen/codegenexport.h b/plugins/clang/codegen/codegenexport.h
similarity index 100%
rename from languages/clang/codegen/codegenexport.h
rename to plugins/clang/codegen/codegenexport.h
diff --git a/languages/clang/codegen/codegenhelper.cpp b/plugins/clang/codegen/codegenhelper.cpp
similarity index 100%
rename from languages/clang/codegen/codegenhelper.cpp
rename to plugins/clang/codegen/codegenhelper.cpp
diff --git a/languages/clang/codegen/codegenhelper.h b/plugins/clang/codegen/codegenhelper.h
similarity index 100%
rename from languages/clang/codegen/codegenhelper.h
rename to plugins/clang/codegen/codegenhelper.h
diff --git a/languages/clang/codegen/sourcemanipulation.cpp b/plugins/clang/codegen/sourcemanipulation.cpp
similarity index 100%
rename from languages/clang/codegen/sourcemanipulation.cpp
rename to plugins/clang/codegen/sourcemanipulation.cpp
diff --git a/languages/clang/codegen/sourcemanipulation.h b/plugins/clang/codegen/sourcemanipulation.h
similarity index 100%
rename from languages/clang/codegen/sourcemanipulation.h
rename to plugins/clang/codegen/sourcemanipulation.h
diff --git a/languages/clang/duchain/builder.cpp b/plugins/clang/duchain/builder.cpp
similarity index 100%
rename from languages/clang/duchain/builder.cpp
rename to plugins/clang/duchain/builder.cpp
diff --git a/languages/clang/duchain/builder.h b/plugins/clang/duchain/builder.h
similarity index 100%
rename from languages/clang/duchain/builder.h
rename to plugins/clang/duchain/builder.h
diff --git a/languages/clang/duchain/clangdiagnosticevaluator.cpp b/plugins/clang/duchain/clangdiagnosticevaluator.cpp
similarity index 100%
rename from languages/clang/duchain/clangdiagnosticevaluator.cpp
rename to plugins/clang/duchain/clangdiagnosticevaluator.cpp
diff --git a/languages/clang/duchain/clangdiagnosticevaluator.h b/plugins/clang/duchain/clangdiagnosticevaluator.h
similarity index 100%
rename from languages/clang/duchain/clangdiagnosticevaluator.h
rename to plugins/clang/duchain/clangdiagnosticevaluator.h
diff --git a/languages/clang/duchain/clangducontext.cpp b/plugins/clang/duchain/clangducontext.cpp
similarity index 100%
rename from languages/clang/duchain/clangducontext.cpp
rename to plugins/clang/duchain/clangducontext.cpp
diff --git a/languages/clang/duchain/clangducontext.h b/plugins/clang/duchain/clangducontext.h
similarity index 100%
rename from languages/clang/duchain/clangducontext.h
rename to plugins/clang/duchain/clangducontext.h
diff --git a/languages/clang/duchain/clanghelpers.cpp b/plugins/clang/duchain/clanghelpers.cpp
similarity index 100%
rename from languages/clang/duchain/clanghelpers.cpp
rename to plugins/clang/duchain/clanghelpers.cpp
diff --git a/languages/clang/duchain/clanghelpers.h b/plugins/clang/duchain/clanghelpers.h
similarity index 100%
rename from languages/clang/duchain/clanghelpers.h
rename to plugins/clang/duchain/clanghelpers.h
diff --git a/languages/clang/duchain/clangindex.cpp b/plugins/clang/duchain/clangindex.cpp
similarity index 100%
rename from languages/clang/duchain/clangindex.cpp
rename to plugins/clang/duchain/clangindex.cpp
diff --git a/languages/clang/duchain/clangindex.h b/plugins/clang/duchain/clangindex.h
similarity index 100%
rename from languages/clang/duchain/clangindex.h
rename to plugins/clang/duchain/clangindex.h
diff --git a/languages/clang/duchain/clangparsingenvironment.cpp b/plugins/clang/duchain/clangparsingenvironment.cpp
similarity index 100%
rename from languages/clang/duchain/clangparsingenvironment.cpp
rename to plugins/clang/duchain/clangparsingenvironment.cpp
diff --git a/languages/clang/duchain/clangparsingenvironment.h b/plugins/clang/duchain/clangparsingenvironment.h
similarity index 100%
rename from languages/clang/duchain/clangparsingenvironment.h
rename to plugins/clang/duchain/clangparsingenvironment.h
diff --git a/languages/clang/duchain/clangparsingenvironmentfile.cpp b/plugins/clang/duchain/clangparsingenvironmentfile.cpp
similarity index 100%
rename from languages/clang/duchain/clangparsingenvironmentfile.cpp
rename to plugins/clang/duchain/clangparsingenvironmentfile.cpp
diff --git a/languages/clang/duchain/clangparsingenvironmentfile.h b/plugins/clang/duchain/clangparsingenvironmentfile.h
similarity index 100%
rename from languages/clang/duchain/clangparsingenvironmentfile.h
rename to plugins/clang/duchain/clangparsingenvironmentfile.h
diff --git a/languages/clang/duchain/clangpch.cpp b/plugins/clang/duchain/clangpch.cpp
similarity index 100%
rename from languages/clang/duchain/clangpch.cpp
rename to plugins/clang/duchain/clangpch.cpp
diff --git a/languages/clang/duchain/clangpch.h b/plugins/clang/duchain/clangpch.h
similarity index 100%
rename from languages/clang/duchain/clangpch.h
rename to plugins/clang/duchain/clangpch.h
diff --git a/languages/clang/duchain/clangproblem.cpp b/plugins/clang/duchain/clangproblem.cpp
similarity index 100%
rename from languages/clang/duchain/clangproblem.cpp
rename to plugins/clang/duchain/clangproblem.cpp
diff --git a/languages/clang/duchain/clangproblem.h b/plugins/clang/duchain/clangproblem.h
similarity index 100%
rename from languages/clang/duchain/clangproblem.h
rename to plugins/clang/duchain/clangproblem.h
diff --git a/languages/clang/duchain/cursorkindtraits.h b/plugins/clang/duchain/cursorkindtraits.h
similarity index 100%
rename from languages/clang/duchain/cursorkindtraits.h
rename to plugins/clang/duchain/cursorkindtraits.h
diff --git a/languages/clang/duchain/debugvisitor.cpp b/plugins/clang/duchain/debugvisitor.cpp
similarity index 100%
rename from languages/clang/duchain/debugvisitor.cpp
rename to plugins/clang/duchain/debugvisitor.cpp
diff --git a/languages/clang/duchain/debugvisitor.h b/plugins/clang/duchain/debugvisitor.h
similarity index 100%
rename from languages/clang/duchain/debugvisitor.h
rename to plugins/clang/duchain/debugvisitor.h
diff --git a/languages/clang/duchain/documentfinderhelpers.cpp b/plugins/clang/duchain/documentfinderhelpers.cpp
similarity index 100%
rename from languages/clang/duchain/documentfinderhelpers.cpp
rename to plugins/clang/duchain/documentfinderhelpers.cpp
diff --git a/languages/clang/duchain/documentfinderhelpers.h b/plugins/clang/duchain/documentfinderhelpers.h
similarity index 100%
rename from languages/clang/duchain/documentfinderhelpers.h
rename to plugins/clang/duchain/documentfinderhelpers.h
diff --git a/languages/clang/duchain/duchainutils.cpp b/plugins/clang/duchain/duchainutils.cpp
similarity index 100%
rename from languages/clang/duchain/duchainutils.cpp
rename to plugins/clang/duchain/duchainutils.cpp
diff --git a/languages/clang/duchain/duchainutils.h b/plugins/clang/duchain/duchainutils.h
similarity index 100%
rename from languages/clang/duchain/duchainutils.h
rename to plugins/clang/duchain/duchainutils.h
diff --git a/languages/clang/duchain/gcc_compat.h b/plugins/clang/duchain/gcc_compat.h
similarity index 100%
rename from languages/clang/duchain/gcc_compat.h
rename to plugins/clang/duchain/gcc_compat.h
diff --git a/languages/clang/duchain/macrodefinition.cpp b/plugins/clang/duchain/macrodefinition.cpp
similarity index 100%
rename from languages/clang/duchain/macrodefinition.cpp
rename to plugins/clang/duchain/macrodefinition.cpp
diff --git a/languages/clang/duchain/macrodefinition.h b/plugins/clang/duchain/macrodefinition.h
similarity index 100%
rename from languages/clang/duchain/macrodefinition.h
rename to plugins/clang/duchain/macrodefinition.h
diff --git a/languages/clang/duchain/macronavigationcontext.cpp b/plugins/clang/duchain/macronavigationcontext.cpp
similarity index 100%
rename from languages/clang/duchain/macronavigationcontext.cpp
rename to plugins/clang/duchain/macronavigationcontext.cpp
diff --git a/languages/clang/duchain/macronavigationcontext.h b/plugins/clang/duchain/macronavigationcontext.h
similarity index 100%
rename from languages/clang/duchain/macronavigationcontext.h
rename to plugins/clang/duchain/macronavigationcontext.h
diff --git a/languages/clang/duchain/missingincludepathproblem.cpp b/plugins/clang/duchain/missingincludepathproblem.cpp
similarity index 97%
rename from languages/clang/duchain/missingincludepathproblem.cpp
rename to plugins/clang/duchain/missingincludepathproblem.cpp
index f38f80e381..7d648e88fb 100644
--- a/languages/clang/duchain/missingincludepathproblem.cpp
+++ b/plugins/clang/duchain/missingincludepathproblem.cpp
@@ -1,116 +1,116 @@
/*
* This file is part of KDevelop
*
* Copyright 2014 Sergey Kalinichev
*
* 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 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.
*/
#include "missingincludepathproblem.h"
#include
#include
#include
-#include
+#include
#include
namespace
{
void openConfigurationPage(const QString& path)
{
KDevelop::IDefinesAndIncludesManager::manager()->openConfigurationDialog(path);
}
}
class AddCustomIncludePathAction : public KDevelop::IAssistantAction
{
Q_OBJECT
public:
explicit AddCustomIncludePathAction(const KDevelop::IndexedString& path)
: m_path(path)
{}
QString description() const override
{
return i18n("Add Custom Include Path");
}
void execute() override
{
openConfigurationPage(m_path.str());
emit executed(this);
}
private:
KDevelop::IndexedString m_path;
};
class OpenProjectForFileAssistant : public KDevelop::IAssistantAction
{
public:
explicit OpenProjectForFileAssistant(const KDevelop::IndexedString& path)
: m_path(path)
{}
QString description() const override
{
return i18n("Open Project");
};
void execute() override
{
KDevelop::ICore::self()->projectController()->openProjectForUrl(m_path.toUrl());
emit executed(this);
}
private:
KDevelop::IndexedString m_path;
};
class MissingIncludePathAssistant : public ClangFixitAssistant
{
public:
MissingIncludePathAssistant(const QString& title, const KDevelop::IndexedString& path)
: ClangFixitAssistant(title, {})
, m_path(path)
{}
void createActions() override
{
auto project = KDevelop::ICore::self()->projectController()->findProjectForUrl(m_path.toUrl());
if (!project) {
addAction(KDevelop::IAssistantAction::Ptr(new OpenProjectForFileAssistant(m_path)));
}
addAction(KDevelop::IAssistantAction::Ptr(new AddCustomIncludePathAction(m_path)));
}
private:
KDevelop::IndexedString m_path;
};
MissingIncludePathProblem::MissingIncludePathProblem(CXDiagnostic diagnostic, CXTranslationUnit unit)
: ClangProblem(diagnostic, unit)
{}
KDevelop::IAssistant::Ptr MissingIncludePathProblem::solutionAssistant() const
{
return KDevelop::IAssistant::Ptr(new MissingIncludePathAssistant(description(), finalLocation().document));
}
#include "missingincludepathproblem.moc"
diff --git a/languages/clang/duchain/missingincludepathproblem.h b/plugins/clang/duchain/missingincludepathproblem.h
similarity index 100%
rename from languages/clang/duchain/missingincludepathproblem.h
rename to plugins/clang/duchain/missingincludepathproblem.h
diff --git a/languages/clang/duchain/navigationwidget.cpp b/plugins/clang/duchain/navigationwidget.cpp
similarity index 100%
rename from languages/clang/duchain/navigationwidget.cpp
rename to plugins/clang/duchain/navigationwidget.cpp
diff --git a/languages/clang/duchain/navigationwidget.h b/plugins/clang/duchain/navigationwidget.h
similarity index 100%
rename from languages/clang/duchain/navigationwidget.h
rename to plugins/clang/duchain/navigationwidget.h
diff --git a/languages/clang/duchain/parsesession.cpp b/plugins/clang/duchain/parsesession.cpp
similarity index 100%
rename from languages/clang/duchain/parsesession.cpp
rename to plugins/clang/duchain/parsesession.cpp
diff --git a/languages/clang/duchain/parsesession.h b/plugins/clang/duchain/parsesession.h
similarity index 100%
rename from languages/clang/duchain/parsesession.h
rename to plugins/clang/duchain/parsesession.h
diff --git a/languages/clang/duchain/templatehelpers.h b/plugins/clang/duchain/templatehelpers.h
similarity index 100%
rename from languages/clang/duchain/templatehelpers.h
rename to plugins/clang/duchain/templatehelpers.h
diff --git a/languages/clang/duchain/todoextractor.cpp b/plugins/clang/duchain/todoextractor.cpp
similarity index 100%
rename from languages/clang/duchain/todoextractor.cpp
rename to plugins/clang/duchain/todoextractor.cpp
diff --git a/languages/clang/duchain/todoextractor.h b/plugins/clang/duchain/todoextractor.h
similarity index 100%
rename from languages/clang/duchain/todoextractor.h
rename to plugins/clang/duchain/todoextractor.h
diff --git a/languages/clang/duchain/types/classspecializationtype.cpp b/plugins/clang/duchain/types/classspecializationtype.cpp
similarity index 100%
rename from languages/clang/duchain/types/classspecializationtype.cpp
rename to plugins/clang/duchain/types/classspecializationtype.cpp
diff --git a/languages/clang/duchain/types/classspecializationtype.h b/plugins/clang/duchain/types/classspecializationtype.h
similarity index 100%
rename from languages/clang/duchain/types/classspecializationtype.h
rename to plugins/clang/duchain/types/classspecializationtype.h
diff --git a/languages/clang/duchain/unknowndeclarationproblem.cpp b/plugins/clang/duchain/unknowndeclarationproblem.cpp
similarity index 99%
rename from languages/clang/duchain/unknowndeclarationproblem.cpp
rename to plugins/clang/duchain/unknowndeclarationproblem.cpp
index b47a6ed378..9f27d335e5 100644
--- a/languages/clang/duchain/unknowndeclarationproblem.cpp
+++ b/plugins/clang/duchain/unknowndeclarationproblem.cpp
@@ -1,557 +1,557 @@
/*
* Copyright 2014 Jørgen Kvalsvik
* Copyright 2014 Kevin Funk
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 .
*
*/
#include "unknowndeclarationproblem.h"
#include "clanghelpers.h"
#include "parsesession.h"
#include "../util/clangdebug.h"
#include "../util/clangutils.h"
#include "../util/clangtypes.h"
#include "../clangsettings/clangsettingsmanager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
#include
using namespace KDevelop;
namespace {
/** Under some conditions, such as when looking up suggestions
* for the undeclared namespace 'std' we will get an awful lot
* of suggestions. This parameter limits how many suggestions
* will pop up, as rarely more than a few will be relevant anyways
*
* Forward declaration suggestions are included in this number
*/
const int maxSuggestions = 5;
/**
* We don't want anything from the bits directory -
* we'd rather prefer forwarding includes, such as
*/
bool isBlacklisted(const QString& path)
{
if (ClangHelpers::isSource(path))
return true;
// Do not allow including directly from the bits directory.
// Instead use one of the forwarding headers in other directories, when possible.
if (path.contains( QLatin1String("bits") ) && path.contains(QLatin1String("/include/c++/")))
return true;
return false;
}
QStringList scanIncludePaths( const QString& identifier, const QDir& dir, int maxDepth = 3 )
{
if (!maxDepth) {
return {};
}
QStringList candidates;
const auto path = dir.absolutePath();
if( isBlacklisted( path ) ) {
return {};
}
const QStringList nameFilters = {identifier, identifier + QLatin1String(".*")};
for (const auto& file : dir.entryList(nameFilters, QDir::Files)) {
if (identifier.compare(file, Qt::CaseInsensitive) == 0 || ClangHelpers::isHeader(file)) {
const QString filePath = path + QLatin1Char('/') + file;
clangDebug() << "Found candidate file" << filePath;
candidates.append( filePath );
}
}
maxDepth--;
for( const auto& subdir : dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
candidates += scanIncludePaths( identifier, QDir{ path + QLatin1Char('/') + subdir }, maxDepth );
return candidates;
}
/**
* Find files in dir that match the given identifier. Matches common C++ header file extensions only.
*/
QStringList scanIncludePaths( const QualifiedIdentifier& identifier, const KDevelop::Path::List& includes )
{
const auto stripped_identifier = identifier.last().toString();
QStringList candidates;
for( const auto& include : includes ) {
candidates += scanIncludePaths( stripped_identifier, QDir{ include.toLocalFile() } );
}
std::sort( candidates.begin(), candidates.end() );
candidates.erase( std::unique( candidates.begin(), candidates.end() ), candidates.end() );
return candidates;
}
/**
* Determine how much path is shared between two includes.
* boost/tr1/unordered_map
* boost/tr1/unordered_set
* have a shared path of 2 where
* boost/tr1/unordered_map
* boost/vector
* have a shared path of 1
*/
int sharedPathLevel(const QString& a, const QString& b)
{
int shared = -1;
for(auto x = a.begin(), y = b.begin(); *x == *y && x != a.end() && y != b.end() ; ++x, ++y ) {
if( *x == QDir::separator() ) {
++shared;
}
}
return shared;
}
/**
* Try to find a proper include position from the DUChain:
*
* look at existing imports (i.e. #include's) and find a fitting
* file with the same/similar path to the new include file and use that
*
* TODO: Implement a fallback scheme
*/
KDevelop::DocumentRange includeDirectivePosition(const KDevelop::Path& source, const QString& includeFile)
{
static const QRegularExpression mocFilenameExpression(QStringLiteral("(moc_[^\\/\\\\]+\\.cpp$|\\.moc$)") );
DUChainReadLocker lock;
const TopDUContext* top = DUChainUtils::standardContextForUrl( source.toUrl() );
if( !top ) {
clangDebug() << "unable to find standard context for" << source.toLocalFile() << "Creating null range";
return KDevelop::DocumentRange::invalid();
}
int line = -1;
// look at existing #include statements and re-use them
int currentMatchQuality = -1;
for( const auto& import : top->importedParentContexts() ) {
const auto importFilename = import.context(top)->url().str();
const int matchQuality = sharedPathLevel( importFilename , includeFile );
if( matchQuality < currentMatchQuality ) {
continue;
}
const auto match = mocFilenameExpression.match(importFilename);
if (match.hasMatch()) {
clangDebug() << "moc file detected in" << source.toUrl().toDisplayString() << ":" << importFilename << "-- not using as include insertion location";
continue;
}
line = import.position.line + 1;
currentMatchQuality = matchQuality;
}
if( line == -1 ) {
/* Insert at the top of the document */
return {IndexedString(source.pathOrUrl()), {0, 0, 0, 0}};
}
return {IndexedString(source.pathOrUrl()), {line, 0, line, 0}};
}
KDevelop::DocumentRange forwardDeclarationPosition(const QualifiedIdentifier& identifier, const KDevelop::Path& source)
{
DUChainReadLocker lock;
const TopDUContext* top = DUChainUtils::standardContextForUrl( source.toUrl() );
if( !top ) {
clangDebug() << "unable to find standard context for" << source.toLocalFile() << "Creating null range";
return KDevelop::DocumentRange::invalid();
}
if (!top->findDeclarations(identifier).isEmpty()) {
// Already forward-declared
return KDevelop::DocumentRange::invalid();
}
int line = std::numeric_limits< int >::max();
for( const auto decl : top->localDeclarations() ) {
line = std::min( line, decl->range().start.line );
}
if( line == std::numeric_limits< int >::max() ) {
return KDevelop::DocumentRange::invalid();
}
// We want it one line above the first declaration
line = std::max( line - 1, 0 );
return {IndexedString(source.pathOrUrl()), {line, 0, line, 0}};
}
/**
* Iteratively build all levels of the current scope. A (missing) type anywhere
* can be arbitrarily namespaced, so we create the permutations of possible
* nestings of namespaces it can currently be in,
*
* TODO: add detection of namespace aliases, such as 'using namespace KDevelop;'
*
* namespace foo {
* namespace bar {
* function baz() {
* type var;
* }
* }
* }
*
* Would give:
* foo::bar::baz::type
* foo::bar::type
* foo::type
* type
*/
QVector findPossibleQualifiedIdentifiers( const QualifiedIdentifier& identifier, const KDevelop::Path& file, const KDevelop::CursorInRevision& cursor )
{
DUChainReadLocker lock;
const TopDUContext* top = DUChainUtils::standardContextForUrl( file.toUrl() );
if( !top ) {
clangDebug() << "unable to find standard context for" << file.toLocalFile() << "Not creating duchain candidates";
return {};
}
const auto* context = top->findContextAt( cursor );
if( !context ) {
clangDebug() << "No context found at" << cursor;
return {};
}
QVector declarations{ identifier };
for( auto scopes = context->scopeIdentifier(); !scopes.isEmpty(); scopes.pop() ) {
declarations.append( scopes + identifier );
}
clangDebug() << "Possible declarations:" << declarations;
return declarations;
}
}
QStringList UnknownDeclarationProblem::findMatchingIncludeFiles(const QVector& declarations)
{
DUChainReadLocker lock;
QStringList candidates;
for (const auto decl: declarations) {
// skip declarations that don't belong to us
const auto& file = decl->topContext()->parsingEnvironmentFile();
if (!file || file->language() != ParseSession::languageString()) {
continue;
}
if( dynamic_cast( decl ) ) {
continue;
}
if( decl->isForwardDeclaration() ) {
continue;
}
const auto filepath = decl->url().toUrl().toLocalFile();
if( !isBlacklisted( filepath ) ) {
candidates << filepath;
clangDebug() << "Adding" << filepath << "determined from candidate" << decl->toString();
}
for( const auto importer : file->importers() ) {
if( importer->imports().count() != 1 && !isBlacklisted( filepath ) ) {
continue;
}
if( importer->topContext()->localDeclarations().count() ) {
continue;
}
const auto filePath = importer->url().toUrl().toLocalFile();
if( isBlacklisted( filePath ) ) {
continue;
}
/* This file is a forwarder, such as
* does not actually implement the functions, but include other headers that do
* we prefer this to other headers
*/
candidates << filePath;
clangDebug() << "Adding forwarder file" << filePath << "to the result set";
}
}
std::sort( candidates.begin(), candidates.end() );
candidates.erase( std::unique( candidates.begin(), candidates.end() ), candidates.end() );
clangDebug() << "Candidates: " << candidates;
return candidates;
}
namespace {
/**
* Takes a filepath and the include paths and determines what directive to use.
*/
ClangFixit directiveForFile( const QString& includefile, const KDevelop::Path::List& includepaths, const KDevelop::Path& source )
{
const auto sourceFolder = source.parent();
const Path canonicalFile( QFileInfo( includefile ).canonicalFilePath() );
QString shortestDirective;
bool isRelative = false;
// we can include the file directly
if (sourceFolder == canonicalFile.parent()) {
shortestDirective = canonicalFile.lastPathSegment();
isRelative = true;
} else {
// find the include directive with the shortest length
for( const auto& includePath : includepaths ) {
QString relative = includePath.relativePath( canonicalFile );
if( relative.startsWith( QLatin1String("./") ) )
relative = relative.mid( 2 );
if( shortestDirective.isEmpty() || relative.length() < shortestDirective.length() ) {
shortestDirective = relative;
isRelative = includePath == sourceFolder;
}
}
}
if( shortestDirective.isEmpty() ) {
// Item not found in include path
return {};
}
const auto range = DocumentRange(IndexedString(source.pathOrUrl()), includeDirectivePosition(source, canonicalFile.lastPathSegment()));
if( !range.isValid() ) {
clangDebug() << "unable to determine valid position for" << includefile << "in" << source.pathOrUrl();
return {};
}
QString directive;
if( isRelative ) {
directive = QStringLiteral("#include \"%1\"").arg(shortestDirective);
} else {
directive = QStringLiteral("#include <%1>").arg(shortestDirective);
}
return ClangFixit{directive + QLatin1Char('\n'), range, i18n("Insert \'%1\'", directive)};
}
KDevelop::Path::List includePaths( const KDevelop::Path& file )
{
// Find project's custom include paths
const auto source = file.toLocalFile();
const auto item = ICore::self()->projectController()->projectModel()->itemForPath( KDevelop::IndexedString( source ) );
return IDefinesAndIncludesManager::manager()->includes(item);
}
/**
* Return a list of header files viable for inclusions. All elements will be unique
*/
QStringList includeFiles(const QualifiedIdentifier& identifier, const QVector& declarations, const KDevelop::Path& file)
{
const auto includes = includePaths( file );
if( includes.isEmpty() ) {
clangDebug() << "Include path is empty";
return {};
}
const auto candidates = UnknownDeclarationProblem::findMatchingIncludeFiles(declarations);
if( !candidates.isEmpty() ) {
// If we find a candidate from the duchain we don't bother scanning the include paths
return candidates;
}
return scanIncludePaths(identifier, includes);
}
/**
* Construct viable forward declarations for the type name.
*/
ClangFixits forwardDeclarations(const QVector& matchingDeclarations, const Path& source)
{
DUChainReadLocker lock;
ClangFixits fixits;
for (const auto decl : matchingDeclarations) {
const auto qid = decl->qualifiedIdentifier();
if (qid.count() > 1) {
// TODO: Currently we're not able to determine what is namespaces, class names etc
// and makes a suitable forward declaration, so just suggest "vanilla" declarations.
continue;
}
const auto range = forwardDeclarationPosition(qid, source);
if (!range.isValid()) {
continue; // do not know where to insert
}
if (const auto classDecl = dynamic_cast(decl)) {
const auto name = qid.last().toString();
switch (classDecl->classType()) {
case ClassDeclarationData::Class:
fixits += {
QLatin1String("class ") + name + QLatin1String(";\n"), range,
i18n("Forward declare as 'class'")
};
break;
case ClassDeclarationData::Struct:
fixits += {
QLatin1String("struct ") + name + QLatin1String(";\n"), range,
i18n("Forward declare as 'struct'")
};
break;
default:
break;
}
}
}
return fixits;
}
/**
* Search the persistent symbol table for matching declarations for identifiers @p identifiers
*/
QVector findMatchingDeclarations(const QVector& identifiers)
{
DUChainReadLocker lock;
QVector matchingDeclarations;
matchingDeclarations.reserve(identifiers.size());
for (const auto& declaration : identifiers) {
clangDebug() << "Considering candidate declaration" << declaration;
const IndexedDeclaration* declarations;
uint declarationCount;
PersistentSymbolTable::self().declarations( declaration , declarationCount, declarations );
for (uint i = 0; i < declarationCount; ++i) {
// Skip if the declaration is invalid or if it is an alias declaration -
// we want the actual declaration (and its file)
if (auto decl = declarations[i].declaration()) {
matchingDeclarations << decl;
}
}
}
return matchingDeclarations;
}
ClangFixits fixUnknownDeclaration( const QualifiedIdentifier& identifier, const KDevelop::Path& file, const KDevelop::DocumentRange& docrange )
{
ClangFixits fixits;
const CursorInRevision cursor{docrange.start().line(), docrange.start().column()};
const auto possibleIdentifiers = findPossibleQualifiedIdentifiers(identifier, file, cursor);
const auto matchingDeclarations = findMatchingDeclarations(possibleIdentifiers);
if (ClangSettingsManager::self()->assistantsSettings().forwardDeclare) {
for (const auto& fixit : forwardDeclarations(matchingDeclarations, file)) {
fixits << fixit;
if (fixits.size() == maxSuggestions) {
return fixits;
}
}
}
const auto includefiles = includeFiles(identifier, matchingDeclarations, file);
if (includefiles.isEmpty()) {
// return early as the computation of the include paths is quite expensive
return fixits;
}
const auto includepaths = includePaths( file );
clangDebug() << "found include paths for" << file << ":" << includepaths;
/* create fixits for candidates */
for( const auto& includeFile : includefiles ) {
const auto fixit = directiveForFile( includeFile, includepaths, file /* UP */ );
if (!fixit.range.isValid()) {
clangDebug() << "unable to create directive for" << includeFile << "in" << file.toLocalFile();
continue;
}
fixits << fixit;
if (fixits.size() == maxSuggestions) {
return fixits;
}
}
return fixits;
}
QString symbolFromDiagnosticSpelling(const QString& str)
{
/* in all error messages the symbol is in in the first pair of quotes */
const auto split = str.split( QLatin1Char('\'') );
auto symbol = split.value( 1 );
if( str.startsWith( QLatin1String("No member named") ) ) {
symbol = split.value( 3 ) + QLatin1String("::") + split.value( 1 );
}
return symbol;
}
}
UnknownDeclarationProblem::UnknownDeclarationProblem(CXDiagnostic diagnostic, CXTranslationUnit unit)
: ClangProblem(diagnostic, unit)
{
setSymbol(QualifiedIdentifier(symbolFromDiagnosticSpelling(description())));
}
void UnknownDeclarationProblem::setSymbol(const QualifiedIdentifier& identifier)
{
m_identifier = identifier;
}
IAssistant::Ptr UnknownDeclarationProblem::solutionAssistant() const
{
const Path path(finalLocation().document.str());
const auto fixits = allFixits() + fixUnknownDeclaration(m_identifier, path, finalLocation());
return IAssistant::Ptr(new ClangFixitAssistant(fixits));
}
diff --git a/languages/clang/duchain/unknowndeclarationproblem.h b/plugins/clang/duchain/unknowndeclarationproblem.h
similarity index 100%
rename from languages/clang/duchain/unknowndeclarationproblem.h
rename to plugins/clang/duchain/unknowndeclarationproblem.h
diff --git a/languages/clang/duchain/unsavedfile.cpp b/plugins/clang/duchain/unsavedfile.cpp
similarity index 100%
rename from languages/clang/duchain/unsavedfile.cpp
rename to plugins/clang/duchain/unsavedfile.cpp
diff --git a/languages/clang/duchain/unsavedfile.h b/plugins/clang/duchain/unsavedfile.h
similarity index 100%
rename from languages/clang/duchain/unsavedfile.h
rename to plugins/clang/duchain/unsavedfile.h
diff --git a/languages/clang/duchain/wrappedQtHeaders/QtCore/qobjectdefs.h b/plugins/clang/duchain/wrappedQtHeaders/QtCore/qobjectdefs.h
similarity index 100%
rename from languages/clang/duchain/wrappedQtHeaders/QtCore/qobjectdefs.h
rename to plugins/clang/duchain/wrappedQtHeaders/QtCore/qobjectdefs.h
diff --git a/languages/clang/kdevclang.xml b/plugins/clang/kdevclang.xml
similarity index 100%
rename from languages/clang/kdevclang.xml
rename to plugins/clang/kdevclang.xml
diff --git a/languages/clang/kdevclangsupport.json b/plugins/clang/kdevclangsupport.json
similarity index 100%
rename from languages/clang/kdevclangsupport.json
rename to plugins/clang/kdevclangsupport.json
diff --git a/languages/clang/kdevclangsupport.qrc b/plugins/clang/kdevclangsupport.qrc
similarity index 100%
rename from languages/clang/kdevclangsupport.qrc
rename to plugins/clang/kdevclangsupport.qrc
diff --git a/languages/clang/kdevclangsupport.rc b/plugins/clang/kdevclangsupport.rc
similarity index 100%
rename from languages/clang/kdevclangsupport.rc
rename to plugins/clang/kdevclangsupport.rc
diff --git a/languages/clang/tests/CMakeLists.txt b/plugins/clang/tests/CMakeLists.txt
similarity index 98%
rename from languages/clang/tests/CMakeLists.txt
rename to plugins/clang/tests/CMakeLists.txt
index 12770d716f..dd9321135b 100644
--- a/languages/clang/tests/CMakeLists.txt
+++ b/plugins/clang/tests/CMakeLists.txt
@@ -1,104 +1,105 @@
add_executable(clang-parser
clang-parser.cpp
)
target_link_libraries(clang-parser
KDev::Tests
KDevClangPrivate
)
add_library(codecompletiontestbase STATIC codecompletiontestbase.cpp)
target_link_libraries(codecompletiontestbase PUBLIC
KDev::Tests
Qt5::Test
KDevClangPrivate
)
add_executable(clang-minimal-visitor WIN32
minimal_visitor.cpp
)
ecm_mark_nongui_executable(clang-minimal-visitor)
target_link_libraries(clang-minimal-visitor
${CLANG_LIBCLANG_LIB}
)
ecm_add_test(test_buddies.cpp
TEST_NAME test_buddies-clang
LINK_LIBRARIES
KDev::Tests
Qt5::Test
)
ecm_add_test(test_codecompletion.cpp
TEST_NAME test_codecompletion
LINK_LIBRARIES
codecompletiontestbase
)
ecm_add_test(test_assistants.cpp
TEST_NAME test_assistants
LINK_LIBRARIES
KDev::Tests
Qt5::Test
KDevClangPrivate
)
ecm_add_test(test_clangutils.cpp
TEST_NAME test_clangutils
LINK_LIBRARIES
KDev::Tests
Qt5::Test
${CLANG_LIBCLANG_LIB}
KDevClangPrivate
)
ecm_add_test(test_duchain.cpp
TEST_NAME test_duchain-clang
LINK_LIBRARIES
KDev::Tests
Qt5::Test
KDevClangPrivate
+ KDev::DefinesAndIncludesManager
)
ecm_add_test(test_refactoring.cpp
TEST_NAME test_refactoring-clang
LINK_LIBRARIES
KDev::Tests
Qt5::Test
KDevClangPrivate
)
ecm_add_test(test_duchainutils.cpp
TEST_NAME test_duchainutils
LINK_LIBRARIES
KDev::Tests
Qt5::Test
KDevClangPrivate
)
ecm_add_test(test_problems.cpp
TEST_NAME test_problems
LINK_LIBRARIES
KDev::Tests
Qt5::Test
KDevClangPrivate
)
configure_file("testfilepaths.h.cmake" "testfilepaths.h" ESCAPE_QUOTES)
ecm_add_test(test_files.cpp
TEST_NAME test_files-clang
LINK_LIBRARIES
Qt5::Test
Qt5::Core
KDev::Language
KDev::Tests
)
if(NOT COMPILER_OPTIMIZATIONS_DISABLED)
ecm_add_test(bench_codecompletion.cpp
TEST_NAME bench_codecompletion
LINK_LIBRARIES
codecompletiontestbase
)
set_tests_properties(bench_codecompletion PROPERTIES TIMEOUT 30)
endif()
diff --git a/languages/clang/tests/bench_codecompletion.cpp b/plugins/clang/tests/bench_codecompletion.cpp
similarity index 100%
rename from languages/clang/tests/bench_codecompletion.cpp
rename to plugins/clang/tests/bench_codecompletion.cpp
diff --git a/languages/clang/tests/bench_codecompletion.h b/plugins/clang/tests/bench_codecompletion.h
similarity index 100%
rename from languages/clang/tests/bench_codecompletion.h
rename to plugins/clang/tests/bench_codecompletion.h
diff --git a/languages/clang/tests/clang-parser.cpp b/plugins/clang/tests/clang-parser.cpp
similarity index 100%
rename from languages/clang/tests/clang-parser.cpp
rename to plugins/clang/tests/clang-parser.cpp
diff --git a/languages/clang/tests/codecompletiontestbase.cpp b/plugins/clang/tests/codecompletiontestbase.cpp
similarity index 100%
rename from languages/clang/tests/codecompletiontestbase.cpp
rename to plugins/clang/tests/codecompletiontestbase.cpp
diff --git a/languages/clang/tests/codecompletiontestbase.h b/plugins/clang/tests/codecompletiontestbase.h
similarity index 100%
rename from languages/clang/tests/codecompletiontestbase.h
rename to plugins/clang/tests/codecompletiontestbase.h
diff --git a/languages/clang/tests/files/basicdeclsandcontexts.cpp b/plugins/clang/tests/files/basicdeclsandcontexts.cpp
similarity index 100%
rename from languages/clang/tests/files/basicdeclsandcontexts.cpp
rename to plugins/clang/tests/files/basicdeclsandcontexts.cpp
diff --git a/languages/clang/tests/files/cuda.cu b/plugins/clang/tests/files/cuda.cu
similarity index 100%
rename from languages/clang/tests/files/cuda.cu
rename to plugins/clang/tests/files/cuda.cu
diff --git a/languages/clang/tests/files/defaultparameters.cpp b/plugins/clang/tests/files/defaultparameters.cpp
similarity index 100%
rename from languages/clang/tests/files/defaultparameters.cpp
rename to plugins/clang/tests/files/defaultparameters.cpp
diff --git a/languages/clang/tests/files/forwarddeclarations.cpp b/plugins/clang/tests/files/forwarddeclarations.cpp
similarity index 100%
rename from languages/clang/tests/files/forwarddeclarations.cpp
rename to plugins/clang/tests/files/forwarddeclarations.cpp
diff --git a/languages/clang/tests/files/friends.cpp b/plugins/clang/tests/files/friends.cpp
similarity index 100%
rename from languages/clang/tests/files/friends.cpp
rename to plugins/clang/tests/files/friends.cpp
diff --git a/languages/clang/tests/files/functiondefinitiondeclarations.cpp b/plugins/clang/tests/files/functiondefinitiondeclarations.cpp
similarity index 100%
rename from languages/clang/tests/files/functiondefinitiondeclarations.cpp
rename to plugins/clang/tests/files/functiondefinitiondeclarations.cpp
diff --git a/languages/clang/tests/files/functions.cpp b/plugins/clang/tests/files/functions.cpp
similarity index 100%
rename from languages/clang/tests/files/functions.cpp
rename to plugins/clang/tests/files/functions.cpp
diff --git a/languages/clang/tests/files/imports.cpp b/plugins/clang/tests/files/imports.cpp
similarity index 100%
rename from languages/clang/tests/files/imports.cpp
rename to plugins/clang/tests/files/imports.cpp
diff --git a/languages/clang/tests/files/includes.cpp b/plugins/clang/tests/files/includes.cpp
similarity index 100%
rename from languages/clang/tests/files/includes.cpp
rename to plugins/clang/tests/files/includes.cpp
diff --git a/languages/clang/tests/files/includes/bar.h b/plugins/clang/tests/files/includes/bar.h
similarity index 100%
rename from languages/clang/tests/files/includes/bar.h
rename to plugins/clang/tests/files/includes/bar.h
diff --git a/languages/clang/tests/files/includes/foo.h b/plugins/clang/tests/files/includes/foo.h
similarity index 100%
rename from languages/clang/tests/files/includes/foo.h
rename to plugins/clang/tests/files/includes/foo.h
diff --git a/languages/clang/tests/files/invalid.cpp b/plugins/clang/tests/files/invalid.cpp
similarity index 100%
rename from languages/clang/tests/files/invalid.cpp
rename to plugins/clang/tests/files/invalid.cpp
diff --git a/languages/clang/tests/files/macros.cpp b/plugins/clang/tests/files/macros.cpp
similarity index 100%
rename from languages/clang/tests/files/macros.cpp
rename to plugins/clang/tests/files/macros.cpp
diff --git a/languages/clang/tests/files/namespaces.cpp b/plugins/clang/tests/files/namespaces.cpp
similarity index 100%
rename from languages/clang/tests/files/namespaces.cpp
rename to plugins/clang/tests/files/namespaces.cpp
diff --git a/languages/clang/tests/files/operators.cpp b/plugins/clang/tests/files/operators.cpp
similarity index 100%
rename from languages/clang/tests/files/operators.cpp
rename to plugins/clang/tests/files/operators.cpp
diff --git a/languages/clang/tests/files/outofline.cpp b/plugins/clang/tests/files/outofline.cpp
similarity index 100%
rename from languages/clang/tests/files/outofline.cpp
rename to plugins/clang/tests/files/outofline.cpp
diff --git a/languages/clang/tests/files/purec.c b/plugins/clang/tests/files/purec.c
similarity index 100%
rename from languages/clang/tests/files/purec.c
rename to plugins/clang/tests/files/purec.c
diff --git a/languages/clang/tests/files/special.cpp b/plugins/clang/tests/files/special.cpp
similarity index 100%
rename from languages/clang/tests/files/special.cpp
rename to plugins/clang/tests/files/special.cpp
diff --git a/languages/clang/tests/files/templates.cpp b/plugins/clang/tests/files/templates.cpp
similarity index 100%
rename from languages/clang/tests/files/templates.cpp
rename to plugins/clang/tests/files/templates.cpp
diff --git a/languages/clang/tests/files/test.cl b/plugins/clang/tests/files/test.cl
similarity index 100%
rename from languages/clang/tests/files/test.cl
rename to plugins/clang/tests/files/test.cl
diff --git a/languages/clang/tests/files/types.cpp b/plugins/clang/tests/files/types.cpp
similarity index 100%
rename from languages/clang/tests/files/types.cpp
rename to plugins/clang/tests/files/types.cpp
diff --git a/languages/clang/tests/files/uses.cpp b/plugins/clang/tests/files/uses.cpp
similarity index 100%
rename from languages/clang/tests/files/uses.cpp
rename to plugins/clang/tests/files/uses.cpp
diff --git a/languages/clang/tests/files/variables.cpp b/plugins/clang/tests/files/variables.cpp
similarity index 100%
rename from languages/clang/tests/files/variables.cpp
rename to plugins/clang/tests/files/variables.cpp
diff --git a/languages/clang/tests/minimal_visitor.cpp b/plugins/clang/tests/minimal_visitor.cpp
similarity index 100%
rename from languages/clang/tests/minimal_visitor.cpp
rename to plugins/clang/tests/minimal_visitor.cpp
diff --git a/languages/clang/tests/test_assistants.cpp b/plugins/clang/tests/test_assistants.cpp
similarity index 100%
rename from languages/clang/tests/test_assistants.cpp
rename to plugins/clang/tests/test_assistants.cpp
diff --git a/languages/clang/tests/test_assistants.h b/plugins/clang/tests/test_assistants.h
similarity index 100%
rename from languages/clang/tests/test_assistants.h
rename to plugins/clang/tests/test_assistants.h
diff --git a/languages/clang/tests/test_buddies.cpp b/plugins/clang/tests/test_buddies.cpp
similarity index 100%
rename from languages/clang/tests/test_buddies.cpp
rename to plugins/clang/tests/test_buddies.cpp
diff --git a/languages/clang/tests/test_buddies.h b/plugins/clang/tests/test_buddies.h
similarity index 100%
rename from languages/clang/tests/test_buddies.h
rename to plugins/clang/tests/test_buddies.h
diff --git a/languages/clang/tests/test_clangutils.cpp b/plugins/clang/tests/test_clangutils.cpp
similarity index 100%
rename from languages/clang/tests/test_clangutils.cpp
rename to plugins/clang/tests/test_clangutils.cpp
diff --git a/languages/clang/tests/test_clangutils.h b/plugins/clang/tests/test_clangutils.h
similarity index 100%
rename from languages/clang/tests/test_clangutils.h
rename to plugins/clang/tests/test_clangutils.h
diff --git a/languages/clang/tests/test_codecompletion.cpp b/plugins/clang/tests/test_codecompletion.cpp
similarity index 100%
rename from languages/clang/tests/test_codecompletion.cpp
rename to plugins/clang/tests/test_codecompletion.cpp
diff --git a/languages/clang/tests/test_codecompletion.h b/plugins/clang/tests/test_codecompletion.h
similarity index 100%
rename from languages/clang/tests/test_codecompletion.h
rename to plugins/clang/tests/test_codecompletion.h
diff --git a/languages/clang/tests/test_duchain.cpp b/plugins/clang/tests/test_duchain.cpp
similarity index 99%
rename from languages/clang/tests/test_duchain.cpp
rename to plugins/clang/tests/test_duchain.cpp
index 2c75713296..657b386cba 100644
--- a/languages/clang/tests/test_duchain.cpp
+++ b/plugins/clang/tests/test_duchain.cpp
@@ -1,2024 +1,2024 @@
/*
* Copyright 2014 Milian Wolff
* Copyright 2014 Kevin Funk
* Copyright 2015 Sergey Kalinichev
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 .
*/
#include "test_duchain.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "duchain/clangparsingenvironmentfile.h"
#include "duchain/clangparsingenvironment.h"
#include "duchain/parsesession.h"
-#include
+#include
#include
#include
#include
#include
#include
QTEST_MAIN(TestDUChain);
using namespace KDevelop;
class TestEnvironmentProvider final : public IDefinesAndIncludesManager::BackgroundProvider
{
public:
~TestEnvironmentProvider() override = default;
QHash< QString, QString > definesInBackground(const QString& /*path*/) const override
{
return defines;
}
Path::List includesInBackground(const QString& /*path*/) const override
{
return includes;
}
Path::List frameworkDirectoriesInBackground(const QString&) const override
{
return {};
}
IDefinesAndIncludesManager::Type type() const override
{
return IDefinesAndIncludesManager::UserDefined;
}
QHash defines;
Path::List includes;
};
TestDUChain::~TestDUChain() = default;
void TestDUChain::initTestCase()
{
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=false\ndefault.debug=true\nkdevelop.plugins.clang.debug=true\n"));
QVERIFY(qputenv("KDEV_DISABLE_PLUGINS", "kdevcppsupport"));
QVERIFY(qputenv("KDEV_CLANG_DISPLAY_DIAGS", "1"));
AutoTestShell::init({QStringLiteral("kdevclangsupport")});
auto core = TestCore::initialize();
delete core->projectController();
m_projectController = new TestProjectController(core);
core->setProjectController(m_projectController);
}
void TestDUChain::cleanupTestCase()
{
TestCore::shutdown();
}
void TestDUChain::cleanup()
{
if (m_provider) {
IDefinesAndIncludesManager::manager()->unregisterBackgroundProvider(m_provider.data());
}
}
void TestDUChain::init()
{
m_provider.reset(new TestEnvironmentProvider);
IDefinesAndIncludesManager::manager()->registerBackgroundProvider(m_provider.data());
}
struct ExpectedComment
{
QString identifier;
QString comment;
};
Q_DECLARE_METATYPE(ExpectedComment)
Q_DECLARE_METATYPE(AbstractType::WhichType)
void TestDUChain::testComments()
{
QFETCH(QString, code);
QFETCH(ExpectedComment, expectedComment);
TestFile file(code, QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
auto top = file.topContext();
QVERIFY(top);
auto candidates = top->findDeclarations(QualifiedIdentifier(expectedComment.identifier));
QVERIFY(!candidates.isEmpty());
auto decl = candidates.first();
QString comment = QString::fromLocal8Bit(decl->comment());
comment = KDevelop::htmlToPlainText(comment, KDevelop::CompleteMode);
QCOMPARE(comment, expectedComment.comment);
}
void TestDUChain::testComments_data()
{
QTest::addColumn("code");
QTest::addColumn("expectedComment");
// note: Clang only retrieves the comments when in doxygen-style format (i.e. '///', '/**', '///<')
QTest::newRow("invalid1")
<< "//this is foo\nint foo;"
<< ExpectedComment{"foo", QString()};
QTest::newRow("invalid2")
<< "/*this is foo*/\nint foo;"
<< ExpectedComment{"foo", QString()};
QTest::newRow("basic1")
<< "///this is foo\nint foo;"
<< ExpectedComment{"foo", "this is foo"};
QTest::newRow("basic2")
<< "/**this is foo*/\nint foo;"
<< ExpectedComment{"foo", "this is foo"};
QTest::newRow("enumerator")
<< "enum Foo { bar1, ///localDeclarations().size(), 2);
auto decl = file.topContext()->localDeclarations()[1];
QVERIFY(decl);
auto function = dynamic_cast(decl);
QVERIFY(function);
auto functionType = function->type();
QVERIFY(functionType);
#if CINDEX_VERSION_MINOR < 34
QEXPECT_FAIL("namespace", "The ElaboratedType is not exposed through the libclang interface, not much we can do here", Abort);
#endif
QVERIFY(functionType->returnType()->whichType() != AbstractType::TypeDelayed);
#if CINDEX_VERSION_MINOR < 34
QEXPECT_FAIL("typedef", "After using clang_getCanonicalType on ElaboratedType all typedef information get's stripped away", Continue);
#endif
QCOMPARE(functionType->returnType()->whichType(), type);
}
void TestDUChain::testElaboratedType_data()
{
QTest::addColumn("code");
QTest::addColumn("type");
QTest::newRow("namespace")
<< "namespace NS{struct Type{};} struct NS::Type foo();"
<< AbstractType::TypeStructure;
QTest::newRow("enum")
<< "enum Enum{}; enum Enum foo();"
<< AbstractType::TypeEnumeration;
QTest::newRow("typedef")
<< "namespace NS{typedef int type;} NS::type foo();"
<< AbstractType::TypeAlias;
}
void TestDUChain::testInclude()
{
TestFile header(QStringLiteral("int foo() { return 42; }\n"), QStringLiteral("h"));
// NOTE: header is _not_ explicitly being parsed, instead the impl job does that
TestFile impl("#include \"" + header.url().str() + "\"\n"
"int main() { return foo(); }", QStringLiteral("cpp"), &header);
impl.parse(TopDUContext::AllDeclarationsContextsAndUses);
auto implCtx = impl.topContext();
QVERIFY(implCtx);
DUChainReadLocker lock;
QCOMPARE(implCtx->localDeclarations().size(), 1);
auto headerCtx = DUChain::self()->chainForDocument(header.url());
QVERIFY(headerCtx);
QVERIFY(!headerCtx->parsingEnvironmentFile()->needsUpdate());
QCOMPARE(headerCtx->localDeclarations().size(), 1);
QVERIFY(implCtx->imports(headerCtx, CursorInRevision(0, 10)));
Declaration* foo = headerCtx->localDeclarations().first();
QCOMPARE(foo->uses().size(), 1);
QCOMPARE(foo->uses().begin().key(), impl.url());
QCOMPARE(foo->uses().begin()->size(), 1);
QCOMPARE(foo->uses().begin()->first(), RangeInRevision(1, 20, 1, 23));
}
void TestDUChain::testMissingInclude()
{
auto code = R"(
#pragma once
#include "missing1.h"
template
class A
{
T a;
};
#include "missing2.h"
class B : public A
{
};
)";
// NOTE: This fails and needs fixing. If the include of "missing2.h"
// above is commented out, then it doesn't fail. Maybe
// clang stops processing when it encounters the second missing
// header, or similar.
TestFile header(code, QStringLiteral("h"));
TestFile impl("#include \"" + header.url().str() + "\"\n", QStringLiteral("cpp"), &header);
QVERIFY(impl.parseAndWait(TopDUContext::AllDeclarationsContextsAndUses));
DUChainReadLocker lock;
auto top = impl.topContext();
QVERIFY(top);
QCOMPARE(top->importedParentContexts().count(), 1);
TopDUContext* headerCtx = dynamic_cast(top->importedParentContexts().first().context(top));
QVERIFY(headerCtx);
QCOMPARE(headerCtx->url(), header.url());
#if CINDEX_VERSION_MINOR < 34
QEXPECT_FAIL("", "Second missing header isn't reported", Continue);
#endif
QCOMPARE(headerCtx->problems().count(), 2);
QCOMPARE(headerCtx->localDeclarations().count(), 2);
auto a = dynamic_cast(headerCtx->localDeclarations().first());
QVERIFY(a);
auto b = dynamic_cast(headerCtx->localDeclarations().last());
QVERIFY(b);
#if CINDEX_VERSION_MINOR < 34
QEXPECT_FAIL("", "Base class isn't assigned correctly", Continue);
#endif
QCOMPARE(b->baseClassesSize(), 1u);
#if CINDEX_VERSION_MINOR < 34
// at least the one problem we have should have been propagated
QCOMPARE(top->problems().count(), 1);
#else
// two errors:
// /tmp/testfile_f32415.h:3:10: error: 'missing1.h' file not found
// /tmp/testfile_f32415.h:11:10: error: 'missing2.h' file not found
QCOMPARE(top->problems().count(), 2);
#endif
}
QByteArray createCode(const QByteArray& prefix, const int functions)
{
QByteArray code;
code += "#ifndef " + prefix + "_H\n";
code += "#define " + prefix + "_H\n";
for (int i = 0; i < functions; ++i) {
code += "void myFunc_" + prefix + "(int arg1, char arg2, const char* arg3);\n";
}
code += "#endif\n";
return code;
}
void TestDUChain::testIncludeLocking()
{
TestFile header1(createCode("Header1", 1000), QStringLiteral("h"));
TestFile header2(createCode("Header2", 1000), QStringLiteral("h"));
TestFile header3(createCode("Header3", 1000), QStringLiteral("h"));
ICore::self()->languageController()->backgroundParser()->setThreadCount(3);
TestFile impl1("#include \"" + header1.url().str() + "\"\n"
"#include \"" + header2.url().str() + "\"\n"
"#include \"" + header3.url().str() + "\"\n"
"int main() { return 0; }", QStringLiteral("cpp"));
TestFile impl2("#include \"" + header2.url().str() + "\"\n"
"#include \"" + header1.url().str() + "\"\n"
"#include \"" + header3.url().str() + "\"\n"
"int main() { return 0; }", QStringLiteral("cpp"));
TestFile impl3("#include \"" + header3.url().str() + "\"\n"
"#include \"" + header1.url().str() + "\"\n"
"#include \"" + header2.url().str() + "\"\n"
"int main() { return 0; }", QStringLiteral("cpp"));
impl1.parse(TopDUContext::AllDeclarationsContextsAndUses);
impl2.parse(TopDUContext::AllDeclarationsContextsAndUses);
impl3.parse(TopDUContext::AllDeclarationsContextsAndUses);
QVERIFY(impl1.waitForParsed(5000));
QVERIFY(impl2.waitForParsed(5000));
QVERIFY(impl3.waitForParsed(5000));
DUChainReadLocker lock;
QVERIFY(DUChain::self()->chainForDocument(header1.url()));
QVERIFY(DUChain::self()->chainForDocument(header2.url()));
QVERIFY(DUChain::self()->chainForDocument(header3.url()));
}
void TestDUChain::testReparse()
{
TestFile file(QStringLiteral("int main() { int i = 42; return i; }"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
DeclarationPointer mainDecl;
DeclarationPointer iDecl;
for (int i = 0; i < 3; ++i) {
QVERIFY(file.waitForParsed(500));
DUChainReadLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->childContexts().size(), 1);
QCOMPARE(file.topContext()->localDeclarations().size(), 1);
DUContext *exprContext = file.topContext()->childContexts().first()->childContexts().first();
QCOMPARE(exprContext->localDeclarations().size(), 1);
if (i) {
QVERIFY(mainDecl);
QCOMPARE(mainDecl.data(), file.topContext()->localDeclarations().first());
QVERIFY(iDecl);
QCOMPARE(iDecl.data(), exprContext->localDeclarations().first());
}
mainDecl = file.topContext()->localDeclarations().first();
iDecl = exprContext->localDeclarations().first();
QVERIFY(mainDecl->uses().isEmpty());
QCOMPARE(iDecl->uses().size(), 1);
QCOMPARE(iDecl->uses().begin()->size(), 1);
if (i == 1) {
file.setFileContents(QStringLiteral("int main()\n{\nfloat i = 13; return i - 5;\n}\n"));
}
file.parse(TopDUContext::Features(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive));
}
}
void TestDUChain::testReparseError()
{
TestFile file(QStringLiteral("int i = 1 / 0;\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
for (int i = 0; i < 2; ++i) {
QVERIFY(file.waitForParsed(500));
DUChainReadLocker lock;
QVERIFY(file.topContext());
if (!i) {
QCOMPARE(file.topContext()->problems().size(), 1);
file.setFileContents(QStringLiteral("int i = 0;\n"));
} else {
QCOMPARE(file.topContext()->problems().size(), 0);
}
file.parse(TopDUContext::Features(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive));
}
}
void TestDUChain::testTemplate()
{
TestFile file("template struct foo { T bar; };\n"
"int main() { foo myFoo; return myFoo.bar; }\n", QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->localDeclarations().size(), 2);
auto fooDecl = file.topContext()->localDeclarations().first();
QVERIFY(fooDecl->internalContext());
QCOMPARE(fooDecl->internalContext()->localDeclarations().size(), 2);
QCOMPARE(file.topContext()->findDeclarations(QualifiedIdentifier("foo< T >")).size(), 1);
QCOMPARE(file.topContext()->findDeclarations(QualifiedIdentifier("foo< T >::bar")).size(), 1);
auto mainCtx = file.topContext()->localDeclarations().last()->internalContext()->childContexts().first();
QVERIFY(mainCtx);
auto myFoo = mainCtx->localDeclarations().first();
QVERIFY(myFoo);
QCOMPARE(myFoo->abstractType()->toString().remove(' '), QStringLiteral("foo"));
}
void TestDUChain::testNamespace()
{
TestFile file("namespace foo { struct bar { int baz; }; }\n"
"int main() { foo::bar myBar; }\n", QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->localDeclarations().size(), 2);
auto fooDecl = file.topContext()->localDeclarations().first();
QVERIFY(fooDecl->internalContext());
QCOMPARE(fooDecl->internalContext()->localDeclarations().size(), 1);
DUContext* top = file.topContext().data();
DUContext* mainCtx = file.topContext()->childContexts().last();
auto foo = top->localDeclarations().first();
QCOMPARE(foo->qualifiedIdentifier().toString(), QString("foo"));
DUContext* fooCtx = file.topContext()->childContexts().first();
QCOMPARE(fooCtx->localScopeIdentifier().toString(), QString("foo"));
QCOMPARE(fooCtx->scopeIdentifier(true).toString(), QString("foo"));
QCOMPARE(fooCtx->localDeclarations().size(), 1);
auto bar = fooCtx->localDeclarations().first();
QCOMPARE(bar->qualifiedIdentifier().toString(), QString("foo::bar"));
QCOMPARE(fooCtx->childContexts().size(), 1);
DUContext* barCtx = fooCtx->childContexts().first();
QCOMPARE(barCtx->localScopeIdentifier().toString(), QString("bar"));
QCOMPARE(barCtx->scopeIdentifier(true).toString(), QString("foo::bar"));
QCOMPARE(barCtx->localDeclarations().size(), 1);
auto baz = barCtx->localDeclarations().first();
QCOMPARE(baz->qualifiedIdentifier().toString(), QString("foo::bar::baz"));
for (auto ctx : {top, mainCtx}) {
QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo")).size(), 1);
QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo::bar")).size(), 1);
QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo::bar::baz")).size(), 1);
}
}
void TestDUChain::testAutoTypeDeduction()
{
TestFile file(QStringLiteral(R"(
const volatile auto foo = 5;
template struct myTemplate {};
myTemplate& > templRefParam;
auto autoTemplRefParam = templRefParam;
)"), QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
DUContext* ctx = file.topContext().data();
QVERIFY(ctx);
QCOMPARE(ctx->localDeclarations().size(), 4);
QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo")).size(), 1);
Declaration* decl = ctx->findDeclarations(QualifiedIdentifier(QStringLiteral("foo")))[0];
QCOMPARE(decl->identifier(), Identifier("foo"));
#if CINDEX_VERSION_MINOR < 31
QEXPECT_FAIL("", "No type deduction here unfortunately, missing API in Clang", Continue);
#endif
QVERIFY(decl->type());
#if CINDEX_VERSION_MINOR < 31
QCOMPARE(decl->toString(), QStringLiteral("const volatile auto foo"));
#else
QCOMPARE(decl->toString(), QStringLiteral("const volatile int foo"));
#endif
decl = ctx->findDeclarations(QualifiedIdentifier(QStringLiteral("autoTemplRefParam")))[0];
QVERIFY(decl);
QVERIFY(decl->abstractType());
#if CINDEX_VERSION_MINOR < 31
QEXPECT_FAIL("", "Auto type is not exposed via LibClang", Continue);
#endif
QCOMPARE(decl->abstractType()->toString(), QStringLiteral("myTemplate< myTemplate< int >& >"));
}
void TestDUChain::testTypeDeductionInTemplateInstantiation()
{
// see: http://clang-developers.42468.n3.nabble.com/RFC-missing-libclang-query-functions-features-td2504253.html
TestFile file(QStringLiteral("template struct foo { T member; } foo f; auto i = f.member;"), QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
DUContext* ctx = file.topContext().data();
QVERIFY(ctx);
QCOMPARE(ctx->localDeclarations().size(), 3);
Declaration* decl = nullptr;
// check 'foo' declaration
decl = ctx->localDeclarations()[0];
QVERIFY(decl);
QCOMPARE(decl->identifier(), Identifier("foo< T >"));
// check type of 'member' inside declaration-scope
QCOMPARE(ctx->childContexts().size(), 1);
DUContext* fooCtx = ctx->childContexts().first();
QVERIFY(fooCtx);
// Should there really be two declarations?
QCOMPARE(fooCtx->localDeclarations().size(), 2);
decl = fooCtx->localDeclarations()[1];
QCOMPARE(decl->identifier(), Identifier("member"));
// check type of 'member' in definition of 'f'
decl = ctx->localDeclarations()[1];
QCOMPARE(decl->identifier(), Identifier("f"));
decl = ctx->localDeclarations()[2];
QCOMPARE(decl->identifier(), Identifier("i"));
#if CINDEX_VERSION_MINOR < 31
QEXPECT_FAIL("", "No type deduction here unfortunately, missing API in Clang", Continue);
#endif
QVERIFY(decl->type());
}
void TestDUChain::testVirtualMemberFunction()
{
//Forward-declarations with "struct" or "class" are considered equal, so make sure the override is detected correctly.
TestFile file(QStringLiteral("struct S {}; struct A { virtual S* ret(); }; struct B : public A { virtual S* ret(); };"), QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
DUContext* top = file.topContext().data();
QVERIFY(top);
QCOMPARE(top->childContexts().count(), 3);
QCOMPARE(top->localDeclarations().count(), 3);
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
Declaration* decl = top->childContexts()[2]->localDeclarations()[0];
QCOMPARE(decl->identifier(), Identifier("ret"));
QVERIFY(DUChainUtils::getOverridden(decl));
}
void TestDUChain::testBaseClasses()
{
TestFile file(QStringLiteral("class Base {}; class Inherited : public Base {};"), QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
DUContext* top = file.topContext().data();
QVERIFY(top);
QCOMPARE(top->localDeclarations().count(), 2);
Declaration* baseDecl = top->localDeclarations().first();
QCOMPARE(baseDecl->identifier(), Identifier("Base"));
ClassDeclaration* inheritedDecl = dynamic_cast(top->localDeclarations()[1]);
QCOMPARE(inheritedDecl->identifier(), Identifier("Inherited"));
QVERIFY(inheritedDecl);
QCOMPARE(inheritedDecl->baseClassesSize(), 1u);
QCOMPARE(baseDecl->uses().count(), 1);
QCOMPARE(baseDecl->uses().first().count(), 1);
QCOMPARE(baseDecl->uses().first().first(), RangeInRevision(0, 40, 0, 44));
}
void TestDUChain::testReparseBaseClasses()
{
TestFile file(QStringLiteral("struct a{}; struct b : a {};\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
for (int i = 0; i < 2; ++i) {
qDebug() << "run: " << i;
QVERIFY(file.waitForParsed(500));
DUChainWriteLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->childContexts().size(), 2);
QCOMPARE(file.topContext()->childContexts().first()->importers().size(), 1);
QCOMPARE(file.topContext()->childContexts().last()->importedParentContexts().size(), 1);
QCOMPARE(file.topContext()->localDeclarations().size(), 2);
auto aDecl = dynamic_cast(file.topContext()->localDeclarations().first());
QVERIFY(aDecl);
QCOMPARE(aDecl->baseClassesSize(), 0u);
auto bDecl = dynamic_cast(file.topContext()->localDeclarations().last());
QVERIFY(bDecl);
QCOMPARE(bDecl->baseClassesSize(), 1u);
int distance = 0;
QVERIFY(bDecl->isPublicBaseClass(aDecl, file.topContext(), &distance));
QCOMPARE(distance, 1);
file.parse(TopDUContext::Features(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive));
}
}
void TestDUChain::testReparseBaseClassesTemplates()
{
TestFile file(QStringLiteral("template struct a{}; struct b : a {};\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
for (int i = 0; i < 2; ++i) {
qDebug() << "run: " << i;
QVERIFY(file.waitForParsed(500));
DUChainWriteLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->childContexts().size(), 2);
QCOMPARE(file.topContext()->childContexts().first()->importers().size(), 1);
QCOMPARE(file.topContext()->childContexts().last()->importedParentContexts().size(), 1);
QCOMPARE(file.topContext()->localDeclarations().size(), 2);
auto aDecl = dynamic_cast(file.topContext()->localDeclarations().first());
QVERIFY(aDecl);
QCOMPARE(aDecl->baseClassesSize(), 0u);
auto bDecl = dynamic_cast(file.topContext()->localDeclarations().last());
QVERIFY(bDecl);
QCOMPARE(bDecl->baseClassesSize(), 1u);
int distance = 0;
QVERIFY(bDecl->isPublicBaseClass(aDecl, file.topContext(), &distance));
QCOMPARE(distance, 1);
file.parse(TopDUContext::Features(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive));
}
}
void TestDUChain::testGetInheriters_data()
{
QTest::addColumn("code");
QTest::newRow("inline") << "struct Base { struct Inner {}; }; struct Inherited : Base, Base::Inner {};";
QTest::newRow("outline") << "struct Base { struct Inner; }; struct Base::Inner {}; struct Inherited : Base, Base::Inner {};";
}
void TestDUChain::testGetInheriters()
{
QFETCH(QString, code);
TestFile file(code, QStringLiteral("cpp"));
QVERIFY(file.parseAndWait());
DUChainReadLocker lock;
auto top = file.topContext();
QVERIFY(top);
QVERIFY(top->problems().isEmpty());
QCOMPARE(top->localDeclarations().count(), 2);
Declaration* baseDecl = top->localDeclarations().first();
QCOMPARE(baseDecl->identifier(), Identifier("Base"));
DUContext* baseCtx = baseDecl->internalContext();
QVERIFY(baseCtx);
QCOMPARE(baseCtx->localDeclarations().count(), 1);
Declaration* innerDecl = baseCtx->localDeclarations().first();
QCOMPARE(innerDecl->identifier(), Identifier("Inner"));
if (auto forward = dynamic_cast(innerDecl)) {
innerDecl = forward->resolve(top);
}
QVERIFY(dynamic_cast(innerDecl));
Declaration* inheritedDecl = top->localDeclarations().last();
QVERIFY(inheritedDecl);
QCOMPARE(inheritedDecl->identifier(), Identifier("Inherited"));
uint maxAllowedSteps = uint(-1);
auto baseInheriters = DUChainUtils::getInheriters(baseDecl, maxAllowedSteps);
QCOMPARE(baseInheriters, QList() << inheritedDecl);
maxAllowedSteps = uint(-1);
auto innerInheriters = DUChainUtils::getInheriters(innerDecl, maxAllowedSteps);
QCOMPARE(innerInheriters, QList() << inheritedDecl);
maxAllowedSteps = uint(-1);
auto inheritedInheriters = DUChainUtils::getInheriters(inheritedDecl, maxAllowedSteps);
QCOMPARE(inheritedInheriters.count(), 0);
}
void TestDUChain::testGlobalFunctionDeclaration()
{
TestFile file(QStringLiteral("void foo(int arg1, char arg2);\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
file.waitForParsed();
DUChainReadLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->localDeclarations().size(), 1);
QCOMPARE(file.topContext()->childContexts().size(), 1);
QVERIFY(!file.topContext()->childContexts().first()->inSymbolTable());
}
void TestDUChain::testFunctionDefinitionVsDeclaration()
{
TestFile file(QStringLiteral("void func(); void func() {}\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
QVERIFY(file.waitForParsed());
DUChainReadLocker lock;
QVERIFY(file.topContext());
QCOMPARE(file.topContext()->localDeclarations().size(), 2);
auto funcDecl = file.topContext()->localDeclarations()[0];
QVERIFY(!funcDecl->isDefinition());
QVERIFY(!dynamic_cast(funcDecl));
auto funcDef = file.topContext()->localDeclarations()[1];
QVERIFY(dynamic_cast(funcDef));
QVERIFY(funcDef->isDefinition());
}
void TestDUChain::testEnsureNoDoubleVisit()
{
// On some language construct, we may up visiting the same cursor multiple times
// Example: "struct SomeStruct {} s;"
// decl: "SomeStruct SomeStruct " of kind StructDecl (2) in main.cpp@[(1,1),(1,17)]
// decl: "struct SomeStruct s " of kind VarDecl (9) in main.cpp@[(1,1),(1,19)]
// decl: "SomeStruct SomeStruct " of kind StructDecl (2) in main.cpp@[(1,1),(1,17)]
//
// => We end up visiting the StructDecl twice (or more)
// That's because we use clang_visitChildren not just on the translation unit cursor.
// Apparently just "recursing" vs. "visiting children explicitly"
// results in a different AST traversal
TestFile file(QStringLiteral("struct SomeStruct {} s;\n"), QStringLiteral("cpp"));
file.parse(TopDUContext::AllDeclarationsContextsAndUses);
QVERIFY(file.waitForParsed());
DUChainReadLocker lock;
auto top = file.topContext();
QVERIFY(top);
// there should only be one declaration for "SomeStruct"
auto candidates = top->findDeclarations(QualifiedIdentifier(QStringLiteral("SomeStruct")));
QCOMPARE(candidates.size(), 1);
}
void TestDUChain::testParsingEnvironment()
{
const TopDUContext::Features features = TopDUContext::AllDeclarationsContextsAndUses;
IndexedTopDUContext indexed;
ClangParsingEnvironment lastEnv;
{
TestFile file(QStringLiteral("int main() {}\n"), QStringLiteral("cpp"));
auto astFeatures = static_cast(features | TopDUContext::AST);
file.parse(astFeatures);
file.setKeepDUChainData(true);
QVERIFY(file.waitForParsed());
DUChainWriteLocker lock;
auto top = file.topContext();
QVERIFY(top);
auto sessionData = ParseSessionData::Ptr(dynamic_cast(top->ast().data()));
lock.unlock();
ParseSession session(sessionData);
lock.lock();
QVERIFY(session.data());
QVERIFY(top);
auto envFile = QExplicitlySharedDataPointer(
dynamic_cast(file.topContext()->parsingEnvironmentFile().data()));
QCOMPARE(envFile->features(), astFeatures);
QVERIFY(envFile->featuresSatisfied(astFeatures));
QCOMPARE(envFile->environmentQuality(), ClangParsingEnvironment::Source);
// if no environment is given, no update should be triggered
QVERIFY(!envFile->needsUpdate());
// same env should also not trigger a reparse
ClangParsingEnvironment env = session.environment();
QCOMPARE(env.quality(), ClangParsingEnvironment::Source);
QVERIFY(!envFile->needsUpdate(&env));
// but changing the environment should trigger an update
env.addIncludes(Path::List() << Path(QStringLiteral("/foo/bar/baz")));
QVERIFY(envFile->needsUpdate(&env));
envFile->setEnvironment(env);
QVERIFY(!envFile->needsUpdate(&env));
// setting the environment quality higher should require an update
env.setQuality(ClangParsingEnvironment::BuildSystem);
QVERIFY(envFile->needsUpdate(&env));
envFile->setEnvironment(env);
QVERIFY(!envFile->needsUpdate(&env));
// changing defines requires an update
env.addDefines(QHash{ { "foo", "bar" } });
QVERIFY(envFile->needsUpdate(&env));
// but only when changing the defines for the envFile's TU
const auto barTU = IndexedString("bar.cpp");
const auto oldTU = env.translationUnitUrl();
env.setTranslationUnitUrl(barTU);
QCOMPARE(env.translationUnitUrl(), barTU);
QVERIFY(!envFile->needsUpdate(&env));
env.setTranslationUnitUrl(oldTU);
QVERIFY(envFile->needsUpdate(&env));
// update it again
envFile->setEnvironment(env);
QVERIFY(!envFile->needsUpdate(&env));
lastEnv = env;
// now compare against a lower quality environment
// in such a case, we do not want to trigger an update
env.setQuality(ClangParsingEnvironment::Unknown);
env.setTranslationUnitUrl(barTU);
QVERIFY(!envFile->needsUpdate(&env));
// even when the environment changes
env.addIncludes(Path::List() << Path(QStringLiteral("/lalalala")));
QVERIFY(!envFile->needsUpdate(&env));
indexed = top->indexed();
}
DUChain::self()->storeToDisk();
{
DUChainWriteLocker lock;
QVERIFY(!DUChain::self()->isInMemory(indexed.index()));
QVERIFY(indexed.data());
QVERIFY(DUChain::self()->environmentFileForDocument(indexed));
auto envFile = QExplicitlySharedDataPointer(
dynamic_cast(DUChain::self()->environmentFileForDocument(indexed).data()));
QVERIFY(envFile);
QCOMPARE(envFile->features(), features);
QVERIFY(envFile->featuresSatisfied(features));
QVERIFY(!envFile->needsUpdate(&lastEnv));
DUChain::self()->removeDocumentChain(indexed.data());
}
}
void TestDUChain::testActiveDocumentHasASTAttached()
{
const TopDUContext::Features features = TopDUContext::AllDeclarationsContextsAndUses;
IndexedTopDUContext indexed;
ClangParsingEnvironment lastEnv;
{
TestFile file(QStringLiteral("int main() {}\n"), QStringLiteral("cpp"));
auto astFeatures = static_cast(features | TopDUContext::AST);
file.parse(astFeatures);
file.setKeepDUChainData(true);
QVERIFY(file.waitForParsed());
DUChainWriteLocker lock;
auto top = file.topContext();
QVERIFY(top);
auto sessionData = ParseSessionData::Ptr(dynamic_cast(top->ast().data()));
lock.unlock();
ParseSession session(sessionData);
lock.lock();
QVERIFY(session.data());
QVERIFY(top);
QVERIFY(top->ast());
indexed = top->indexed();
}
DUChain::self()->storeToDisk();
{
DUChainWriteLocker lock;
QVERIFY(!DUChain::self()->isInMemory(indexed.index()));
QVERIFY(indexed.data());
}
QUrl url;
{
DUChainReadLocker lock;
auto ctx = indexed.data();
QVERIFY(ctx);
QVERIFY(!ctx->ast());
url = ctx->url().toUrl();
}
QVERIFY(!QFileInfo::exists(url.toLocalFile()));
QFile file(url.toLocalFile());
file.open(QIODevice::WriteOnly);
Q_ASSERT(file.isOpen());
auto document = ICore::self()->documentController()->openDocument(url);
QVERIFY(document);
ICore::self()->documentController()->activateDocument(document);
QApplication::processEvents();
ICore::self()->languageController()->backgroundParser()->parseDocuments();
QThread::sleep(1);
document->close(KDevelop::IDocument::Discard);
{
DUChainReadLocker lock;
auto ctx = indexed.data();
QVERIFY(ctx);
QVERIFY(ctx->ast());
}
DUChainWriteLocker lock;
DUChain::self()->removeDocumentChain(indexed.data());
}
void TestDUChain::testActiveDocumentsGetBestPriority()
{
// note: this test would make more sense in kdevplatform, but we don't have a language plugin available there
// (required for background parsing)
// TODO: Create a fake-language plugin in kdevplatform for testing purposes, use that.
TestFile file1(QStringLiteral("int main() {}\n"), QStringLiteral("cpp"));
TestFile file2(QStringLiteral("int main() {}\n"), QStringLiteral("cpp"));
TestFile file3(QStringLiteral("int main() {}\n"), QStringLiteral("cpp"));
DUChain::self()->storeToDisk();
auto backgroundParser = ICore::self()->languageController()->backgroundParser();
QVERIFY(!backgroundParser->isQueued(file1.url()));
auto documentController = ICore::self()->documentController();
// open first document (no activation)
auto doc = documentController->openDocument(file1.url().toUrl(), KTextEditor::Range::invalid(), {IDocumentController::DoNotActivate});
QVERIFY(doc);
QVERIFY(backgroundParser->isQueued(file1.url()));
QCOMPARE(backgroundParser->priorityForDocument(file1.url()), (int)BackgroundParser::NormalPriority);
// open second document, activate
doc = documentController->openDocument(file2.url().toUrl());
QVERIFY(doc);
QVERIFY(backgroundParser->isQueued(file2.url()));
QCOMPARE(backgroundParser->priorityForDocument(file2.url()), (int)BackgroundParser::BestPriority);
// open third document, activate, too
doc = documentController->openDocument(file3.url().toUrl());
QVERIFY(doc);
QVERIFY(backgroundParser->isQueued(file3.url()));
QCOMPARE(backgroundParser->priorityForDocument(file3.url()), (int)BackgroundParser::BestPriority);
}
void TestDUChain::testSystemIncludes()
{
ClangParsingEnvironment env;
Path::List projectIncludes = {
Path("/projects/1"),
Path("/projects/1/sub"),
Path("/projects/2"),
Path("/projects/2/sub")
};
env.addIncludes(projectIncludes);
auto includes = env.includes();
// no project paths set, so everything is considered a system include
QCOMPARE(includes.system, projectIncludes);
QVERIFY(includes.project.isEmpty());
Path::List systemIncludes = {
Path("/sys"),
Path("/sys/sub")
};
env.addIncludes(systemIncludes);
includes = env.includes();
QCOMPARE(includes.system, projectIncludes + systemIncludes);
QVERIFY(includes.project.isEmpty());
Path::List projects = {
Path("/projects/1"),
Path("/projects/2")
};
env.setProjectPaths(projects);
// now the list should be properly separated
QCOMPARE(env.projectPaths(), projects);
includes = env.includes();
QCOMPARE(includes.system, systemIncludes);
QCOMPARE(includes.project, projectIncludes);
}
void TestDUChain::benchDUChainBuilder()
{
QBENCHMARK_ONCE {
TestFile file(
"#include \n"
"#include