Commit e47c5e98 authored by Kevin Funk's avatar Kevin Funk
Browse files

Merge remote-tracking branch 'origin/5.0'

Non-trivial merge.

Skipped merging the following changes due to :
- ba4a7221
  Fix GDB unit tests for 5.0 branch
  Problem: Same patch for master already got applied
- 16bd7996
  Turn off gdb disable-randomization when testing
  Problem: No testing mode (m_testing variable) anymore?
    (didn't compile, please re-apply)

@Peifeng: Please double-check master

CCMAIL: 7437103@gmail.com
parents f6965687 78b9a078
......@@ -34,7 +34,7 @@ include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
set(QT_MIN_VERSION "5.4.0")
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Widgets Concurrent Quick QuickWidgets WebKitWidgets Script Test)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Widgets Concurrent Quick QuickWidgets WebKitWidgets Test)
set(KF5_DEP_VERSION "5.15.0") # we need KCrash::initialize
find_package(KF5 ${KF5_DEP_VERSION} REQUIRED COMPONENTS
Config
......@@ -145,6 +145,6 @@ install(EXPORT KDevelopTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" NAMESPAC
# 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 ${SHARE_INSTALL_PREFIX}/appdata/)
install(FILES org.kde.kdevelop.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
......@@ -45,7 +45,6 @@
#include <QFileInfo>
#include <QDir>
#include <QProcess>
#include <QResource>
#include <QSessionManager>
#include <QTextStream>
#include <QDBusInterface>
......@@ -235,12 +234,12 @@ static qint64 getRunningSessionPid()
return KDevelop::SessionController::sessionRunInfo(sessionUuid).holderPid;
}
static QString findSessionId(const QString& session)
static QString findSessionId(const SessionInfos& availableSessionInfos, const QString& session)
{
//If there is a session and a project with the same name, always open the session
//regardless of the order encountered
QString projectAsSession;
foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos())
foreach(const KDevelop::SessionInfo& si, availableSessionInfos)
{
if ( session == si.name || session == si.uuid.toString() ) {
return si.uuid.toString();
......@@ -263,18 +262,6 @@ static QString findSessionId(const QString& session)
return projectAsSession;
}
static void tryLoadIconResources()
{
const QString breezeIcons = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("icons/breeze/breeze-icons.rcc"));
if (!breezeIcons.isEmpty() && QFile::exists(breezeIcons)) {
qCDebug(APP) << "Loading icons rcc:" << breezeIcons;
// prepend /icons to the root to comply with KIcon* machinery
QResource::registerResource(breezeIcons, QStringLiteral("/icons/breeze"));
QIcon::setThemeSearchPaths(QStringList() << QStringLiteral(":/icons"));
}
}
static qint64 findSessionPid(const QString &sessionId)
{
KDevelop::SessionRunInfo sessionInfo = KDevelop::SessionController::sessionRunInfo( sessionId );
......@@ -414,8 +401,6 @@ int main( int argc, char *argv[] )
KCrash::initialize();
tryLoadIconResources();
Kdelibs4ConfigMigrator migrator(QStringLiteral("kdevelop"));
migrator.setConfigFiles({QStringLiteral("kdeveloprc")});
migrator.setUiFiles({QStringLiteral("kdevelopui.rc")});
......@@ -489,6 +474,8 @@ int main( int argc, char *argv[] )
initialFiles.append(UrlInfo(file));
}
const auto availableSessionInfos = KDevelop::SessionController::availableSessionInfos();
if (!initialFiles.isEmpty() && !parser.isSet("new-session")) {
#if KDEVELOP_SINGLE_APP
if (app.isRunning()) {
......@@ -500,7 +487,7 @@ int main( int argc, char *argv[] )
#else
qint64 pid = -1;
if (parser.isSet("open-session")) {
const QString session = findSessionId(parser.value("open-session"));
const QString session = findSessionId(availableSessionInfos, parser.value("open-session"));
if (session.isEmpty()) {
return 1;
} else if (KDevelop::SessionController::isSessionRunning(session)) {
......@@ -520,7 +507,7 @@ int main( int argc, char *argv[] )
QString session;
uint nRunningSessions = 0;
foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos())
foreach(const KDevelop::SessionInfo& si, availableSessionInfos)
if(KDevelop::SessionController::isSessionRunning(si.uuid.toString()))
++nRunningSessions;
......@@ -530,7 +517,7 @@ int main( int argc, char *argv[] )
{
QTextStream qerr(stderr);
SessionInfos candidates;
foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos())
foreach(const KDevelop::SessionInfo& si, availableSessionInfos)
if( (!si.name.isEmpty() || !si.projects.isEmpty() || parser.isSet("pid")) &&
(!parser.isSet("pid") || KDevelop::SessionController::isSessionRunning(si.uuid.toString())))
candidates << si;
......@@ -579,7 +566,7 @@ int main( int argc, char *argv[] )
} else if ( parser.isSet("new-session") )
{
session = parser.value("new-session");
foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos())
foreach(const KDevelop::SessionInfo& si, availableSessionInfos)
{
if ( session == si.name ) {
QTextStream qerr(stderr);
......@@ -589,14 +576,14 @@ int main( int argc, char *argv[] )
}
// session doesn't exist, we can create it
} else if ( parser.isSet("open-session") ) {
session = findSessionId(parser.value("open-session"));
session = findSessionId(availableSessionInfos, parser.value("open-session"));
if (session.isEmpty()) {
return 1;
}
} else if ( parser.isSet("remove-session") )
{
session = parser.value("remove-session");
auto si = findSessionInList(KDevelop::SessionController::availableSessionInfos(), session);
auto si = findSessionInList(availableSessionInfos, session);
if (!si) {
QTextStream qerr(stderr);
qerr << endl << i18n("No session with the name %1 exists.", session) << endl;
......@@ -618,12 +605,11 @@ int main( int argc, char *argv[] )
if(parser.isSet("pid")) {
if (session.isEmpty())
{ // just pick the first running session
foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos())
foreach(const KDevelop::SessionInfo& si, availableSessionInfos)
if(KDevelop::SessionController::isSessionRunning(si.uuid.toString()))
session = si.uuid.toString();
}
SessionInfos sessions = KDevelop::SessionController::availableSessionInfos();
const KDevelop::SessionInfo* sessionData = findSessionInList( sessions, session );
const KDevelop::SessionInfo* sessionData = findSessionInList(availableSessionInfos, session);
if( !sessionData ) {
qCritical() << "session not given or does not exist";
......
......@@ -29,7 +29,7 @@
#=============================================================================
set(KNOWN_VERSIONS 3.9 3.8 3.7 3.6 3.5)
set(KNOWN_VERSIONS 4.0 3.9 3.8 3.7 3.6 3.5)
foreach(version ${KNOWN_VERSIONS})
if (LLVM_DIR OR (DEFINED Clang_FIND_VERSION AND Clang_FIND_VERSION VERSION_GREATER version))
......
......@@ -89,6 +89,8 @@ GdbDebugger *DebugSession::createDebugger() const
}
void DebugSession::initializeDebugger()
connect(gdb, &GDB::debuggerInternalOutput, this,
&DebugSession::gdbInternalOutput);
{
//addCommand(new GDBCommand(GDBMI::EnableTimings, "yes"));
......@@ -120,6 +122,11 @@ void DebugSession::initializeDebugger()
addCommand(MI::NonMI, "source " + fileName);
}
if (m_testing) {
// GDB can't disable ASLR on CI server.
queueCmd(new GDBCommand(GDBMI::GdbSet, "disable-randomization off"));
}
qCDebug(DEBUGGERGDB) << "Initialized GDB";
}
......
......@@ -82,6 +82,7 @@ protected:
private Q_SLOTS:
void handleVersion(const QStringList& s);
void handleFileExecAndSymbols(const MI::ResultRecord& r);
void gdbInternalOutput (const QString& output);
private:
friend class GdbTest;
......
......@@ -36,6 +36,10 @@ public:
bool start(KConfigGroup& config, const QStringList& extraArguments = {}) override;
/** Reports debugger interal output, including stderr output from debugger
and the 'log' MI channel */
void debuggerInternalOutput(const QString& s);
};
} // end of namespace GDB
......
......@@ -21,6 +21,8 @@
*/
#include "gdbframestackmodel.h"
#include <algorithm>
#include "debugsession.h"
......
......@@ -57,6 +57,7 @@ using KDevelop::AutoTestShell;
namespace KDevMI { namespace GDB {
QUrl findExecutable(const QString& name)
{
QFileInfo info(qApp->applicationDirPath() + "/unittests/" + name);
Q_ASSERT(info.exists());
......
......@@ -191,7 +191,9 @@ ClangParseJob::ClangParseJob(const IndexedString& url, ILanguageSupport* languag
foreach(auto document, ICore::self()->documentController()->openDocuments()) {
auto textDocument = document->textDocument();
if (!textDocument || !textDocument->isModified() || !textDocument->url().isLocalFile()
// TODO: Introduce a cache so we don't have to re-read all the open documents
// which were not changed since the last run
if (!textDocument || !textDocument->url().isLocalFile()
|| !DocumentFinderHelpers::mimeTypesList().contains(textDocument->mimeType()))
{
continue;
......
......@@ -299,7 +299,7 @@ CXChildVisitResult declVisitor(CXCursor cursor, CXCursor parent, CXClientData d)
DUChainReadLocker lock;
top = DUChain::self()->chainForDocument(ClangString(clang_getFileName(file)).toIndexed());
}
DeclarationPointer declaration = ClangHelpers::findDeclaration(clang_getCursorLocation(cursor), top);
DeclarationPointer declaration = ClangHelpers::findDeclaration(clang_getCursorLocation(cursor), QualifiedIdentifier(), top);
data->prototypes->append(FuncImplementInfo{kind == CXCursor_Constructor, kind == CXCursor_Destructor,
data->templatePrefix, returnType, rest, declaration});
......
......@@ -237,7 +237,7 @@ public:
QWidget* createExpandingWidget(const CodeCompletionModel* /*model*/) const override
{
return new ClangNavigationWidget(m_declaration);
return new ClangNavigationWidget(m_declaration, KDevelop::AbstractNavigationWidget::EmbeddableWidget);
}
int matchQuality() const
......
......@@ -75,6 +75,7 @@ QString AdaptSignatureAction::toolTip() const
void AdaptSignatureAction::execute()
{
Q_ASSERT(!DUChain::lock()->currentThreadHasReadLock() && !DUChain::lock()->currentThreadHasWriteLock());
DUChainReadLocker lock;
IndexedString url = m_otherSideTopContext->url();
lock.unlock();
......@@ -110,6 +111,7 @@ void AdaptSignatureAction::execute()
}
DocumentChange changeParameters(functionContext->url(), parameterRange, QString(), newText);
lock.unlock();
changeParameters.m_ignoreOldText = true;
changes.addChange(changeParameters);
changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
......
......@@ -30,7 +30,8 @@ using namespace KDevelop;
template<>
QWidget* ClangTopDUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext,
const QString& htmlPrefix, const QString& htmlSuffix) const
const QString& htmlPrefix, const QString& htmlSuffix,
KDevelop::AbstractNavigationWidget::DisplayHints hints) const
{
if (!decl) {
const QUrl u = url().toUrl();
......@@ -40,20 +41,21 @@ QWidget* ClangTopDUContext::createNavigationWidget(Declaration* decl, TopDUConte
item.isDirectory = false;
item.basePath = u.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash);
return new ClangNavigationWidget(item, TopDUContextPointer(topContext ? topContext : this->topContext()), htmlPrefix, htmlSuffix);
return new ClangNavigationWidget(item, TopDUContextPointer(topContext ? topContext : this->topContext()), htmlPrefix, htmlSuffix, hints);
}
return new ClangNavigationWidget(DeclarationPointer(decl));
return new ClangNavigationWidget(DeclarationPointer(decl), hints);
}
template<>
QWidget* ClangNormalDUContext::createNavigationWidget(Declaration* decl, TopDUContext* /*topContext*/,
const QString& /*htmlPrefix*/, const QString& /*htmlSuffix*/) const
const QString& /*htmlPrefix*/, const QString& /*htmlSuffix*/,
KDevelop::AbstractNavigationWidget::DisplayHints hints) const
{
if (!decl) {
clangDebug() << "no declaration, not returning navigationwidget";
return 0;
}
return new ClangNavigationWidget(DeclarationPointer(decl));
return new ClangNavigationWidget(DeclarationPointer(decl), hints);
}
DUCHAIN_DEFINE_TYPE_WITH_DATA(ClangNormalDUContext, DUContextData)
......
......@@ -40,7 +40,8 @@ public:
}
virtual QWidget* createNavigationWidget(KDevelop::Declaration* decl = 0, KDevelop::TopDUContext* topContext = 0,
const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()) const override;
const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString(),
KDevelop::AbstractNavigationWidget::DisplayHints hints = KDevelop::AbstractNavigationWidget::NoHints) const override;
enum {
Identity = IdentityT
......
......@@ -193,7 +193,7 @@ ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& im
return context;
}
DeclarationPointer ClangHelpers::findDeclaration(CXSourceLocation location, const ReferencedTopDUContext& top)
DeclarationPointer ClangHelpers::findDeclaration(CXSourceLocation location, QualifiedIdentifier id, const ReferencedTopDUContext& top)
{
if (!top) {
// may happen for cyclic includes
......@@ -202,6 +202,24 @@ DeclarationPointer ClangHelpers::findDeclaration(CXSourceLocation location, cons
auto cursor = CursorInRevision(ClangLocation(location));
DUChainReadLocker lock;
QList<Declaration*> decls;
if (!id.isEmpty())
{
decls = top->findDeclarations(id);
foreach (Declaration* decl, decls)
{
if (decl->range().contains(cursor) ||
(decl->range().isEmpty() && decl->range().start == cursor))
{
return DeclarationPointer(decl);
}
}
}
// there was no match based on the IDs, try the classical
// range based search (very slow)
Q_ASSERT(top);
if (DUContext *local = top->findContextAt(cursor)) {
if (local->owner() && local->owner()->range().contains(cursor)) {
......@@ -221,7 +239,22 @@ DeclarationPointer ClangHelpers::findDeclaration(CXCursor cursor, const IncludeF
return {};
}
return findDeclaration(location, includes.value(file));
// build a qualified identifier by following the chain of semantic parents
QList<Identifier> ids;
CXCursor currentCursor = cursor;
while (currentCursor.kind != CXCursor_TranslationUnit &&
currentCursor.kind != CXCursor_InvalidFile)
{
ids << Identifier(ClangString(clang_getCursorSpelling(currentCursor)).toString());
currentCursor = clang_getCursorSemanticParent(currentCursor);
}
QualifiedIdentifier qid;
for (int i = ids.size()-1; i >= 0; --i)
{
qid.push(ids[i]);
}
return findDeclaration(location, qid, includes.value(file));
}
DeclarationPointer ClangHelpers::findDeclaration(CXType type, const IncludeFileContexts& includes)
......
......@@ -45,7 +45,7 @@ using IncludeFileContexts = QHash<CXFile, KDevelop::ReferencedTopDUContext>;
namespace ClangHelpers {
KDevelop::DeclarationPointer findDeclaration(CXSourceLocation cursor, const KDevelop::ReferencedTopDUContext& top);
KDevelop::DeclarationPointer findDeclaration(CXSourceLocation cursor, KDevelop::QualifiedIdentifier id, const KDevelop::ReferencedTopDUContext& top);
KDevelop::DeclarationPointer findDeclaration(CXCursor cursor, const IncludeFileContexts& includes);
KDevelop::DeclarationPointer findDeclaration(CXType type, const IncludeFileContexts& includes);
......
......@@ -29,6 +29,8 @@
#include <util/clangtypes.h>
#include <util/clangdebug.h>
#include <language/backgroundparser/urlparselock.h>
#include <language/duchain/duchainlock.h>
#include <language/duchain/duchain.h>
#include <clang-c/Index.h>
......@@ -94,6 +96,34 @@ IndexedString ClangIndex::translationUnitForUrl(const IndexedString& url)
return tu.value();
}
}
// if no explicit pin data is available, follow back the duchain import chain
{
KDevelop::DUChainReadLocker lock;
TopDUContext* top = DUChain::self()->chainForDocument(url);
if (top) {
TopDUContext* tuTop = top;
QSet<TopDUContext*> visited;
while(true) {
visited.insert(tuTop);
TopDUContext* next = NULL;
auto importers = tuTop->indexedImporters();
foreach(IndexedDUContext ctx, importers) {
if (ctx.data()) {
next = ctx.data()->topContext();
break;
}
}
if (!next || visited.contains(next)) {
break;
}
tuTop = next;
}
if (tuTop != top) {
return tuTop->url();
}
}
}
// otherwise, fallback to a simple buddy search for headers
if (ClangHelpers::isHeader(url.str())) {
foreach(const QUrl& buddy, DocumentFinderHelpers::getPotentialBuddies(url.toUrl(), false)) {
......
......@@ -78,12 +78,16 @@ CXChildVisitResult visitCursor(CXCursor cursor, CXCursor /*parent*/, CXClientDat
(*data->out) << "| display: \"" << displayName << "\" ";
}
ClangRange range(clang_getCursorExtent(cursor));
KTextEditor::Range simpleRange = range.toRange();
auto cursorExtent = ClangRange(clang_getCursorExtent(cursor)).toRange();
ClangString fileName(clang_getFileName(file));
(*data->out) << "| loc: " << fileName << '@' << '['
<< '(' << simpleRange.start().line()+1 << ',' << simpleRange.start().column()+1 << "),"
<< '(' << simpleRange.end().line()+1 << ',' << simpleRange.end().column()+1 << ")] ";
<< '(' << cursorExtent.start().line()+1 << ',' << cursorExtent.start().column()+1 << "),"
<< '(' << cursorExtent.end().line()+1 << ',' << cursorExtent.end().column()+1 << ")] ";
auto spellingNameRange = ClangRange(clang_Cursor_getSpellingNameRange(cursor, 0, 0)).toRange();
(*data->out) << "| sp-name-range: ["
<< '(' << spellingNameRange.start().line()+1 << ',' << spellingNameRange.start().column()+1 << "),"
<< '(' << spellingNameRange.end().line()+1 << ',' << spellingNameRange.end().column()+1 << ")] ";
if (clang_isDeclaration(kind)) {
(*data->out) << "| isDecl";
......
......@@ -83,9 +83,9 @@ QString MacroNavigationContext::html(bool shorten)
modifyHtml() += QStringLiteral(" "); //The action name _must_ stay "show_uses", since that is also used from outside
makeLink(i18n("Show uses"), QStringLiteral("show_uses"), NavigationAction(m_macro.dynamicCast<Declaration>(), NavigationAction::NavigateUses));
auto code = m_macro->definition().str().replace(QStringLiteral("\n"), QStringLiteral("<br/>"));
auto code = m_macro->definition().str();
modifyHtml() += QLatin1String("<p>") + i18n("Body: ");
modifyHtml() += QLatin1String("<tt>") + code + QLatin1String("</tt>");
modifyHtml() += QLatin1String("<tt>") + code.toHtmlEscaped().replace(QStringLiteral("\n"), QStringLiteral("<br/>")) + QLatin1String("</tt>");
modifyHtml() += QLatin1String("</p>");
modifyHtml() += fontSizeSuffix(shorten) + QLatin1String("</p></body></html>");
......
......@@ -84,9 +84,10 @@ bool IncludeNavigationContext::filterDeclaration(Declaration* decl)
&& !(declId.startsWith(QLatin1String("__")) || (declId.startsWith(QLatin1Char('_')) && declId.length() > 1 && declId[1].isUpper()) );
}
ClangNavigationWidget::ClangNavigationWidget(const DeclarationPointer& declaration)
ClangNavigationWidget::ClangNavigationWidget(const DeclarationPointer& declaration, KDevelop::AbstractNavigationWidget::DisplayHints hints)
: AbstractNavigationWidget()
{
setDisplayHints(hints);
if (auto macro = declaration.dynamicCast<MacroDefinition>()) {
initBrowser(200);
......@@ -102,8 +103,11 @@ ClangNavigationWidget::ClangNavigationWidget(const DeclarationPointer& declarati
}
}
ClangNavigationWidget::ClangNavigationWidget(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation)
ClangNavigationWidget::ClangNavigationWidget(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation,
KDevelop::AbstractNavigationWidget::DisplayHints hints)
: AbstractNavigationWidget()
{
setDisplayHints(hints);
initBrowser(400);
//The first context is registered so it is kept alive by the shared-pointer mechanism
......@@ -112,8 +116,11 @@ ClangNavigationWidget::ClangNavigationWidget(const MacroDefinition::Ptr& macro,
}
ClangNavigationWidget::ClangNavigationWidget(const IncludeItem& includeItem, KDevelop::TopDUContextPointer topContext,
const QString& htmlPrefix, const QString& htmlSuffix)
const QString& htmlPrefix, const QString& htmlSuffix,
KDevelop::AbstractNavigationWidget::DisplayHints hints)
: AbstractNavigationWidget()
{
setDisplayHints(hints);
m_topContext = topContext;
initBrowser(200);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment