Commit 512e39aa authored by Peifeng Yu's avatar Peifeng Yu
Browse files

Merge remote-tracking branch 'origin/master' into peifeng/lldb-plugin

parents 77ef011a 9cb910b9
......@@ -29,11 +29,19 @@
#=============================================================================
set(KNOWN_VERSIONS 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))
break()
endif ()
if (${Clang_FIND_REQUIRED})
find_package(LLVM ${Clang_FIND_VERSION} REQUIRED)
find_package(LLVM ${version} REQUIRED)
else ()
find_package(LLVM ${Clang_FIND_VERSION})
find_package(LLVM ${version})
endif ()
endforeach()
set(CLANG_FOUND FALSE)
......
......@@ -139,7 +139,7 @@ void MIDebugger::readyReadStandardOutput()
void MIDebugger::readyReadStandardError()
{
process_->setReadChannel(QProcess::StandardError);
emit internalCommandOutput(QString::fromUtf8(process_->readAll()));
emit debuggerInternalOutput(QString::fromUtf8(process_->readAll()));
}
void MIDebugger::processLine(const QByteArray& line)
......@@ -266,17 +266,16 @@ void MIDebugger::processLine(const QByteArray& line)
if (s.subkind == MI::StreamRecord::Target) {
emit applicationOutput(s.message);
} else {
} else if (s.subkind == MI::StreamRecord::Console) {
if (currentCmd_ && currentCmd_->isUserCommand())
emit userCommandOutput(s.message);
else if (s.subkind == MI::StreamRecord::Console) {
emit applicationOutput(s.message);
} else {
else
emit internalCommandOutput(s.message);
}
if (currentCmd_)
currentCmd_->newOutput(s.message);
} else {
emit debuggerInternalOutput(s.message);
}
emit streamRecord(s);
......
......@@ -118,10 +118,13 @@ Q_SIGNALS:
void userCommandOutput(const QString& s);
/** Reports output of a command issued internally
by KDevelop. At the moment, stderr output from
debugger and the 'log' MI channel will be also routed here. */
by KDevelop. */
void internalCommandOutput(const QString& s);
/** Reports debugger interal output, including stderr output from debugger
and the 'log' MI channel */
void debuggerInternalOutput(const QString& s);
protected Q_SLOTS:
void readyReadStandardOutput();
void readyReadStandardError();
......
......@@ -43,6 +43,7 @@
#include <KParts/MainWindow>
#include <QFileInfo>
#include <QRegularExpression>
using namespace KDevMI;
using namespace KDevelop;
......@@ -58,6 +59,11 @@ MIDebugJob::MIDebugJob(MIDebuggerPlugin* p, ILaunchConfiguration* launchcfg,
m_session = p->createSession();
connect(m_session, &MIDebugSession::inferiorStdoutLines, this, &MIDebugJob::stdoutReceived);
connect(m_session, &MIDebugSession::inferiorStderrLines, this, &MIDebugJob::stderrReceived);
connect(m_session, &MIDebugSession::debuggerInternalCommandOutput,
this, [this](const QString &output){
this->stdoutReceived(output.split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts));
});
connect(m_session, &MIDebugSession::finished, this, &MIDebugJob::done);
if (launchcfg->project()) {
......
......@@ -119,11 +119,11 @@ QMap<QString, MIVariable*> & MIDebugSession::variableMapping()
return m_allVariables;
}
MIVariable* MIDebugSession::findVariableByVarobjName(const QString &varobjName)
MIVariable* MIDebugSession::findVariableByVarobjName(const QString &varobjName) const
{
if (m_allVariables.count(varobjName) == 0)
return nullptr;
return m_allVariables[varobjName];
return m_allVariables.value(varobjName);
}
void MIDebugSession::markAllVariableDead()
......@@ -170,6 +170,7 @@ bool MIDebugSession::startDebugger(ILaunchConfiguration *cfg)
});
connect(m_debugger, &MIDebugger::userCommandOutput, this, &MIDebugSession::debuggerUserCommandOutput);
connect(m_debugger, &MIDebugger::internalCommandOutput, this, &MIDebugSession::debuggerInternalCommandOutput);
connect(m_debugger, &MIDebugger::debuggerInternalOutput, this, &MIDebugSession::debuggerInternalOutput);
// state signals
connect(m_debugger, &MIDebugger::programStopped, this, &MIDebugSession::inferiorStopped);
......
......@@ -86,6 +86,11 @@ Q_SIGNALS:
*/
void debuggerInternalCommandOutput(const QString &output);
/**
* Emits when received internal output from debugger
*/
void debuggerInternalOutput(const QString &output);
/**
* Emits when received standard output from inferior's tty
*/
......@@ -215,7 +220,7 @@ public:
MI::CommandFlags flags = 0);
QMap<QString, MIVariable*> & variableMapping();
MIVariable* findVariableByVarobjName(const QString &varobjName);
MIVariable* findVariableByVarobjName(const QString &varobjName) const;
void markAllVariableDead();
protected Q_SLOTS:
......
......@@ -136,6 +136,9 @@ void GDBOutputWidget::currentSessionChanged(KDevelop::IDebugSession* s)
this, &GDBOutputWidget::slotInternalCommandStdout);
connect(session, &DebugSession::debuggerUserCommandOutput,
this, &GDBOutputWidget::slotUserCommandStdout);
// debugger internal output, treat it as an internal command output
connect(session, &DebugSession::debuggerInternalOutput,
this, &GDBOutputWidget::slotInternalCommandStdout);
connect(session, &DebugSession::debuggerStateChanged,
this, &GDBOutputWidget::slotStateChanged);
......
......@@ -267,14 +267,18 @@ private:
} while(0)
#define COMPARE_DATA(index, expected) \
compareData((index), (expected), __FILE__, __LINE__)
do { if(!compareData((index), (expected), __FILE__, __LINE__)) return; } while (0)
void compareData(QModelIndex index, QString expected, const char *file, int line)
bool compareData(QModelIndex index, QString expected, const char *file, int line)
{
QString s = index.model()->data(index, Qt::DisplayRole).toString();
if (s != expected) {
QFAIL(qPrintable(QString("'%0' didn't match expected '%1' in %2:%3").arg(s).arg(expected).arg(file).arg(line)));
QTest::qFail(qPrintable(QString("'%0' didn't match expected '%1' in %2:%3")
.arg(s).arg(expected).arg(file).arg(line)),
file, line);
return false;
}
return true;
}
static const QString debugeeFileName = findSourceFile("debugee.cpp");
......@@ -2039,29 +2043,31 @@ void GdbTest::testPathWithSpace()
bool GdbTest::waitForState(DebugSession *session, DebugSession::DebuggerState state,
const char *file, int line, bool waitForIdle)
{
QPointer<DebugSession> s(session); //session can get deleted in DebugController
QPointer<MIDebugSession> s(session); //session can get deleted in DebugController
QTime stopWatch;
stopWatch.start();
while (s.data()->state() != state || (waitForIdle && s->debuggerStateIsOn(s_dbgBusy))) {
// legacy behavior for tests that implicitly may require waiting for idle,
// but which were written before waitForIdle was added
waitForIdle = waitForIdle || state != MIDebugSession::EndedState;
while (s && (s->state() != state || (waitForIdle && s->debuggerStateIsOn(s_dbgBusy)))) {
if (stopWatch.elapsed() > 5000) {
qWarning() << "current state" << s.data()->state() << "waiting for" << state;
qWarning() << "current state" << s->state() << "waiting for" << state;
QTest::qFail(qPrintable(QString("Timeout before reaching state %0").arg(state)),
file, line);
file, line);
return false;
}
QTest::qWait(20);
if (!s) {
if (state == DebugSession::EndedState)
break;
QTest::qFail(qPrintable(QString("Session ended before reaching state %0").arg(state)),
file, line);
return false;
}
}
if (!waitForIdle && state != DebugSession::EndedState) {
// legacy behavior for tests that implicitly may require waiting for idle,
// but which were written before waitForIdle was added
QTest::qWait(100);
// NOTE: don't wait anymore after leaving the loop. Waiting re-enters event loop and
// may change session state.
if (!s && state != MIDebugSession::EndedState) {
QTest::qFail(qPrintable(QString("Session ended before reaching state %0").arg(state)),
file, line);
return false;
}
qDebug() << "Reached state " << state << " in " << file << ':' << line;
......
......@@ -56,13 +56,16 @@ void TestManPageModel::testDocumentation()
QVERIFY(spy.wait());
const QString description = documentation.description();
if (!description.isEmpty()) {
qDebug() << description;
// check that we've found the correct page by checking some references
QVERIFY(description.contains("dlclose"));
QVERIFY(description.contains("dlerror"));
QVERIFY(description.contains("dlopen"));
QVERIFY(!description.isEmpty());
qDebug() << "Description:" << description;
if (description.isEmpty() || description.contains("No man page matching to dlmopen found")) {
QSKIP("This test requires installed man pages for dlmopen & friends");
}
// check that we've found the correct page by checking some references
QVERIFY(description.contains("dlclose"));
QVERIFY(description.contains("dlerror"));
QVERIFY(description.contains("dlopen"));
}
QTEST_MAIN(TestManPageModel)
......
......@@ -140,7 +140,7 @@ ProjectFileItem* findProjectFileItem(const IndexedString& url, bool* hasBuildSys
}
if (file && file->project()) {
if (auto bsm = file->project()->buildSystemManager()) {
*hasBuildSystemInfo = bsm->hasIncludesOrDefines(file);
*hasBuildSystemInfo = bsm->hasBuildInfo(file);
}
}
return file;
......@@ -165,10 +165,12 @@ ClangParseJob::ClangParseJob(const IndexedString& url, ILanguageSupport* languag
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()));
}
......@@ -230,6 +232,7 @@ void ClangParseJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread*
}
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));
}
......
......@@ -78,8 +78,6 @@ Signature getDeclarationSignature(const Declaration *functionDecl, const DUConte
AdaptSignatureAssistant::AdaptSignatureAssistant(ILanguageSupport* supportedLanguage)
: StaticAssistant(supportedLanguage)
{
connect(DUChain::self(), &DUChain::updateReady,
this, &AdaptSignatureAssistant::updateReady);
}
QString AdaptSignatureAssistant::title() const
......@@ -98,21 +96,21 @@ void AdaptSignatureAssistant::reset()
m_otherSideTopContext = {};
m_otherSideContext = {};
m_oldSignature = {};
m_document = {};
m_document = nullptr;
m_view.clear();
}
void AdaptSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEditor::Range& invocationRange, const QString& removedText)
void AdaptSignatureAssistant::textChanged(KTextEditor::Document* doc, const KTextEditor::Range& invocationRange, const QString& removedText)
{
reset();
m_view = view;
m_document = doc;
m_lastEditPosition = invocationRange.end();
KTextEditor::Range sigAssistRange = invocationRange;
if (!removedText.isEmpty()) {
sigAssistRange.setRange(sigAssistRange.start(), sigAssistRange.start());
}
m_document = view->document()->url();
DUChainReadLocker lock(DUChain::lock(), 300);
if (!lock.locked()) {
......@@ -120,7 +118,7 @@ void AdaptSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEd
return;
}
KTextEditor::Range simpleInvocationRange = KTextEditor::Range(sigAssistRange);
Declaration* funDecl = getDeclarationAtCursor(simpleInvocationRange.start(), m_document);
Declaration* funDecl = getDeclarationAtCursor(simpleInvocationRange.start(), m_document->url());
if (!funDecl || !funDecl->type<FunctionType>()) {
clangDebug() << "No function at cursor";
return;
......@@ -164,7 +162,7 @@ void AdaptSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEd
bool AdaptSignatureAssistant::isUseful() const
{
return !m_declarationName.isEmpty() && m_otherSideId.isValid();
return !m_declarationName.isEmpty() && m_otherSideId.isValid() && !actions().isEmpty();
}
bool AdaptSignatureAssistant::getSignatureChanges(const Signature& newSignature, QList<int>& oldPositions) const
......@@ -254,18 +252,18 @@ QList<RenameAction*> AdaptSignatureAssistant::getRenameActions(const Signature &
return renameActions;
}
void AdaptSignatureAssistant::updateReady(const KDevelop::IndexedString& document, const KDevelop::ReferencedTopDUContext& /*context*/)
void AdaptSignatureAssistant::updateReady(const KDevelop::IndexedString& document, const KDevelop::ReferencedTopDUContext& top)
{
if (document.toUrl() != m_document || !m_view) {
if (!top || !m_document || document.toUrl() != m_document->url() || top->url() != IndexedString(m_document->url())) {
return;
}
clearActions();
DUChainReadLocker lock;
Declaration *functionDecl = getDeclarationAtCursor(KTextEditor::Cursor(m_view.data()->cursorPosition()), m_document);
Declaration *functionDecl = getDeclarationAtCursor(m_lastEditPosition, m_document->url());
if (!functionDecl || functionDecl->identifier() != m_declarationName) {
clangDebug() << "No function found at" << m_document << m_view.data()->cursorPosition();
clangDebug() << "No function found at" << m_document->url() << m_lastEditPosition;
return;
}
DUContext *functionCtxt = DUChainUtils::getFunctionContext(functionDecl);
......@@ -307,4 +305,16 @@ void AdaptSignatureAssistant::updateReady(const KDevelop::IndexedString& documen
emit actionsChanged();
}
KTextEditor::Range AdaptSignatureAssistant::displayRange() const
{
if (!m_document) {
return {};
}
auto s = m_lastEditPosition;
KTextEditor::Range ran = {s.line(), 0, s.line(), m_document->lineLength(s.line())};
qDebug() << "display range:" << ran;
return ran;
}
#include "moc_adaptsignatureassistant.cpp"
......@@ -42,8 +42,9 @@ public:
AdaptSignatureAssistant(KDevelop::ILanguageSupport* supportedLanguage);
QString title() const override;
void textChanged(KTextEditor::View* view, const KTextEditor::Range& invocationRange, const QString& removedText = QString()) override;
void textChanged(KTextEditor::Document* doc, const KTextEditor::Range& invocationRange, const QString& removedText = QString()) override;
bool isUseful() const override;
KTextEditor::Range displayRange() const override;
private:
///Compare @param newSignature to m_oldSignature and put differences in oldPositions
......@@ -61,13 +62,14 @@ private:
KDevelop::DeclarationId m_otherSideId;
KDevelop::ReferencedTopDUContext m_otherSideTopContext;
KDevelop::DUContextPointer m_otherSideContext;
KTextEditor::Cursor m_lastEditPosition;
//old signature of the _other_side
Signature m_oldSignature;
QUrl m_document;
QPointer<KTextEditor::Document> m_document;
QPointer<KTextEditor::View> m_view;
private slots:
void updateReady(const KDevelop::IndexedString& document, const KDevelop::ReferencedTopDUContext& context);
void updateReady(const KDevelop::IndexedString& document, const KDevelop::ReferencedTopDUContext& context) override;
void reset();
};
......
......@@ -996,9 +996,9 @@ void Visitor::setDeclData(CXCursor cursor, ClassMemberDeclaration *decl) const
const QString offsetStr = bitOffset ? i18nc("%1: bytes, %2: bits", "%1, %2", byteOffsetStr, bitOffsetStr) : byteOffsetStr;
decl->setComment(decl->comment()
+ i18n("<br/>offset in parent: %1<br/>"
"size: %2 Bytes<br/>"
"aligned to: %3 Bytes", offsetStr, sizeOf, alignedTo).toUtf8());
+ i18n("<p>offset in parent: %1; "
"size: %2 Bytes; "
"aligned to: %3 Bytes</p>", offsetStr, sizeOf, alignedTo).toUtf8());
}
}
#endif
......@@ -1036,8 +1036,8 @@ void Visitor::setDeclData(CXCursor cursor, ClassDeclaration* decl) const
auto alignOf = clang_Type_getAlignOf(type);
if (sizeOf >= 0 && alignOf >= 0) {
decl->setComment(decl->comment()
+ i18n("<br/>size: %1 Bytes<br/>"
"aligned to: %2 Bytes", sizeOf, alignOf).toUtf8());
+ i18n("<p>size: %1 Bytes; "
"aligned to: %2 Bytes</p>", sizeOf, alignOf).toUtf8());
}
}
}
......
......@@ -43,14 +43,20 @@ void ClangParsingEnvironment::addIncludes(const Path::List& includes)
m_includes += includes;
}
ClangParsingEnvironment::IncludePaths ClangParsingEnvironment::includes() const
void ClangParsingEnvironment::addFrameworkDirectories(const KDevelop::Path::List& frameworkDirectories)
{
m_frameworkDirectories += frameworkDirectories;
}
template <typename PathType>
static PathType appendPaths(const KDevelop::Path::List &paths, const KDevelop::Path::List &projectPaths)
{
IncludePaths ret;
ret.project.reserve(m_includes.size());
ret.system.reserve(m_includes.size());
foreach (const auto& path, m_includes) {
PathType ret;
ret.project.reserve(paths.size());
ret.system.reserve(paths.size());
foreach (const auto& path, paths) {
bool inProject = false;
foreach (const auto& project, m_projectPaths) {
foreach (const auto& project, projectPaths) {
if (project.isParentOf(path) || project == path) {
inProject = true;
break;
......@@ -65,6 +71,16 @@ ClangParsingEnvironment::IncludePaths ClangParsingEnvironment::includes() const
return ret;
}
ClangParsingEnvironment::IncludePaths ClangParsingEnvironment::includes() const
{
return appendPaths<IncludePaths>(m_includes, m_projectPaths);
}
ClangParsingEnvironment::FrameworkDirectories ClangParsingEnvironment::frameworkDirectories() const
{
return appendPaths<FrameworkDirectories>(m_frameworkDirectories, m_projectPaths);
}
void ClangParsingEnvironment::addDefines(const QHash<QString, QString>& defines)
{
for (auto it = defines.constBegin(); it != defines.constEnd(); ++it) {
......@@ -121,6 +137,11 @@ uint ClangParsingEnvironment::hash() const
hash << qHash(include);
}
hash << m_frameworkDirectories.size();
for (const auto& fwDir : m_frameworkDirectories) {
hash << qHash(fwDir);
}
hash << qHash(m_pchInclude);
hash << qHash(m_parserSettings.parserOptions);
return hash;
......@@ -130,6 +151,7 @@ bool ClangParsingEnvironment::operator==(const ClangParsingEnvironment& other) c
{
return m_defines == other.m_defines
&& m_includes == other.m_includes
&& m_frameworkDirectories == other.m_frameworkDirectories
&& m_pchInclude == other.m_pchInclude
&& m_quality == other.m_quality
&& m_tuUrl == other.m_tuUrl
......
......@@ -49,6 +49,11 @@ public:
*/
void addIncludes(const KDevelop::Path::List& includes);
/**
* Add the given list of @p framework-directories to this environment.
*/
void addFrameworkDirectories(const KDevelop::Path::List& frameworkDirectories);
struct IncludePaths
{
/// This list contains all include paths outside the known projects paths.
......@@ -61,6 +66,18 @@ public:
*/
IncludePaths includes() const;
struct FrameworkDirectories
{
/// This list contains all framework directories outside the known projects paths.
KDevelop::Path::List system;
/// This list contains all framework directories inside the known projects paths.
KDevelop::Path::List project;
};
/**
* Returns the list of framework directories, split into a list of system paths and project paths.
*/
FrameworkDirectories frameworkDirectories() const;
void addDefines(const QHash<QString, QString>& defines);
QMap<QString, QString> defines() const;
......@@ -101,6 +118,7 @@ public:
private:
KDevelop::Path::List m_projectPaths;
KDevelop::Path::List m_includes;
KDevelop::Path::List m_frameworkDirectories;
// NOTE: As elements in QHash stored in an unordered sequence, we're using QMap instead
QMap<QString, QString> m_defines;
KDevelop::Path m_pchInclude;
......
......@@ -38,68 +38,13 @@
using namespace KDevelop;
namespace {
KTextEditor::View* createDocAndView(const QString& data, KTextEditor::Document** docPtr)
{
if (data.isEmpty()) {
return 0;
}
KTextEditor::Document* doc = ICore::self()->partController()->editorPart()->createDocument(0);
*docPtr = doc;
doc->setText(data);
doc->setMode(QStringLiteral("C++"));
doc->setReadWrite(false);
KTextEditor::View* view = doc->createView(0);
view->setStatusBarEnabled(false);
if (KTextEditor::ConfigInterface* config = qobject_cast<KTextEditor::ConfigInterface*>(view)) {
config->setConfigValue(QStringLiteral("icon-bar"), false);
config->setConfigValue(QStringLiteral("folding-bar"), false);
config->setConfigValue(QStringLiteral("line-numbers"), false);
config->setConfigValue(QStringLiteral("dynamic-word-wrap"), true);
}
return view;
}
}
MacroNavigationContext::MacroNavigationContext(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation)
: m_macro(macro)
, m_preprocessed(nullptr)
, m_definition(nullptr)
, m_widget(new QWidget)
{
QVBoxLayout* layout = new QVBoxLayout(m_widget.data());
if (expansionLocation.isValid()) {
const QString preprocessedBody = retrievePreprocessedBody(expansionLocation);
KTextEditor::View* preprocessedView = createDocAndView(preprocessedBody, &m_preprocessed);
if (m_preprocessed) {
layout->addWidget(new QLabel(i18n("Preprocessed Body:")));
layout->addWidget(preprocessedView);
} else {
layout->addWidget(new QLabel(i18n("Preprocessed Body: (empty)")));
}
}
const QString definitionText = m_macro->definition().str();
KTextEditor::View* definitionView = createDocAndView(definitionText, &m_definition);
if (m_definition) {
layout->addWidget(new QLabel(i18n("Body:")));
layout->addWidget(definitionView);
} else {
layout->addWidget(new QLabel(i18n("Body: (empty)")));
}
m_widget->setLayout(layout);
}
MacroNavigationContext::~MacroNavigationContext()
{
delete m_preprocessed;
delete m_definition;
delete m_widget;
}
QString MacroNavigationContext::name() const
......@@ -107,11 +52,6 @@ QString MacroNavigationContext::name() const
return m_macro->identifier().toString();
}
QWidget* MacroNavigationContext::widget() const
{
return m_widget.data();