forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.8'
Change-Id: Ife02e25f89a601e066851cddf0e000ac9491fc35
This commit is contained in:
@@ -203,6 +203,8 @@ public:
|
||||
virtual bool check(bool enable = true);
|
||||
};
|
||||
|
||||
bool Derived2::
|
||||
|
||||
// performance-unnecessary-value-param
|
||||
void use(Base b)
|
||||
{
|
||||
|
@@ -2948,7 +2948,10 @@ class DumperBase:
|
||||
return self.detypedef().integer()
|
||||
elif self.type.code == TypeCodeBitfield:
|
||||
return self.lvalue
|
||||
unsigned = self.type.name.startswith('unsigned')
|
||||
# Could be something like 'short unsigned int'
|
||||
unsigned = self.type.name == 'unsigned' \
|
||||
or self.type.name.startswith('unsigned ') \
|
||||
or self.type.name.find(' unsigned ') != -1
|
||||
bitsize = self.type.bitsize()
|
||||
return self.extractInteger(bitsize, unsigned)
|
||||
|
||||
|
@@ -39,8 +39,9 @@ bool convertPosition(const QTextDocument *document, int pos, int *line, int *col
|
||||
(*column) = -1;
|
||||
return false;
|
||||
} else {
|
||||
// line and column are both 1-based
|
||||
(*line) = block.blockNumber() + 1;
|
||||
(*column) = pos - block.position();
|
||||
(*column) = pos - block.position() + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
||||
|
||||
{
|
||||
auto runConfig = runner->runControl()->runConfiguration();
|
||||
auto aspect = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
|
||||
auto aspect = runConfig->aspect<Debugger::DebuggerRunConfigurationAspect>();
|
||||
Core::Id runMode = runner->runMode();
|
||||
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
|
||||
m_useCppDebugger = debuggingMode && aspect->useCppDebugger();
|
||||
@@ -194,23 +194,23 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
||||
m_deviceSerialNumber = AndroidManager::deviceSerialNumber(target);
|
||||
m_apiLevel = AndroidManager::deviceApiLevel(target);
|
||||
|
||||
m_extraEnvVars = runConfig->extraAspect<EnvironmentAspect>()->environment();
|
||||
m_extraEnvVars = runConfig->aspect<EnvironmentAspect>()->environment();
|
||||
qCDebug(androidRunWorkerLog) << "Environment variables for the app"
|
||||
<< m_extraEnvVars.toStringList();
|
||||
|
||||
m_extraAppParams = runConfig->runnable().commandLineArguments;
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_AMSTARTARGS))
|
||||
if (auto aspect = runConfig->aspect(Constants::ANDROID_AMSTARTARGS))
|
||||
m_amStartExtraArgs = static_cast<BaseStringAspect *>(aspect)->value().split(' ');
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) {
|
||||
if (auto aspect = runConfig->aspect(Constants::ANDROID_PRESTARTSHELLCMDLIST)) {
|
||||
for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
for (const QString &shellCmd : runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList())
|
||||
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
|
||||
if (auto aspect = runConfig->extraAspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
|
||||
if (auto aspect = runConfig->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
|
||||
for (const QString &shellCmd : static_cast<BaseStringListAspect *>(aspect)->value())
|
||||
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ public:
|
||||
if (auto debuggable = dynamic_cast<DebuggableTestConfiguration *>(config))
|
||||
enableQuick = debuggable->mixedDebugging();
|
||||
|
||||
if (auto debugAspect = extraAspect<Debugger::DebuggerRunConfigurationAspect>()) {
|
||||
if (auto debugAspect = aspect<Debugger::DebuggerRunConfigurationAspect>()) {
|
||||
debugAspect->setUseQmlDebugger(enableQuick);
|
||||
ProjectExplorer::ProjectExplorerPlugin::instance()->updateRunActions();
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ const char *BareMetalCustomRunConfiguration::Id = "BareMetal";
|
||||
|
||||
bool BareMetalCustomRunConfiguration::isConfigured() const
|
||||
{
|
||||
return !extraAspect<ExecutableAspect>()->executable().isEmpty();
|
||||
return !aspect<ExecutableAspect>()->executable().isEmpty();
|
||||
}
|
||||
|
||||
RunConfiguration::ConfigurationState
|
||||
|
@@ -85,7 +85,7 @@ void BareMetalDebugSupport::start()
|
||||
{
|
||||
const auto rc = runControl()->runConfiguration();
|
||||
QTC_ASSERT(rc, reportFailure(); return);
|
||||
const auto exeAspect = rc->extraAspect<ExecutableAspect>();
|
||||
const auto exeAspect = rc->aspect<ExecutableAspect>();
|
||||
QTC_ASSERT(exeAspect, reportFailure(); return);
|
||||
|
||||
const QString bin = exeAspect->executable().toString();
|
||||
@@ -124,7 +124,7 @@ void BareMetalDebugSupport::start()
|
||||
|
||||
Runnable inferior;
|
||||
inferior.executable = bin;
|
||||
if (auto aspect = rc->extraAspect<ArgumentsAspect>())
|
||||
if (auto aspect = rc->aspect<ArgumentsAspect>())
|
||||
inferior.commandLineArguments = aspect->arguments(rc->macroExpander());
|
||||
setInferior(inferior);
|
||||
setSymbolFile(bin);
|
||||
|
@@ -63,7 +63,7 @@ BareMetalRunConfiguration::BareMetalRunConfiguration(Target *target, Core::Id id
|
||||
void BareMetalRunConfiguration::updateTargetInformation()
|
||||
{
|
||||
const BuildTargetInfo bti = target()->applicationTargets().buildTargetInfo(buildKey());
|
||||
extraAspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
emit enabledChanged();
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangcompletionchunkstotextconverter.h"
|
||||
#include "clangfixitoperation.h"
|
||||
#include "clangutils.h"
|
||||
|
||||
#include <cplusplus/Icons.h>
|
||||
#include <cplusplus/MatchingText.h>
|
||||
@@ -34,10 +35,13 @@
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
#include <texteditor/completionsettings.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/textutils.h>
|
||||
@@ -45,6 +49,7 @@
|
||||
|
||||
using namespace CPlusPlus;
|
||||
using namespace ClangBackEnd;
|
||||
using namespace TextEditor;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
@@ -73,7 +78,7 @@ bool ClangAssistProposalItem::implicitlyApplies() const
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString textUntilPreviousStatement(TextEditor::TextDocumentManipulatorInterface &manipulator,
|
||||
static QString textUntilPreviousStatement(TextDocumentManipulatorInterface &manipulator,
|
||||
int startPosition)
|
||||
{
|
||||
static const QString stopCharacters(";{}#");
|
||||
@@ -90,7 +95,7 @@ static QString textUntilPreviousStatement(TextEditor::TextDocumentManipulatorInt
|
||||
}
|
||||
|
||||
// 7.3.3: using typename(opt) nested-name-specifier unqualified-id ;
|
||||
static bool isAtUsingDeclaration(TextEditor::TextDocumentManipulatorInterface &manipulator,
|
||||
static bool isAtUsingDeclaration(TextDocumentManipulatorInterface &manipulator,
|
||||
int basePosition)
|
||||
{
|
||||
SimpleLexer lexer;
|
||||
@@ -105,7 +110,7 @@ static bool isAtUsingDeclaration(TextEditor::TextDocumentManipulatorInterface &m
|
||||
if (lastToken.kind() != T_COLON_COLON)
|
||||
return false;
|
||||
|
||||
return Utils::contains(tokens, [](const Token &token) {
|
||||
return ::Utils::contains(tokens, [](const Token &token) {
|
||||
return token.kind() == T_USING;
|
||||
});
|
||||
}
|
||||
@@ -135,17 +140,17 @@ static QString methodDefinitionParameters(const CodeCompletionChunks &chunks)
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface &manipulator,
|
||||
void ClangAssistProposalItem::apply(TextDocumentManipulatorInterface &manipulator,
|
||||
int basePosition) const
|
||||
{
|
||||
const CodeCompletion ccr = firstCodeCompletion();
|
||||
|
||||
if (!ccr.requiredFixIts.empty()) {
|
||||
// Important: Calculate shift before changing the document.
|
||||
basePosition += fixItsShift(manipulator);
|
||||
|
||||
ClangFixItOperation fixItOperation(Utf8String(), ccr.requiredFixIts);
|
||||
fixItOperation.perform();
|
||||
|
||||
const int shift = fixItsShift(manipulator);
|
||||
basePosition += shift;
|
||||
}
|
||||
|
||||
QString textToBeInserted = m_text;
|
||||
@@ -175,8 +180,8 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface
|
||||
|
||||
textToBeInserted = converter.text();
|
||||
} else if (!ccr.text.isEmpty()) {
|
||||
const TextEditor::CompletionSettings &completionSettings =
|
||||
TextEditor::TextEditorSettings::instance()->completionSettings();
|
||||
const CompletionSettings &completionSettings =
|
||||
TextEditorSettings::instance()->completionSettings();
|
||||
const bool autoInsertBrackets = completionSettings.m_autoInsertBrackets;
|
||||
|
||||
if (autoInsertBrackets &&
|
||||
@@ -193,9 +198,9 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface
|
||||
QTextCursor cursor = manipulator.textCursorAt(basePosition);
|
||||
|
||||
bool abandonParen = false;
|
||||
if (Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
|
||||
Utils::Text::moveToPrevChar(manipulator, cursor);
|
||||
Utils::Text::moveToPrevChar(manipulator, cursor);
|
||||
if (::Utils::Text::matchPreviousWord(manipulator, cursor, "&")) {
|
||||
::Utils::Text::moveToPrevChar(manipulator, cursor);
|
||||
::Utils::Text::moveToPrevChar(manipulator, cursor);
|
||||
const QChar prevChar = manipulator.characterAt(cursor.position());
|
||||
cursor.setPosition(basePosition);
|
||||
abandonParen = QString("(;,{}").contains(prevChar);
|
||||
@@ -206,7 +211,7 @@ void ClangAssistProposalItem::apply(TextEditor::TextDocumentManipulatorInterface
|
||||
if (!abandonParen && ccr.completionKind == CodeCompletion::FunctionDefinitionCompletionKind) {
|
||||
const CodeCompletionChunk resultType = ccr.chunks.first();
|
||||
QTC_ASSERT(resultType.kind == CodeCompletionChunk::ResultType, return;);
|
||||
if (Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
|
||||
if (::Utils::Text::matchPreviousWord(manipulator, cursor, resultType.text.toString())) {
|
||||
extraCharacters += methodDefinitionParameters(ccr.chunks);
|
||||
// To skip the next block.
|
||||
abandonParen = true;
|
||||
@@ -306,7 +311,7 @@ void ClangAssistProposalItem::setText(const QString &text)
|
||||
|
||||
QString ClangAssistProposalItem::text() const
|
||||
{
|
||||
return m_text + (requiresFixIts() ? fixItText() : QString());
|
||||
return m_text;
|
||||
}
|
||||
|
||||
const QVector<ClangBackEnd::FixItContainer> &ClangAssistProposalItem::firstCompletionFixIts() const
|
||||
@@ -314,39 +319,53 @@ const QVector<ClangBackEnd::FixItContainer> &ClangAssistProposalItem::firstCompl
|
||||
return firstCodeCompletion().requiredFixIts;
|
||||
}
|
||||
|
||||
// FIXME: Indicate required fix-it without adding extra text.
|
||||
std::pair<int, int> fixItPositionsRange(const FixItContainer &fixIt, const QTextCursor &cursor)
|
||||
{
|
||||
const QTextBlock startLine = cursor.document()->findBlockByNumber(fixIt.range.start.line - 1);
|
||||
const QTextBlock endLine = cursor.document()->findBlockByNumber(fixIt.range.end.line - 1);
|
||||
|
||||
const int fixItStartPos = ::Utils::Text::positionInText(
|
||||
cursor.document(),
|
||||
static_cast<int>(fixIt.range.start.line),
|
||||
Utils::cppEditorColumn(startLine, static_cast<int>(fixIt.range.start.column)));
|
||||
const int fixItEndPos = ::Utils::Text::positionInText(
|
||||
cursor.document(),
|
||||
static_cast<int>(fixIt.range.end.line),
|
||||
Utils::cppEditorColumn(endLine, static_cast<int>(fixIt.range.end.column)));
|
||||
return std::make_pair(fixItStartPos, fixItEndPos);
|
||||
}
|
||||
|
||||
static QString textReplacedByFixit(const FixItContainer &fixIt)
|
||||
{
|
||||
TextEditorWidget *textEditorWidget = TextEditorWidget::currentTextEditorWidget();
|
||||
if (!textEditorWidget)
|
||||
return QString();
|
||||
const std::pair<int, int> fixItPosRange = fixItPositionsRange(fixIt,
|
||||
textEditorWidget->textCursor());
|
||||
return textEditorWidget->textAt(fixItPosRange.first,
|
||||
fixItPosRange.second - fixItPosRange.first);
|
||||
}
|
||||
|
||||
QString ClangAssistProposalItem::fixItText() const
|
||||
{
|
||||
const FixItContainer &fixIt = firstCompletionFixIts().first();
|
||||
const SourceRangeContainer &range = fixIt.range;
|
||||
return QCoreApplication::translate("ClangCodeModel::ClangAssistProposalItem",
|
||||
" (requires to correct [%1:%2-%3:%4] to \"%5\")")
|
||||
.arg(range.start.line)
|
||||
.arg(range.start.column)
|
||||
.arg(range.end.line)
|
||||
.arg(range.end.column)
|
||||
"Requires to correct \"%1\" to \"%2\"")
|
||||
.arg(textReplacedByFixit(fixIt))
|
||||
.arg(fixIt.text.toString());
|
||||
}
|
||||
|
||||
int ClangAssistProposalItem::fixItsShift(
|
||||
const TextEditor::TextDocumentManipulatorInterface &manipulator) const
|
||||
int ClangAssistProposalItem::fixItsShift(const TextDocumentManipulatorInterface &manipulator) const
|
||||
{
|
||||
const QVector<ClangBackEnd::FixItContainer> &requiredFixIts = firstCompletionFixIts();
|
||||
if (requiredFixIts.empty())
|
||||
return 0;
|
||||
|
||||
int shift = 0;
|
||||
QTextCursor cursor = manipulator.textCursorAt(0);
|
||||
const QTextCursor cursor = manipulator.textCursorAt(0);
|
||||
for (const FixItContainer &fixIt : requiredFixIts) {
|
||||
const int fixItStartPos = Utils::Text::positionInText(
|
||||
cursor.document(),
|
||||
static_cast<int>(fixIt.range.start.line),
|
||||
static_cast<int>(fixIt.range.start.column));
|
||||
const int fixItEndPos = Utils::Text::positionInText(
|
||||
cursor.document(),
|
||||
static_cast<int>(fixIt.range.end.line),
|
||||
static_cast<int>(fixIt.range.end.column));
|
||||
shift += fixIt.text.toString().length() - (fixItEndPos - fixItStartPos);
|
||||
const std::pair<int, int> fixItPosRange = fixItPositionsRange(fixIt, cursor);
|
||||
shift += fixIt.text.toString().length() - (fixItPosRange.second - fixItPosRange.first);
|
||||
}
|
||||
return shift;
|
||||
}
|
||||
@@ -425,10 +444,14 @@ QString ClangAssistProposalItem::detail() const
|
||||
detail += "<br>";
|
||||
detail += CompletionChunksToTextConverter::convertToToolTipWithHtml(
|
||||
codeCompletion.chunks, codeCompletion.completionKind);
|
||||
|
||||
if (!codeCompletion.briefComment.isEmpty())
|
||||
detail += "<br>" + codeCompletion.briefComment.toString();
|
||||
}
|
||||
|
||||
if (requiresFixIts())
|
||||
detail += "<br><br><b>" + fixItText() + "</b>";
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
|
@@ -56,11 +56,7 @@ void ClangAssistProposalModel::sort(const QString &/*prefix*/)
|
||||
return static_cast<int>(first->prefixMatch())
|
||||
< static_cast<int>(second->prefixMatch());
|
||||
}
|
||||
if (first->requiresFixIts() != second->requiresFixIts())
|
||||
return first->requiresFixIts() < second->requiresFixIts();
|
||||
return (first->order() > 0
|
||||
&& (first->order() < second->order()
|
||||
|| (first->order() == second->order() && first->text() < second->text())));
|
||||
return false;
|
||||
};
|
||||
|
||||
// Keep the order for the items with the same priority and name.
|
||||
|
@@ -51,8 +51,9 @@
|
||||
#include <clangsupport/filecontainer.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/mimetypes/mimedatabase.h>
|
||||
#include <utils/optional.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDirIterator>
|
||||
@@ -76,20 +77,18 @@ static void addAssistProposalItem(QList<AssistProposalItemInterface *> &items,
|
||||
item->appendCodeCompletion(codeCompletion);
|
||||
}
|
||||
|
||||
// Add the next CXXMethod or CXXConstructor which is the overload for another existing item.
|
||||
static void addFunctionOverloadAssistProposalItem(QList<AssistProposalItemInterface *> &items,
|
||||
AssistProposalItemInterface *sameItem,
|
||||
const ClangCompletionAssistInterface *interface,
|
||||
const CodeCompletion &codeCompletion,
|
||||
const QString &name)
|
||||
{
|
||||
ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first();
|
||||
auto *item = static_cast<ClangAssistProposalItem *>(sameItem);
|
||||
item->setHasOverloadsWithParameters(true);
|
||||
if (resultType.kind != ClangBackEnd::CodeCompletionChunk::ResultType) {
|
||||
// It's the constructor.
|
||||
if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind) {
|
||||
// It's the constructor, currently constructor definitions do not lead here.
|
||||
// CLANG-UPGRADE-CHECK: Can we get here with constructor definition?
|
||||
if (!item->firstCodeCompletion().hasParameters)
|
||||
item->removeFirstCodeCompletion();
|
||||
item->appendCodeCompletion(codeCompletion);
|
||||
return;
|
||||
}
|
||||
@@ -98,15 +97,27 @@ static void addFunctionOverloadAssistProposalItem(QList<AssistProposalItemInterf
|
||||
cursor.setPosition(interface->position());
|
||||
cursor.movePosition(QTextCursor::StartOfWord);
|
||||
|
||||
const ClangBackEnd::CodeCompletionChunk resultType = codeCompletion.chunks.first();
|
||||
if (::Utils::Text::matchPreviousWord(*interface->textEditorWidget(),
|
||||
cursor,
|
||||
resultType.text.toString())) {
|
||||
// Function definition completion - do not merge completions together.
|
||||
addAssistProposalItem(items, codeCompletion, name);
|
||||
} else {
|
||||
item->appendCodeCompletion(codeCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if they are both CXXMethod or CXXConstructor.
|
||||
static bool isTheSameFunctionOverload(const CodeCompletion &completion,
|
||||
const QString &name,
|
||||
ClangAssistProposalItem *lastItem)
|
||||
{
|
||||
return completion.hasParameters
|
||||
&& completion.completionKind == lastItem->firstCodeCompletion().completionKind
|
||||
&& lastItem->text() == name;
|
||||
}
|
||||
|
||||
static QList<AssistProposalItemInterface *> toAssistProposalItems(
|
||||
const CodeCompletions &completions,
|
||||
const ClangCompletionAssistInterface *interface)
|
||||
@@ -117,8 +128,9 @@ static QList<AssistProposalItemInterface *> toAssistProposalItems(
|
||||
QList<AssistProposalItemInterface *> items;
|
||||
items.reserve(completions.size());
|
||||
for (const CodeCompletion &codeCompletion : completions) {
|
||||
if (codeCompletion.text.isEmpty()) // TODO: Make isValid()?
|
||||
continue;
|
||||
if (codeCompletion.text.isEmpty())
|
||||
continue; // It's an OverloadCandidate which has text but no typedText.
|
||||
|
||||
if (signalCompletion && codeCompletion.completionKind != CodeCompletion::SignalCompletionKind)
|
||||
continue;
|
||||
if (slotCompletion && codeCompletion.completionKind != CodeCompletion::SlotCompletionKind)
|
||||
@@ -128,36 +140,18 @@ static QList<AssistProposalItemInterface *> toAssistProposalItems(
|
||||
? CompletionChunksToTextConverter::convertToName(codeCompletion.chunks)
|
||||
: codeCompletion.text.toString();
|
||||
|
||||
if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind
|
||||
|| codeCompletion.completionKind == CodeCompletion::ClassCompletionKind) {
|
||||
auto samePreviousConstructor
|
||||
= std::find_if(items.begin(),
|
||||
items.end(),
|
||||
[&](const AssistProposalItemInterface *item) {
|
||||
return item->text() == name
|
||||
&& static_cast<const ClangAssistProposalItem *>(item)->firstCodeCompletion()
|
||||
.completionKind == codeCompletion.completionKind;
|
||||
});
|
||||
if (samePreviousConstructor == items.end()) {
|
||||
if (items.empty()) {
|
||||
addAssistProposalItem(items, codeCompletion, name);
|
||||
} else if (codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind){
|
||||
addFunctionOverloadAssistProposalItem(items, *samePreviousConstructor, interface,
|
||||
codeCompletion, name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!items.empty() && items.last()->text() == name) {
|
||||
if ((codeCompletion.completionKind == CodeCompletion::FunctionCompletionKind
|
||||
|| codeCompletion.completionKind == CodeCompletion::FunctionDefinitionCompletionKind)
|
||||
&& codeCompletion.hasParameters) {
|
||||
} else {
|
||||
auto *lastItem = static_cast<ClangAssistProposalItem *>(items.last());
|
||||
if (isTheSameFunctionOverload(codeCompletion, name, lastItem)) {
|
||||
addFunctionOverloadAssistProposalItem(items, items.back(), interface,
|
||||
codeCompletion, name);
|
||||
}
|
||||
} else {
|
||||
addAssistProposalItem(items, codeCompletion, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
@@ -187,48 +181,14 @@ IAssistProposal *ClangCompletionAssistProcessor::perform(const AssistInterface *
|
||||
return startCompletionHelper(); // == 0 if results are calculated asynchronously
|
||||
}
|
||||
|
||||
static CodeCompletions filterFunctionSignatures(const CodeCompletions &completions)
|
||||
{
|
||||
return ::Utils::filtered(completions, [](const CodeCompletion &completion) {
|
||||
return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind;
|
||||
});
|
||||
}
|
||||
|
||||
static CodeCompletions filterConstructorSignatures(Utf8String textBefore,
|
||||
const CodeCompletions &completions)
|
||||
{
|
||||
const int prevStatementEnd = textBefore.lastIndexOf(";");
|
||||
if (prevStatementEnd != -1)
|
||||
textBefore = textBefore.mid(prevStatementEnd + 1);
|
||||
|
||||
return ::Utils::filtered(completions, [&textBefore](const CodeCompletion &completion) {
|
||||
if (completion.completionKind != CodeCompletion::ConstructorCompletionKind)
|
||||
return false;
|
||||
const Utf8String type = completion.chunks.at(0).text;
|
||||
return textBefore.indexOf(type) != -1;
|
||||
});
|
||||
}
|
||||
|
||||
void ClangCompletionAssistProcessor::handleAvailableCompletions(
|
||||
const CodeCompletions &completions)
|
||||
void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeCompletions &completions)
|
||||
{
|
||||
QTC_CHECK(m_completions.isEmpty());
|
||||
|
||||
if (m_sentRequestType == FunctionHintCompletion) {
|
||||
CodeCompletions functionSignatures;
|
||||
if (m_completionOperator == T_LPAREN) {
|
||||
functionSignatures = filterFunctionSignatures(completions);
|
||||
} else {
|
||||
const QTextBlock block = m_interface->textDocument()->findBlock(
|
||||
m_interface->position());
|
||||
const QString textBefore = block.text().left(
|
||||
m_interface->position() - block.position());
|
||||
|
||||
functionSignatures = filterConstructorSignatures(textBefore, completions);
|
||||
}
|
||||
|
||||
if (!functionSignatures.isEmpty()) {
|
||||
setAsyncProposalAvailable(createFunctionHintProposal(functionSignatures));
|
||||
const CodeCompletion &firstCompletion = completions.front();
|
||||
if (firstCompletion.completionKind == CodeCompletion::FunctionOverloadCompletionKind) {
|
||||
setAsyncProposalAvailable(createFunctionHintProposal(completions));
|
||||
return;
|
||||
}
|
||||
// else: Proceed with a normal completion in case:
|
||||
|
@@ -155,8 +155,18 @@ int clangColumn(const QTextBlock &line, int cppEditorColumn)
|
||||
// (2) The return value is the column in Clang which is the utf8 byte offset from the beginning
|
||||
// of the line.
|
||||
// Here we convert column from (1) to (2).
|
||||
// '+ 1' is for 1-based columns
|
||||
return line.text().left(cppEditorColumn).toUtf8().size() + 1;
|
||||
// '- 1' and '+ 1' are because of 1-based columns
|
||||
return line.text().left(cppEditorColumn - 1).toUtf8().size() + 1;
|
||||
}
|
||||
|
||||
int cppEditorColumn(const QTextBlock &line, int clangColumn)
|
||||
{
|
||||
// (1) clangColumn is the column in Clang which is the utf8 byte offset from the beginning
|
||||
// of the line.
|
||||
// (2) The return value is the actual column shown by CppEditor.
|
||||
// Here we convert column from (1) to (2).
|
||||
// '- 1' and '+ 1' are because of 1-based columns
|
||||
return QString::fromUtf8(line.text().toUtf8().left(clangColumn - 1)).size() + 1;
|
||||
}
|
||||
|
||||
::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token)
|
||||
|
@@ -57,7 +57,8 @@ CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath);
|
||||
CppTools::ProjectPart::Ptr projectPartForFileBasedOnProcessor(const QString &filePath);
|
||||
bool isProjectPartLoaded(const CppTools::ProjectPart::Ptr projectPart);
|
||||
QString projectPartIdForFile(const QString &filePath);
|
||||
int clangColumn(const QTextBlock &lineText, int cppEditorColumn);
|
||||
int clangColumn(const QTextBlock &line, int cppEditorColumn);
|
||||
int cppEditorColumn(const QTextBlock &line, int clangColumn);
|
||||
|
||||
QString diagnosticCategoryPrefixRemoved(const QString &text);
|
||||
|
||||
|
@@ -98,11 +98,11 @@ QString CMakeRunConfiguration::disabledReason() const
|
||||
void CMakeRunConfiguration::updateTargetInformation()
|
||||
{
|
||||
BuildTargetInfo bti = target()->applicationTargets().buildTargetInfo(buildKey());
|
||||
extraAspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
extraAspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.workingDirectory);
|
||||
extraAspect<LocalEnvironmentAspect>()->buildEnvironmentHasChanged();
|
||||
aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(bti.workingDirectory);
|
||||
aspect<LocalEnvironmentAspect>()->buildEnvironmentHasChanged();
|
||||
|
||||
auto terminalAspect = extraAspect<TerminalAspect>();
|
||||
auto terminalAspect = aspect<TerminalAspect>();
|
||||
if (!terminalAspect->isUserSet())
|
||||
terminalAspect->setUseTerminal(bti.usesTerminal);
|
||||
}
|
||||
|
@@ -69,10 +69,7 @@ bool TreeScanner::asyncScanForFiles(const Utils::FileName &directory)
|
||||
m_scanFuture = fi->future();
|
||||
m_futureWatcher.setFuture(m_scanFuture);
|
||||
|
||||
if (m_versionControls.isEmpty())
|
||||
m_versionControls = Core::VcsManager::versionControls();
|
||||
|
||||
Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory, m_versionControls); });
|
||||
Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory); });
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -150,14 +147,12 @@ FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Uti
|
||||
}
|
||||
|
||||
void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& directory,
|
||||
const FileFilter &filter, const FileTypeFactory &factory,
|
||||
QList<Core::IVersionControl *> &versionControls)
|
||||
const FileFilter &filter, const FileTypeFactory &factory)
|
||||
{
|
||||
std::unique_ptr<FutureInterface> fip(fi);
|
||||
fip->reportStarted();
|
||||
|
||||
Result nodes
|
||||
= FileNode::scanForFilesWithVersionControls(
|
||||
Result nodes = FileNode::scanForFiles(
|
||||
directory,
|
||||
[&filter, &factory](const Utils::FileName &fn) -> FileNode * {
|
||||
const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString());
|
||||
@@ -172,7 +167,7 @@ void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& direc
|
||||
type = factory(mimeType, fn);
|
||||
|
||||
return new FileNode(fn, type, false);
|
||||
}, versionControls, fip.get());
|
||||
}, fip.get());
|
||||
|
||||
Utils::sort(nodes, ProjectExplorer::Node::sortByPath);
|
||||
|
||||
|
@@ -88,8 +88,7 @@ signals:
|
||||
|
||||
private:
|
||||
static void scanForFiles(FutureInterface *fi, const Utils::FileName &directory,
|
||||
const FileFilter &filter, const FileTypeFactory &factory,
|
||||
QList<Core::IVersionControl *> &versionControls);
|
||||
const FileFilter &filter, const FileTypeFactory &factory);
|
||||
|
||||
private:
|
||||
FileFilter m_filter;
|
||||
@@ -97,7 +96,6 @@ private:
|
||||
|
||||
FutureWatcher m_futureWatcher;
|
||||
Future m_scanFuture;
|
||||
QList<Core::IVersionControl *> m_versionControls;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -1682,9 +1682,8 @@ namespace {
|
||||
class ConvertToCamelCaseOp: public CppQuickFixOperation
|
||||
{
|
||||
public:
|
||||
ConvertToCamelCaseOp(const CppQuickFixInterface &interface, int priority,
|
||||
const QString &newName)
|
||||
: CppQuickFixOperation(interface, priority)
|
||||
ConvertToCamelCaseOp(const CppQuickFixInterface &interface, const QString &newName)
|
||||
: CppQuickFixOperation(interface, -1)
|
||||
, m_name(newName)
|
||||
{
|
||||
setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Camel Case"));
|
||||
@@ -1744,7 +1743,7 @@ void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOp
|
||||
return;
|
||||
for (int i = 1; i < newName.length() - 1; ++i) {
|
||||
if (ConvertToCamelCaseOp::isConvertibleUnderscore(newName, i)) {
|
||||
result << new ConvertToCamelCaseOp(interface, path.size() - 1, newName);
|
||||
result << new ConvertToCamelCaseOp(interface, newName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3303,10 +3302,18 @@ public:
|
||||
|
||||
// Write class qualification, if any.
|
||||
if (matchingClass) {
|
||||
const Name *name = rewriteName(matchingClass->name(), &env, control);
|
||||
Class *current = matchingClass;
|
||||
QVector<const Name *> classes{matchingClass->name()};
|
||||
while (current->enclosingScope()->asClass()) {
|
||||
current = current->enclosingScope()->asClass();
|
||||
classes.prepend(current->name());
|
||||
}
|
||||
for (const Name *n : classes) {
|
||||
const Name *name = rewriteName(n, &env, control);
|
||||
funcDef.append(printer.prettyName(name));
|
||||
funcDef.append(QLatin1String("::"));
|
||||
}
|
||||
}
|
||||
|
||||
// Write the extracted function itself and its call.
|
||||
funcDef.append(funcName);
|
||||
|
@@ -906,9 +906,9 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit, bool allowTer
|
||||
|
||||
if (runConfig) {
|
||||
m_runParameters.displayName = runConfig->displayName();
|
||||
if (auto symbolsAspect = runConfig->extraAspect<SymbolFileAspect>())
|
||||
if (auto symbolsAspect = runConfig->aspect<SymbolFileAspect>())
|
||||
m_runParameters.symbolFile = symbolsAspect->value();
|
||||
if (auto terminalAspect = runConfig->extraAspect<TerminalAspect>())
|
||||
if (auto terminalAspect = runConfig->aspect<TerminalAspect>())
|
||||
m_runParameters.useTerminal = terminalAspect->useTerminal();
|
||||
}
|
||||
|
||||
@@ -924,7 +924,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, Kit *kit, bool allowTer
|
||||
if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(kit))
|
||||
m_runParameters.qtPackageSourceLocation = qtVersion->qtPackageSourcePath().toString();
|
||||
|
||||
if (auto aspect = runConfig ? runConfig->extraAspect<DebuggerRunConfigurationAspect>() : nullptr) {
|
||||
if (auto aspect = runConfig ? runConfig->aspect<DebuggerRunConfigurationAspect>() : nullptr) {
|
||||
if (!aspect->useCppDebugger())
|
||||
m_runParameters.cppEngineType = NoEngineType;
|
||||
m_runParameters.isQmlDebugging = aspect->useQmlDebugger();
|
||||
|
@@ -3385,8 +3385,14 @@ GitRemote::GitRemote(const QString &url)
|
||||
|
||||
// Check for local remotes (refer to the root or relative path)
|
||||
// On Windows, local paths typically starts with <drive>:
|
||||
auto startsWithWindowsDrive = [](const QString &url) {
|
||||
if (!HostOsInfo::isWindowsHost() || url.size() < 2)
|
||||
return false;
|
||||
const QChar drive = url.at(0).toLower();
|
||||
return drive >= 'a' && drive <= 'z' && url.at(1) == ':';
|
||||
};
|
||||
if (url.startsWith("file://") || url.startsWith('/') || url.startsWith('.')
|
||||
|| (HostOsInfo::isWindowsHost() && url[1] == ':')) {
|
||||
|| startsWithWindowsDrive(url)) {
|
||||
protocol = "file";
|
||||
path = QDir::fromNativeSeparators(url.startsWith("file://") ? url.mid(7) : url);
|
||||
isValid = QDir(path).exists() || QDir(path + ".git").exists();
|
||||
|
@@ -82,7 +82,10 @@ bool GitVersionControl::isVcsFileOrDirectory(const Utils::FileName &fileName) co
|
||||
return false;
|
||||
if (fileName.toFileInfo().isDir())
|
||||
return true;
|
||||
return QFile(fileName.toString()).readLine().startsWith("gitdir: ");
|
||||
QFile file(fileName.toString());
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
return false;
|
||||
return file.read(8) == "gitdir: ";
|
||||
}
|
||||
|
||||
bool GitVersionControl::isConfigured() const
|
||||
|
@@ -84,11 +84,6 @@ struct HelpManagerPrivate
|
||||
static HelpManager *m_instance = nullptr;
|
||||
static HelpManagerPrivate *d = nullptr;
|
||||
|
||||
static const char linksForKeyQuery[] = "SELECT d.Title, f.Name, e.Name, "
|
||||
"d.Name, a.Anchor FROM IndexTable a, FileNameTable d, FolderTable e, "
|
||||
"NamespaceTable f WHERE a.FileId=d.FileId AND d.FolderId=e.Id AND "
|
||||
"a.NamespaceId=f.Id AND a.Name='%1'";
|
||||
|
||||
// -- DbCleaner
|
||||
|
||||
struct DbCleaner
|
||||
@@ -227,66 +222,29 @@ QSet<QString> HelpManager::userDocumentationPaths()
|
||||
return d->m_userRegisteredFiles;
|
||||
}
|
||||
|
||||
static QUrl buildQUrl(const QString &ns, const QString &folder,
|
||||
const QString &relFileName, const QString &anchor)
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme(QLatin1String("qthelp"));
|
||||
url.setAuthority(ns);
|
||||
url.setPath(QLatin1Char('/') + folder + QLatin1Char('/') + relFileName);
|
||||
url.setFragment(anchor);
|
||||
return url;
|
||||
}
|
||||
|
||||
// This should go into Qt 4.8 once we start using it for Qt Creator
|
||||
QMap<QString, QUrl> HelpManager::linksForKeyword(const QString &key)
|
||||
{
|
||||
QMap<QString, QUrl> links;
|
||||
QTC_ASSERT(!d->m_needsSetup, return links);
|
||||
|
||||
const QLatin1String sqlite("QSQLITE");
|
||||
const QLatin1String name("HelpManager::linksForKeyword");
|
||||
|
||||
DbCleaner cleaner(name);
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
|
||||
if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
|
||||
const QStringList ®isteredDocs = d->m_helpEngine->registeredDocumentations();
|
||||
for (const QString &nameSpace : registeredDocs) {
|
||||
db.setDatabaseName(d->m_helpEngine->documentationFileName(nameSpace));
|
||||
if (db.open()) {
|
||||
QSqlQuery query = QSqlQuery(db);
|
||||
query.setForwardOnly(true);
|
||||
query.exec(QString::fromLatin1(linksForKeyQuery).arg(key));
|
||||
while (query.next()) {
|
||||
QString title = query.value(0).toString();
|
||||
if (title.isEmpty()) // generate a title + corresponding path
|
||||
title = key + QLatin1String(" : ") + query.value(3).toString();
|
||||
links.insertMulti(title, buildQUrl(query.value(1).toString(),
|
||||
query.value(2).toString(), query.value(3).toString(),
|
||||
query.value(4).toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return links;
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->linksForKeyword(key);
|
||||
}
|
||||
|
||||
QMap<QString, QUrl> HelpManager::linksForIdentifier(const QString &id)
|
||||
{
|
||||
QMap<QString, QUrl> empty;
|
||||
QTC_ASSERT(!d->m_needsSetup, return empty);
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->linksForIdentifier(id);
|
||||
}
|
||||
|
||||
QUrl HelpManager::findFile(const QUrl &url)
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QUrl());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->findFile(url);
|
||||
}
|
||||
|
||||
QByteArray HelpManager::fileData(const QUrl &url)
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QByteArray());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->fileData(url);
|
||||
}
|
||||
|
||||
@@ -297,19 +255,19 @@ void HelpManager::handleHelpRequest(const QUrl &url, Core::HelpManager::HelpView
|
||||
|
||||
QStringList HelpManager::registeredNamespaces()
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QStringList());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->registeredDocumentations();
|
||||
}
|
||||
|
||||
QString HelpManager::namespaceFromFile(const QString &file)
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QString());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->namespaceName(file);
|
||||
}
|
||||
|
||||
QString HelpManager::fileFromNamespace(const QString &nameSpace)
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QString());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->documentationFileName(nameSpace);
|
||||
}
|
||||
|
||||
@@ -325,13 +283,13 @@ void HelpManager::setCustomValue(const QString &key, const QVariant &value)
|
||||
|
||||
QVariant HelpManager::customValue(const QString &key, const QVariant &value)
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return QVariant());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
return d->m_helpEngine->customValue(key, value);
|
||||
}
|
||||
|
||||
HelpManager::Filters HelpManager::filters()
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return Filters());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
|
||||
Filters filters;
|
||||
const QStringList &customFilters = d->m_helpEngine->customFilters();
|
||||
@@ -342,12 +300,12 @@ HelpManager::Filters HelpManager::filters()
|
||||
|
||||
HelpManager::Filters HelpManager::fixedFilters()
|
||||
{
|
||||
Filters fixedFilters;
|
||||
QTC_ASSERT(!d->m_needsSetup, return fixedFilters);
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
|
||||
const QLatin1String sqlite("QSQLITE");
|
||||
const QLatin1String name("HelpManager::fixedCustomFilters");
|
||||
|
||||
Filters fixedFilters;
|
||||
DbCleaner cleaner(name);
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase(sqlite, name);
|
||||
if (db.driver() && db.driver()->lastError().type() == QSqlError::NoError) {
|
||||
@@ -370,7 +328,7 @@ HelpManager::Filters HelpManager::fixedFilters()
|
||||
|
||||
HelpManager::Filters HelpManager::userDefinedFilters()
|
||||
{
|
||||
QTC_ASSERT(!d->m_needsSetup, return Filters());
|
||||
QTC_ASSERT(!d->m_needsSetup, return {});
|
||||
|
||||
Filters all = filters();
|
||||
const Filters &fixed = fixedFilters();
|
||||
|
@@ -139,7 +139,7 @@ void IosRunConfiguration::updateDisplayNames()
|
||||
setDefaultDisplayName(tr("Run on %1").arg(devName));
|
||||
setDisplayName(tr("Run %1 on %2").arg(applicationName()).arg(devName));
|
||||
|
||||
extraAspect<ExecutableAspect>()->setExecutable(localExecutable());
|
||||
aspect<ExecutableAspect>()->setExecutable(localExecutable());
|
||||
}
|
||||
|
||||
void IosRunConfiguration::updateEnabledState()
|
||||
|
@@ -100,7 +100,7 @@ IosRunner::IosRunner(RunControl *runControl)
|
||||
stopRunningRunControl(runControl);
|
||||
auto runConfig = qobject_cast<IosRunConfiguration *>(runControl->runConfiguration());
|
||||
m_bundleDir = runConfig->bundleDirectory().toString();
|
||||
m_arguments = runConfig->extraAspect<ArgumentsAspect>()->arguments(runConfig->macroExpander());
|
||||
m_arguments = runConfig->aspect<ArgumentsAspect>()->arguments(runConfig->macroExpander());
|
||||
m_device = DeviceKitInformation::device(runConfig->target()->kit());
|
||||
m_deviceType = runConfig->deviceType();
|
||||
}
|
||||
@@ -387,7 +387,7 @@ IosQmlProfilerSupport::IosQmlProfilerSupport(RunControl *runControl)
|
||||
Runnable runnable;
|
||||
runnable.executable = iosRunConfig->localExecutable().toUserOutput();
|
||||
runnable.commandLineArguments =
|
||||
iosRunConfig->extraAspect<ArgumentsAspect>()->arguments(iosRunConfig->macroExpander());
|
||||
iosRunConfig->aspect<ArgumentsAspect>()->arguments(iosRunConfig->macroExpander());
|
||||
runControl->setDisplayName(iosRunConfig->applicationName());
|
||||
runControl->setRunnable(runnable);
|
||||
|
||||
|
@@ -113,11 +113,9 @@ void NimProject::collectProjectFiles()
|
||||
m_lastProjectScan.start();
|
||||
QTC_ASSERT(!m_futureWatcher.future().isRunning(), return);
|
||||
FileName prjDir = projectDirectory();
|
||||
const QList<Core::IVersionControl *> versionControls = Core::VcsManager::versionControls();
|
||||
QFuture<QList<ProjectExplorer::FileNode *>> future = Utils::runAsync([prjDir, versionControls] {
|
||||
return FileNode::scanForFilesWithVersionControls(
|
||||
prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); },
|
||||
versionControls);
|
||||
QFuture<QList<ProjectExplorer::FileNode *>> future = Utils::runAsync([prjDir] {
|
||||
return FileNode::scanForFiles(
|
||||
prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); });
|
||||
});
|
||||
m_futureWatcher.setFuture(future);
|
||||
Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan");
|
||||
@@ -144,7 +142,7 @@ void NimProject::updateProject()
|
||||
m_files = transform<QList>(fileNodes, [](const std::unique_ptr<FileNode> &fn) {
|
||||
return fn->filePath().toString();
|
||||
});
|
||||
Utils::sort(m_files, [](const QString &a, const QString &b) { return a < b; });
|
||||
Utils::sort(m_files);
|
||||
|
||||
if (oldFiles == m_files)
|
||||
return;
|
||||
|
@@ -67,9 +67,9 @@ void NimRunConfiguration::updateConfiguration()
|
||||
QTC_ASSERT(buildConfiguration, return);
|
||||
setActiveBuildConfiguration(buildConfiguration);
|
||||
const QFileInfo outFileInfo = buildConfiguration->outFilePath().toFileInfo();
|
||||
extraAspect<ExecutableAspect>()->setExecutable(FileName::fromString(outFileInfo.absoluteFilePath()));
|
||||
aspect<ExecutableAspect>()->setExecutable(FileName::fromString(outFileInfo.absoluteFilePath()));
|
||||
const QString workingDirectory = outFileInfo.absoluteDir().absolutePath();
|
||||
extraAspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(FileName::fromString(workingDirectory));
|
||||
aspect<WorkingDirectoryAspect>()->setDefaultWorkingDirectory(FileName::fromString(workingDirectory));
|
||||
}
|
||||
|
||||
void NimRunConfiguration::setActiveBuildConfiguration(NimBuildConfiguration *activeBuildConfiguration)
|
||||
|
@@ -94,7 +94,7 @@ private:
|
||||
CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc)
|
||||
: QDialog(Core::ICore::dialogParent()),
|
||||
m_rc(rc),
|
||||
m_workingDirectory(rc->extraAspect<EnvironmentAspect>())
|
||||
m_workingDirectory(rc->aspect<EnvironmentAspect>())
|
||||
{
|
||||
auto vbox = new QVBoxLayout(this);
|
||||
vbox->addWidget(new QLabel(tr("Could not find the executable, please specify one.")));
|
||||
@@ -121,21 +121,21 @@ CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc)
|
||||
m_executableChooser = new PathChooser(this);
|
||||
m_executableChooser->setHistoryCompleter("Qt.CustomExecutable.History");
|
||||
m_executableChooser->setExpectedKind(PathChooser::ExistingCommand);
|
||||
m_executableChooser->setPath(rc->extraAspect<ExecutableAspect>()->executable().toString());
|
||||
m_executableChooser->setPath(rc->aspect<ExecutableAspect>()->executable().toString());
|
||||
layout->addRow(tr("Executable:"), m_executableChooser);
|
||||
connect(m_executableChooser, &PathChooser::rawPathChanged,
|
||||
this, &CustomExecutableDialog::changed);
|
||||
|
||||
copyAspect(rc->extraAspect<ArgumentsAspect>(), &m_arguments);
|
||||
copyAspect(rc->aspect<ArgumentsAspect>(), &m_arguments);
|
||||
m_arguments.addToConfigurationLayout(layout);
|
||||
|
||||
copyAspect(rc->extraAspect<WorkingDirectoryAspect>(), &m_workingDirectory);
|
||||
copyAspect(rc->aspect<WorkingDirectoryAspect>(), &m_workingDirectory);
|
||||
m_workingDirectory.addToConfigurationLayout(layout);
|
||||
|
||||
copyAspect(rc->extraAspect<TerminalAspect>(), &m_terminal);
|
||||
copyAspect(rc->aspect<TerminalAspect>(), &m_terminal);
|
||||
m_terminal.addToConfigurationLayout(layout);
|
||||
|
||||
auto enviromentAspect = rc->extraAspect<EnvironmentAspect>();
|
||||
auto enviromentAspect = rc->aspect<EnvironmentAspect>();
|
||||
connect(enviromentAspect, &EnvironmentAspect::environmentChanged,
|
||||
this, &CustomExecutableDialog::environmentWasChanged);
|
||||
environmentWasChanged();
|
||||
@@ -146,10 +146,10 @@ CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc)
|
||||
void CustomExecutableDialog::accept()
|
||||
{
|
||||
auto executable = FileName::fromString(m_executableChooser->path());
|
||||
m_rc->extraAspect<ExecutableAspect>()->setExecutable(executable);
|
||||
copyAspect(&m_arguments, m_rc->extraAspect<ArgumentsAspect>());
|
||||
copyAspect(&m_workingDirectory, m_rc->extraAspect<WorkingDirectoryAspect>());
|
||||
copyAspect(&m_terminal, m_rc->extraAspect<TerminalAspect>());
|
||||
m_rc->aspect<ExecutableAspect>()->setExecutable(executable);
|
||||
copyAspect(&m_arguments, m_rc->aspect<ArgumentsAspect>());
|
||||
copyAspect(&m_workingDirectory, m_rc->aspect<WorkingDirectoryAspect>());
|
||||
copyAspect(&m_terminal, m_rc->aspect<TerminalAspect>());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
@@ -168,7 +168,7 @@ bool CustomExecutableDialog::event(QEvent *event)
|
||||
|
||||
void CustomExecutableDialog::environmentWasChanged()
|
||||
{
|
||||
auto aspect = m_rc->extraAspect<EnvironmentAspect>();
|
||||
auto aspect = m_rc->aspect<EnvironmentAspect>();
|
||||
QTC_ASSERT(aspect, return);
|
||||
m_executableChooser->setEnvironment(aspect->environment());
|
||||
}
|
||||
@@ -242,7 +242,7 @@ void CustomExecutableRunConfiguration::configurationDialogFinished()
|
||||
|
||||
QString CustomExecutableRunConfiguration::rawExecutable() const
|
||||
{
|
||||
return extraAspect<ExecutableAspect>()->executable().toString();
|
||||
return aspect<ExecutableAspect>()->executable().toString();
|
||||
}
|
||||
|
||||
bool CustomExecutableRunConfiguration::isConfigured() const
|
||||
@@ -253,12 +253,12 @@ bool CustomExecutableRunConfiguration::isConfigured() const
|
||||
Runnable CustomExecutableRunConfiguration::runnable() const
|
||||
{
|
||||
FileName workingDirectory =
|
||||
extraAspect<WorkingDirectoryAspect>()->workingDirectory(macroExpander());
|
||||
aspect<WorkingDirectoryAspect>()->workingDirectory(macroExpander());
|
||||
|
||||
Runnable r;
|
||||
r.executable = extraAspect<ExecutableAspect>()->executable().toString();
|
||||
r.commandLineArguments = extraAspect<ArgumentsAspect>()->arguments(macroExpander());
|
||||
r.environment = extraAspect<EnvironmentAspect>()->environment();
|
||||
r.executable = aspect<ExecutableAspect>()->executable().toString();
|
||||
r.commandLineArguments = aspect<ArgumentsAspect>()->arguments(macroExpander());
|
||||
r.environment = aspect<EnvironmentAspect>()->environment();
|
||||
r.workingDirectory = workingDirectory.toString();
|
||||
r.device = DeviceManager::instance()->defaultDevice(Constants::DESKTOP_DEVICE_TYPE);
|
||||
|
||||
|
@@ -154,7 +154,7 @@ bool ProjectConfiguration::fromMap(const QVariantMap &map)
|
||||
return true;
|
||||
}
|
||||
|
||||
ProjectConfigurationAspect *ProjectConfiguration::extraAspect(Core::Id id) const
|
||||
ProjectConfigurationAspect *ProjectConfiguration::aspect(Core::Id id) const
|
||||
{
|
||||
return Utils::findOrDefault(m_aspects, Utils::equal(&ProjectConfigurationAspect::id, id));
|
||||
}
|
||||
|
@@ -126,9 +126,9 @@ public:
|
||||
|
||||
const QList<ProjectConfigurationAspect *> aspects() const { return m_aspects; }
|
||||
|
||||
ProjectConfigurationAspect *extraAspect(Core::Id id) const;
|
||||
ProjectConfigurationAspect *aspect(Core::Id id) const;
|
||||
|
||||
template <typename T> T *extraAspect() const
|
||||
template <typename T> T *aspect() const
|
||||
{
|
||||
for (ProjectConfigurationAspect *aspect : m_aspects)
|
||||
if (T *result = qobject_cast<T *>(aspect))
|
||||
|
@@ -390,15 +390,15 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
|
||||
}
|
||||
|
||||
QList<FileNode *>
|
||||
FileNode::scanForFilesWithVersionControls(const Utils::FileName &directory,
|
||||
FileNode::scanForFiles(const Utils::FileName &directory,
|
||||
const std::function<FileNode *(const Utils::FileName &)> factory,
|
||||
const QList<Core::IVersionControl *> &versionControls,
|
||||
QFutureInterface<QList<FileNode *>> *future)
|
||||
{
|
||||
QSet<QString> visited;
|
||||
if (future)
|
||||
future->setProgressRange(0, 1000000);
|
||||
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0, versionControls);
|
||||
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0,
|
||||
Core::VcsManager::versionControls());
|
||||
}
|
||||
|
||||
bool FileNode::supportsAction(ProjectAction action, const Node *node) const
|
||||
|
@@ -36,7 +36,6 @@
|
||||
#include <functional>
|
||||
|
||||
namespace Utils { class MimeType; }
|
||||
namespace Core { class IVersionControl; }
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
@@ -191,9 +190,8 @@ public:
|
||||
const FileNode *asFileNode() const final { return this; }
|
||||
|
||||
static QList<FileNode *>
|
||||
scanForFilesWithVersionControls(const Utils::FileName &directory,
|
||||
scanForFiles(const Utils::FileName &directory,
|
||||
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
|
||||
const QList<Core::IVersionControl *> &versionControls,
|
||||
QFutureInterface<QList<FileNode *>> *future = nullptr);
|
||||
bool supportsAction(ProjectAction action, const Node *node) const override;
|
||||
|
||||
|
@@ -193,7 +193,7 @@ RunConfiguration::RunConfiguration(Target *target, Core::Id id)
|
||||
});
|
||||
expander->registerPrefix("CurrentRun:Env", tr("Variables in the current run environment"),
|
||||
[this](const QString &var) {
|
||||
const auto envAspect = extraAspect<EnvironmentAspect>();
|
||||
const auto envAspect = aspect<EnvironmentAspect>();
|
||||
return envAspect ? envAspect->environment().value(var) : QString();
|
||||
});
|
||||
expander->registerVariable(Constants::VAR_CURRENTRUN_NAME,
|
||||
@@ -224,6 +224,8 @@ QWidget *RunConfiguration::createConfigurationWidget()
|
||||
{
|
||||
auto widget = new QWidget;
|
||||
auto formLayout = new QFormLayout(widget);
|
||||
formLayout->setMargin(0);
|
||||
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
|
||||
for (ProjectConfigurationAspect *aspect : m_aspects) {
|
||||
if (aspect->isVisible())
|
||||
@@ -232,7 +234,10 @@ QWidget *RunConfiguration::createConfigurationWidget()
|
||||
|
||||
Core::VariableChooser::addSupportForChildWidgets(widget, macroExpander());
|
||||
|
||||
return wrapWidget(widget);
|
||||
auto detailsWidget = new Utils::DetailsWidget;
|
||||
detailsWidget->setState(DetailsWidget::NoSummary);
|
||||
detailsWidget->setWidget(widget);
|
||||
return detailsWidget;
|
||||
}
|
||||
|
||||
void RunConfiguration::updateEnabledState()
|
||||
@@ -282,18 +287,6 @@ BuildConfiguration *RunConfiguration::activeBuildConfiguration() const
|
||||
return target()->activeBuildConfiguration();
|
||||
}
|
||||
|
||||
QWidget *RunConfiguration::wrapWidget(QWidget *inner) const
|
||||
{
|
||||
auto detailsWidget = new Utils::DetailsWidget;
|
||||
detailsWidget->setState(DetailsWidget::NoSummary);
|
||||
detailsWidget->setWidget(inner);
|
||||
if (auto fl = qobject_cast<QFormLayout *>(inner->layout())){
|
||||
fl->setMargin(0);
|
||||
fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
}
|
||||
return detailsWidget;
|
||||
}
|
||||
|
||||
Target *RunConfiguration::target() const
|
||||
{
|
||||
return static_cast<Target *>(parent());
|
||||
@@ -383,14 +376,14 @@ bool RunConfiguration::fromMap(const QVariantMap &map)
|
||||
Runnable RunConfiguration::runnable() const
|
||||
{
|
||||
Runnable r;
|
||||
if (auto aspect = extraAspect<ExecutableAspect>())
|
||||
r.executable = aspect->executable().toString();
|
||||
if (auto aspect = extraAspect<ArgumentsAspect>())
|
||||
r.commandLineArguments = aspect->arguments(macroExpander());
|
||||
if (auto aspect = extraAspect<WorkingDirectoryAspect>())
|
||||
r.workingDirectory = aspect->workingDirectory(macroExpander()).toString();
|
||||
if (auto aspect = extraAspect<EnvironmentAspect>())
|
||||
r.environment = aspect->environment();
|
||||
if (auto executableAspect = aspect<ExecutableAspect>())
|
||||
r.executable = executableAspect->executable().toString();
|
||||
if (auto argumentsAspect = aspect<ArgumentsAspect>())
|
||||
r.commandLineArguments = argumentsAspect->arguments(macroExpander());
|
||||
if (auto workingDirectoryAspect = aspect<WorkingDirectoryAspect>())
|
||||
r.workingDirectory = workingDirectoryAspect->workingDirectory(macroExpander()).toString();
|
||||
if (auto environmentAspect = aspect<EnvironmentAspect>())
|
||||
r.environment = environmentAspect->environment();
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1563,7 +1556,7 @@ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
|
||||
m_runnable = runControl->runnable(); // Default value. Can be overridden using setRunnable.
|
||||
m_device = runControl->device(); // Default value. Can be overridden using setDevice.
|
||||
if (auto runConfig = runControl->runConfiguration()) {
|
||||
if (auto terminalAspect = runConfig->extraAspect<TerminalAspect>())
|
||||
if (auto terminalAspect = runConfig->aspect<TerminalAspect>())
|
||||
m_useTerminal = terminalAspect->useTerminal();
|
||||
}
|
||||
}
|
||||
|
@@ -185,8 +185,8 @@ public:
|
||||
|
||||
template <class T = ISettingsAspect> T *currentSettings(Core::Id id) const
|
||||
{
|
||||
if (auto aspect = qobject_cast<GlobalOrProjectAspect *>(extraAspect(id)))
|
||||
return qobject_cast<T *>(aspect->currentSettings());
|
||||
if (auto a = qobject_cast<GlobalOrProjectAspect *>(aspect(id)))
|
||||
return qobject_cast<T *>(a->currentSettings());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -205,7 +205,6 @@ protected:
|
||||
|
||||
/// convenience function to get current build configuration.
|
||||
BuildConfiguration *activeBuildConfiguration() const;
|
||||
QWidget *wrapWidget(QWidget *inner) const;
|
||||
|
||||
template<class T> void setOutputFormatter()
|
||||
{
|
||||
|
@@ -113,6 +113,10 @@ public:
|
||||
|
||||
bool showInSimpleTree() const override;
|
||||
QString addFileFilter() const override;
|
||||
bool supportsAction(ProjectAction action, const Node *node) const override;
|
||||
bool addFiles(const QStringList &filePaths, QStringList *) override;
|
||||
bool removeFiles(const QStringList &filePaths, QStringList *) override;
|
||||
bool deleteFiles(const QStringList &) override;
|
||||
bool renameFile(const QString &filePath, const QString &newFilePath) override;
|
||||
|
||||
private:
|
||||
@@ -237,9 +241,9 @@ private:
|
||||
Runnable runnable() const final;
|
||||
|
||||
bool supportsDebugger() const { return true; }
|
||||
QString mainScript() const { return extraAspect<MainScriptAspect>()->value(); }
|
||||
QString arguments() const { return extraAspect<ArgumentsAspect>()->arguments(macroExpander()); }
|
||||
QString interpreter() const { return extraAspect<InterpreterAspect>()->value(); }
|
||||
QString mainScript() const { return aspect<MainScriptAspect>()->value(); }
|
||||
QString arguments() const { return aspect<ArgumentsAspect>()->arguments(macroExpander()); }
|
||||
QString interpreter() const { return aspect<InterpreterAspect>()->value(); }
|
||||
|
||||
void updateTargetInformation();
|
||||
};
|
||||
@@ -279,7 +283,7 @@ void PythonRunConfiguration::updateTargetInformation()
|
||||
const BuildTargetInfo bti = buildTargetInfo();
|
||||
const QString script = bti.targetFilePath.toString();
|
||||
setDefaultDisplayName(tr("Run %1").arg(script));
|
||||
extraAspect<MainScriptAspect>()->setValue(script);
|
||||
aspect<MainScriptAspect>()->setValue(script);
|
||||
}
|
||||
|
||||
Runnable PythonRunConfiguration::runnable() const
|
||||
@@ -287,9 +291,9 @@ Runnable PythonRunConfiguration::runnable() const
|
||||
Runnable r;
|
||||
QtcProcess::addArg(&r.commandLineArguments, mainScript());
|
||||
QtcProcess::addArgs(&r.commandLineArguments,
|
||||
extraAspect<ArgumentsAspect>()->arguments(macroExpander()));
|
||||
r.executable = extraAspect<InterpreterAspect>()->value();
|
||||
r.environment = extraAspect<EnvironmentAspect>()->environment();
|
||||
aspect<ArgumentsAspect>()->arguments(macroExpander()));
|
||||
r.executable = aspect<InterpreterAspect>()->value();
|
||||
r.environment = aspect<EnvironmentAspect>()->environment();
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -312,11 +316,13 @@ PythonProject::PythonProject(const FileName &fileName) :
|
||||
setDisplayName(fileName.toFileInfo().completeBaseName());
|
||||
}
|
||||
|
||||
static QStringList readLines(const QString &absoluteFileName)
|
||||
static QStringList readLines(const Utils::FileName &projectFile)
|
||||
{
|
||||
QStringList lines;
|
||||
const QString projectFileName = projectFile.fileName();
|
||||
QSet<QString> visited = { projectFileName };
|
||||
QStringList lines = { projectFileName };
|
||||
|
||||
QFile file(absoluteFileName);
|
||||
QFile file(projectFile.toString());
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
QTextStream stream(&file);
|
||||
|
||||
@@ -324,8 +330,10 @@ static QStringList readLines(const QString &absoluteFileName)
|
||||
QString line = stream.readLine();
|
||||
if (line.isNull())
|
||||
break;
|
||||
|
||||
if (visited.contains(line))
|
||||
continue;
|
||||
lines.append(line);
|
||||
visited.insert(line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,14 +370,6 @@ bool PythonProject::addFiles(const QStringList &filePaths)
|
||||
foreach (const QString &filePath, filePaths)
|
||||
newList.append(baseDir.relativeFilePath(filePath));
|
||||
|
||||
QSet<QString> toAdd;
|
||||
|
||||
foreach (const QString &filePath, filePaths) {
|
||||
QString directory = QFileInfo(filePath).absolutePath();
|
||||
if (!toAdd.contains(directory))
|
||||
toAdd << directory;
|
||||
}
|
||||
|
||||
bool result = saveRawList(newList, projectFilePath().toString());
|
||||
refresh();
|
||||
|
||||
@@ -392,7 +392,7 @@ bool PythonProject::removeFiles(const QStringList &filePaths)
|
||||
bool PythonProject::setFiles(const QStringList &filePaths)
|
||||
{
|
||||
QStringList newList;
|
||||
QDir baseDir(projectFilePath().toString());
|
||||
QDir baseDir(projectDirectory().toString());
|
||||
foreach (const QString &filePath, filePaths)
|
||||
newList.append(baseDir.relativeFilePath(filePath));
|
||||
|
||||
@@ -407,7 +407,7 @@ bool PythonProject::renameFile(const QString &filePath, const QString &newFilePa
|
||||
if (i != m_rawListEntries.end()) {
|
||||
int index = newList.indexOf(i.value());
|
||||
if (index != -1) {
|
||||
QDir baseDir(projectFilePath().toString());
|
||||
QDir baseDir(projectDirectory().toString());
|
||||
newList.replace(index, baseDir.relativeFilePath(newFilePath));
|
||||
}
|
||||
}
|
||||
@@ -418,8 +418,7 @@ bool PythonProject::renameFile(const QString &filePath, const QString &newFilePa
|
||||
void PythonProject::parseProject()
|
||||
{
|
||||
m_rawListEntries.clear();
|
||||
m_rawFileList = readLines(projectFilePath().toString());
|
||||
m_rawFileList << projectFilePath().fileName();
|
||||
m_rawFileList = readLines(projectFilePath());
|
||||
m_files = processEntries(m_rawFileList, &m_rawListEntries);
|
||||
}
|
||||
|
||||
@@ -581,6 +580,37 @@ QString PythonProjectNode::addFileFilter() const
|
||||
return QLatin1String("*.py");
|
||||
}
|
||||
|
||||
bool PythonProjectNode::supportsAction(ProjectAction action, const Node *node) const
|
||||
{
|
||||
switch (node->nodeType()) {
|
||||
case NodeType::File:
|
||||
return action == ProjectAction::Rename
|
||||
|| action == ProjectAction::RemoveFile;
|
||||
case NodeType::Folder:
|
||||
case NodeType::Project:
|
||||
return action == ProjectAction::AddNewFile
|
||||
|| action == ProjectAction::RemoveFile
|
||||
|| action == ProjectAction::AddExistingFile;
|
||||
default:
|
||||
return ProjectNode::supportsAction(action, node);
|
||||
}
|
||||
}
|
||||
|
||||
bool PythonProjectNode::addFiles(const QStringList &filePaths, QStringList *)
|
||||
{
|
||||
return m_project->addFiles(filePaths);
|
||||
}
|
||||
|
||||
bool PythonProjectNode::removeFiles(const QStringList &filePaths, QStringList *)
|
||||
{
|
||||
return m_project->removeFiles(filePaths);
|
||||
}
|
||||
|
||||
bool PythonProjectNode::deleteFiles(const QStringList &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PythonProjectNode::renameFile(const QString &filePath, const QString &newFilePath)
|
||||
{
|
||||
return m_project->renameFile(filePath, newFilePath);
|
||||
|
@@ -30,11 +30,11 @@
|
||||
#include <projectexplorer/kitconfigwidget.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
|
||||
#include <utils/elidinglabel.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <qbs.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
@@ -48,7 +48,7 @@ class ConfigWidget final : public KitConfigWidget
|
||||
public:
|
||||
ConfigWidget(Kit *kit, const KitInformation *kitInfo)
|
||||
: KitConfigWidget(kit, kitInfo),
|
||||
m_contentLabel(new QLabel),
|
||||
m_contentLabel(new Utils::ElidingLabel),
|
||||
m_changeButton(new QPushButton(tr("Change...")))
|
||||
{
|
||||
connect(m_changeButton, &QPushButton::clicked, this, &ConfigWidget::changeProperties);
|
||||
|
@@ -110,11 +110,11 @@ void QbsRunConfiguration::doAdditionalSetup(const RunConfigurationCreationInfo &
|
||||
|
||||
void QbsRunConfiguration::addToBaseEnvironment(Utils::Environment &env) const
|
||||
{
|
||||
if (auto dyldAspect = extraAspect<UseDyldSuffixAspect>()) {
|
||||
if (auto dyldAspect = aspect<UseDyldSuffixAspect>()) {
|
||||
if (dyldAspect->value())
|
||||
env.set("DYLD_IMAGE_SUFFIX", "_debug");
|
||||
}
|
||||
bool usingLibraryPaths = extraAspect<UseLibraryPathsAspect>()->value();
|
||||
bool usingLibraryPaths = aspect<UseLibraryPathsAspect>()->value();
|
||||
|
||||
const auto key = qMakePair(env.toStringList(), usingLibraryPaths);
|
||||
const auto it = m_envCache.constFind(key);
|
||||
@@ -146,16 +146,16 @@ void QbsRunConfiguration::updateTargetInformation()
|
||||
{
|
||||
BuildTargetInfo bti = buildTargetInfo();
|
||||
const FileName executable = executableToRun(bti);
|
||||
auto terminalAspect = extraAspect<TerminalAspect>();
|
||||
auto terminalAspect = aspect<TerminalAspect>();
|
||||
if (!terminalAspect->isUserSet())
|
||||
terminalAspect->setUseTerminal(bti.usesTerminal);
|
||||
|
||||
extraAspect<ExecutableAspect>()->setExecutable(executable);
|
||||
aspect<ExecutableAspect>()->setExecutable(executable);
|
||||
|
||||
if (!executable.isEmpty()) {
|
||||
QString defaultWorkingDir = QFileInfo(executable.toString()).absolutePath();
|
||||
if (!defaultWorkingDir.isEmpty()) {
|
||||
auto wdAspect = extraAspect<WorkingDirectoryAspect>();
|
||||
auto wdAspect = aspect<WorkingDirectoryAspect>();
|
||||
wdAspect->setDefaultWorkingDirectory(FileName::fromString(defaultWorkingDir));
|
||||
}
|
||||
}
|
||||
|
@@ -91,20 +91,20 @@ DesktopQmakeRunConfiguration::DesktopQmakeRunConfiguration(Target *target, Core:
|
||||
void DesktopQmakeRunConfiguration::updateTargetInformation()
|
||||
{
|
||||
setDefaultDisplayName(defaultDisplayName());
|
||||
extraAspect<LocalEnvironmentAspect>()->buildEnvironmentHasChanged();
|
||||
aspect<LocalEnvironmentAspect>()->buildEnvironmentHasChanged();
|
||||
|
||||
BuildTargetInfo bti = buildTargetInfo();
|
||||
|
||||
auto wda = extraAspect<WorkingDirectoryAspect>();
|
||||
auto wda = aspect<WorkingDirectoryAspect>();
|
||||
wda->setDefaultWorkingDirectory(bti.workingDirectory);
|
||||
if (wda->pathChooser())
|
||||
wda->pathChooser()->setBaseFileName(target()->project()->projectDirectory());
|
||||
|
||||
auto terminalAspect = extraAspect<TerminalAspect>();
|
||||
auto terminalAspect = aspect<TerminalAspect>();
|
||||
if (!terminalAspect->isUserSet())
|
||||
terminalAspect->setUseTerminal(bti.usesTerminal);
|
||||
|
||||
extraAspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
aspect<ExecutableAspect>()->setExecutable(bti.targetFilePath);
|
||||
}
|
||||
|
||||
QVariantMap DesktopQmakeRunConfiguration::toMap() const
|
||||
@@ -135,9 +135,9 @@ void DesktopQmakeRunConfiguration::addToBaseEnvironment(Environment &env) const
|
||||
{
|
||||
BuildTargetInfo bti = buildTargetInfo();
|
||||
if (bti.runEnvModifier)
|
||||
bti.runEnvModifier(env, extraAspect<UseLibraryPathsAspect>()->value());
|
||||
bti.runEnvModifier(env, aspect<UseLibraryPathsAspect>()->value());
|
||||
|
||||
if (auto dyldAspect = extraAspect<UseDyldSuffixAspect>()) {
|
||||
if (auto dyldAspect = aspect<UseDyldSuffixAspect>()) {
|
||||
if (dyldAspect->value())
|
||||
env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug"));
|
||||
}
|
||||
|
@@ -302,7 +302,7 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
|
||||
auto runConfiguration = runControl->runConfiguration();
|
||||
if (runConfiguration) {
|
||||
auto aspect = static_cast<QmlProfilerRunConfigurationAspect *>(
|
||||
runConfiguration->extraAspect(Constants::SETTINGS));
|
||||
runConfiguration->aspect(Constants::SETTINGS));
|
||||
if (aspect) {
|
||||
if (QmlProfilerSettings *settings = static_cast<QmlProfilerSettings *>(aspect->currentSettings())) {
|
||||
d->m_profilerConnections->setFlushInterval(settings->flushEnabled() ?
|
||||
|
@@ -305,7 +305,7 @@ Runnable QmlProjectRunConfiguration::runnable() const
|
||||
Runnable r;
|
||||
r.executable = executable();
|
||||
r.commandLineArguments = commandLineArguments();
|
||||
r.environment = extraAspect<QmlProjectEnvironmentAspect>()->environment();
|
||||
r.environment = aspect<QmlProjectEnvironmentAspect>()->environment();
|
||||
r.workingDirectory = static_cast<QmlProject *>(project())->targetDirectory(target()).toString();
|
||||
return r;
|
||||
}
|
||||
@@ -354,7 +354,7 @@ QString QmlProjectRunConfiguration::executable() const
|
||||
QString QmlProjectRunConfiguration::commandLineArguments() const
|
||||
{
|
||||
// arguments in .user file
|
||||
QString args = extraAspect<ArgumentsAspect>()->arguments(macroExpander());
|
||||
QString args = aspect<ArgumentsAspect>()->arguments(macroExpander());
|
||||
const Target *currentTarget = target();
|
||||
const IDevice::ConstPtr device = DeviceKitInformation::device(currentTarget->kit());
|
||||
const Utils::OsType osType = device ? device->osType() : Utils::HostOsInfo::hostOs();
|
||||
|
@@ -265,7 +265,7 @@ void QnxAttachDebugSupport::showProcessesDialog()
|
||||
// QString projectSourceDirectory = dlg.projectSource();
|
||||
QString localExecutable = dlg.localExecutable();
|
||||
if (localExecutable.isEmpty()) {
|
||||
if (auto aspect = runConfig->extraAspect<SymbolFileAspect>())
|
||||
if (auto aspect = runConfig->aspect<SymbolFileAspect>())
|
||||
localExecutable = aspect->fileName().toString();
|
||||
}
|
||||
|
||||
|
@@ -45,7 +45,7 @@ QnxRunConfiguration::QnxRunConfiguration(Target *target, Core::Id id)
|
||||
Runnable QnxRunConfiguration::runnable() const
|
||||
{
|
||||
Runnable r = RemoteLinuxRunConfiguration::runnable();
|
||||
QString libPath = extraAspect<QtLibPathAspect>()->value();
|
||||
QString libPath = aspect<QtLibPathAspect>()->value();
|
||||
if (!libPath.isEmpty()) {
|
||||
r.environment.appendOrSet("LD_LIBRARY_PATH", libPath + "/lib:$LD_LIBRARY_PATH");
|
||||
r.environment.appendOrSet("QML_IMPORT_PATH", libPath + "/imports:$QML_IMPORT_PATH");
|
||||
|
@@ -45,7 +45,7 @@ Slog2InfoRunner::Slog2InfoRunner(RunControl *runControl)
|
||||
: RunWorker(runControl)
|
||||
{
|
||||
setId("Slog2InfoRunner");
|
||||
m_applicationId = runControl->runConfiguration()->extraAspect<ExecutableAspect>()->executable().fileName();
|
||||
m_applicationId = runControl->runConfiguration()->aspect<ExecutableAspect>()->executable().fileName();
|
||||
|
||||
// See QTCREATORBUG-10712 for details.
|
||||
// We need to limit length of ApplicationId to 63 otherwise it would not match one in slog2info.
|
||||
|
@@ -65,7 +65,7 @@ RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(Target *tar
|
||||
|
||||
bool RemoteLinuxCustomRunConfiguration::isConfigured() const
|
||||
{
|
||||
return !extraAspect<ExecutableAspect>()->executable().isEmpty();
|
||||
return !aspect<ExecutableAspect>()->executable().isEmpty();
|
||||
}
|
||||
|
||||
RunConfiguration::ConfigurationState
|
||||
@@ -88,7 +88,7 @@ Core::Id RemoteLinuxCustomRunConfiguration::runConfigId()
|
||||
|
||||
QString RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName()
|
||||
{
|
||||
QString remoteExecutable = extraAspect<ExecutableAspect>()->executable().toString();
|
||||
QString remoteExecutable = aspect<ExecutableAspect>()->executable().toString();
|
||||
QString display = remoteExecutable.isEmpty()
|
||||
? tr("Custom Executable") : tr("Run \"%1\"").arg(remoteExecutable);
|
||||
return RunConfigurationFactory::decoratedTargetName(display, target());
|
||||
|
@@ -73,24 +73,14 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Core::I
|
||||
this, &RemoteLinuxRunConfiguration::updateTargetInformation);
|
||||
}
|
||||
|
||||
void RemoteLinuxRunConfiguration::doAdditionalSetup(const RunConfigurationCreationInfo &)
|
||||
{
|
||||
setDefaultDisplayName(defaultDisplayName());
|
||||
}
|
||||
|
||||
QString RemoteLinuxRunConfiguration::defaultDisplayName() const
|
||||
{
|
||||
return RunConfigurationFactory::decoratedTargetName(buildKey(), target());
|
||||
}
|
||||
|
||||
void RemoteLinuxRunConfiguration::updateTargetInformation()
|
||||
{
|
||||
BuildTargetInfo bti = buildTargetInfo();
|
||||
QString localExecutable = bti.targetFilePath.toString();
|
||||
DeployableFile depFile = target()->deploymentData().deployableForLocalFile(localExecutable);
|
||||
|
||||
extraAspect<ExecutableAspect>()->setExecutable(FileName::fromString(depFile.remoteFilePath()));
|
||||
extraAspect<SymbolFileAspect>()->setValue(localExecutable);
|
||||
aspect<ExecutableAspect>()->setExecutable(FileName::fromString(depFile.remoteFilePath()));
|
||||
aspect<SymbolFileAspect>()->setValue(localExecutable);
|
||||
|
||||
emit enabledChanged();
|
||||
}
|
||||
@@ -103,6 +93,7 @@ const char *RemoteLinuxRunConfiguration::IdPrefix = "RemoteLinuxRunConfiguration
|
||||
RemoteLinuxRunConfigurationFactory::RemoteLinuxRunConfigurationFactory()
|
||||
{
|
||||
registerRunConfiguration<RemoteLinuxRunConfiguration>(RemoteLinuxRunConfiguration::IdPrefix);
|
||||
setDecorateDisplayNames(true);
|
||||
addSupportedTargetDeviceType(RemoteLinux::Constants::GenericLinuxOsType);
|
||||
}
|
||||
|
||||
|
@@ -40,9 +40,6 @@ public:
|
||||
static const char *IdPrefix;
|
||||
|
||||
private:
|
||||
void doAdditionalSetup(const ProjectExplorer::RunConfigurationCreationInfo &) override;
|
||||
|
||||
QString defaultDisplayName() const;
|
||||
void updateTargetInformation();
|
||||
};
|
||||
|
||||
|
@@ -31,9 +31,11 @@
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/completionsettings.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/codeassist/assistproposaliteminterface.h>
|
||||
|
||||
#include <utils/faketooltip.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QRect>
|
||||
#include <QLatin1String>
|
||||
@@ -49,6 +51,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QDesktopWidget>
|
||||
#include <QLabel>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
@@ -92,6 +95,8 @@ QVariant ModelAdapter::data(const QModelIndex &index, int role) const
|
||||
return m_completionModel->icon(index.row());
|
||||
else if (role == Qt::WhatsThisRole)
|
||||
return m_completionModel->detail(index.row());
|
||||
else if (role == Qt::UserRole)
|
||||
return m_completionModel->proposalItem(index.row())->requiresFixIts();
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
@@ -146,6 +151,7 @@ private:
|
||||
// -----------------------
|
||||
class GenericProposalListView : public QListView
|
||||
{
|
||||
friend class ProposalItemDelegate;
|
||||
public:
|
||||
GenericProposalListView(QWidget *parent);
|
||||
|
||||
@@ -160,10 +166,53 @@ public:
|
||||
void selectLastRow() { selectRow(model()->rowCount() - 1); }
|
||||
};
|
||||
|
||||
class ProposalItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProposalItemDelegate(GenericProposalListView *parent = nullptr)
|
||||
: QStyledItemDelegate(parent)
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override
|
||||
{
|
||||
static const QIcon fixItIcon = ::Utils::Icons::CODEMODEL_FIXIT.icon();
|
||||
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
|
||||
if (m_parent->model()->data(index, Qt::UserRole).toBool()) {
|
||||
const QRect itemRect = m_parent->rectForIndex(index);
|
||||
const QScrollBar *verticalScrollBar = m_parent->verticalScrollBar();
|
||||
|
||||
const int x = m_parent->width() - itemRect.height() - (verticalScrollBar->isVisible()
|
||||
? verticalScrollBar->width()
|
||||
: 0);
|
||||
const int iconSize = itemRect.height() - 5;
|
||||
fixItIcon.paint(painter, QRect(x, itemRect.y() - m_parent->verticalOffset(),
|
||||
iconSize, iconSize));
|
||||
}
|
||||
}
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
QSize size(QStyledItemDelegate::sizeHint(option, index));
|
||||
if (m_parent->model()->data(index, Qt::UserRole).toBool())
|
||||
size.setWidth(size.width() + m_parent->rectForIndex(index).height() - 5);
|
||||
return size;
|
||||
}
|
||||
private:
|
||||
GenericProposalListView *m_parent;
|
||||
};
|
||||
|
||||
GenericProposalListView::GenericProposalListView(QWidget *parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
|
||||
setItemDelegate(new ProposalItemDelegate(this));
|
||||
}
|
||||
|
||||
QSize GenericProposalListView::calculateSize() const
|
||||
|
@@ -86,7 +86,7 @@ void ValgrindToolRunner::start()
|
||||
m_runner.setDevice(device());
|
||||
m_runner.setDebuggee(runnable());
|
||||
|
||||
if (auto aspect = runControl()->runConfiguration()->extraAspect<TerminalAspect>())
|
||||
if (auto aspect = runControl()->runConfiguration()->aspect<TerminalAspect>())
|
||||
m_runner.setUseTerminal(aspect->useTerminal());
|
||||
|
||||
connect(&m_runner, &ValgrindRunner::processOutputReceived,
|
||||
|
@@ -84,13 +84,13 @@ WinRtRunnerHelper::WinRtRunnerHelper(ProjectExplorer::RunWorker *runWorker, QStr
|
||||
|
||||
bool loopbackExemptClient = false;
|
||||
bool loopbackExemptServer = false;
|
||||
if (auto aspect = runConfiguration->extraAspect<ArgumentsAspect>())
|
||||
if (auto aspect = runConfiguration->aspect<ArgumentsAspect>())
|
||||
m_arguments = aspect->arguments(runConfiguration->macroExpander());
|
||||
if (auto aspect = runConfiguration->extraAspect<UninstallAfterStopAspect>())
|
||||
if (auto aspect = runConfiguration->aspect<UninstallAfterStopAspect>())
|
||||
m_uninstallAfterStop = aspect->value();
|
||||
if (auto aspect = runConfiguration->extraAspect<LoopbackExemptClientAspect>())
|
||||
if (auto aspect = runConfiguration->aspect<LoopbackExemptClientAspect>())
|
||||
loopbackExemptClient = aspect->value();
|
||||
if (auto aspect = runConfiguration->extraAspect<LoopbackExemptServerAspect>())
|
||||
if (auto aspect = runConfiguration->aspect<LoopbackExemptServerAspect>())
|
||||
loopbackExemptServer = aspect->value();
|
||||
if (loopbackExemptClient && loopbackExemptServer)
|
||||
m_loopbackArguments = "--loopbackexempt clientserver";
|
||||
|
@@ -40,6 +40,8 @@
|
||||
#include "unsavedfile.h"
|
||||
#include "unsavedfiles.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
@@ -47,13 +49,14 @@ namespace ClangBackEnd {
|
||||
namespace {
|
||||
|
||||
CodeCompletions toCodeCompletions(const TranslationUnit &translationUnit,
|
||||
const ClangCodeCompleteResults &results)
|
||||
const ClangCodeCompleteResults &results,
|
||||
bool onlyFunctionOverloads)
|
||||
{
|
||||
if (results.isNull())
|
||||
return CodeCompletions();
|
||||
|
||||
CodeCompletionsExtractor extractor(translationUnit.cxTranslationUnit(), results.data());
|
||||
CodeCompletions codeCompletions = extractor.extractAll();
|
||||
CodeCompletions codeCompletions = extractor.extractAll(onlyFunctionOverloads);
|
||||
|
||||
return codeCompletions;
|
||||
}
|
||||
@@ -83,33 +86,49 @@ CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit,
|
||||
{
|
||||
}
|
||||
|
||||
static void replaceWithOpeningParen(UnsavedFile &file, uint line, uint column)
|
||||
{
|
||||
bool ok;
|
||||
const uint pos = file.toUtf8Position(line, column, &ok);
|
||||
QTC_ASSERT(ok, return;);
|
||||
file.replaceAt(pos, 1, Utf8String("(", 1));
|
||||
}
|
||||
|
||||
CodeCompletions CodeCompleter::complete(uint line, uint column,
|
||||
int funcNameStartLine,
|
||||
int funcNameStartColumn)
|
||||
{
|
||||
if (funcNameStartLine >= 0) {
|
||||
UnsavedFile &file = unsavedFiles.unsavedFile(translationUnit.filePath());
|
||||
// Replace '{' by '(' to get proper FunctionOverloadCompletionKind for constructor.
|
||||
if (file.hasCharacterAt(line, column - 1, '{'))
|
||||
replaceWithOpeningParen(file, line, column - 1);
|
||||
}
|
||||
|
||||
// Check if we have a smart pointer completion and get proper constructor signatures in results.
|
||||
// Results are empty when it's not a smart pointer or this completion failed.
|
||||
ClangCodeCompleteResults results = completeSmartPointerCreation(line,
|
||||
ClangCodeCompleteResults clangCompletions = completeSmartPointerCreation(line,
|
||||
column,
|
||||
funcNameStartLine,
|
||||
funcNameStartColumn);
|
||||
|
||||
if (results.isNull() || results.isEmpty())
|
||||
results = completeHelper(line, column);
|
||||
// Default completion.
|
||||
if (clangCompletions.isNull() || clangCompletions.isEmpty())
|
||||
clangCompletions = completeHelper(line, column);
|
||||
|
||||
filterUnknownContextResults(results, unsavedFile(), line, column);
|
||||
filterUnknownContextResults(clangCompletions, unsavedFile(), line, column);
|
||||
|
||||
return toCodeCompletions(translationUnit, results);
|
||||
return toCodeCompletions(translationUnit, clangCompletions, funcNameStartLine >= 0);
|
||||
}
|
||||
|
||||
// For given "make_unique<T>" / "make_shared<T>" / "QSharedPointer<T>::create" return "new T("
|
||||
// Otherwize return empty QString
|
||||
static QString tweakName(const QString &oldName)
|
||||
static QString tweakName(const Utf8String &oldName)
|
||||
{
|
||||
QString fullName = oldName.trimmed();
|
||||
if (!fullName.contains('>'))
|
||||
if (!oldName.contains('>'))
|
||||
return QString();
|
||||
|
||||
QString fullName = QString(oldName).trimmed();
|
||||
if (!fullName.endsWith('>')) {
|
||||
// This is the class<type>::method case - remove ::method part
|
||||
if (!fullName.endsWith("create") || !fullName.contains("QSharedPointer"))
|
||||
@@ -138,10 +157,12 @@ ClangCodeCompleteResults CodeCompleter::completeSmartPointerCreation(uint line,
|
||||
|
||||
bool ok;
|
||||
const uint startPos = file.toUtf8Position(funcNameStartLine, funcNameStartColumn, &ok);
|
||||
QTC_ASSERT(ok, return ClangCodeCompleteResults(););
|
||||
const uint endPos = file.toUtf8Position(line, column - 1, &ok);
|
||||
QTC_ASSERT(ok, return ClangCodeCompleteResults(););
|
||||
|
||||
Utf8String content = file.fileContent();
|
||||
const QString oldName = content.mid(startPos, endPos - startPos);
|
||||
const Utf8String content = file.fileContent();
|
||||
const Utf8String oldName = content.mid(startPos, endPos - startPos);
|
||||
const QString updatedName = tweakName(oldName);
|
||||
if (updatedName.isEmpty())
|
||||
return ClangCodeCompleteResults();
|
||||
|
@@ -27,9 +27,13 @@
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangstring.h"
|
||||
#include "clangtranslationunit.h"
|
||||
#include "codecompletionchunkconverter.h"
|
||||
#include "sourcelocation.h"
|
||||
#include "sourcerange.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
@@ -85,7 +89,7 @@ bool CodeCompletionsExtractor::peek(const Utf8String &name)
|
||||
return false;
|
||||
}
|
||||
|
||||
CodeCompletions CodeCompletionsExtractor::extractAll()
|
||||
CodeCompletions CodeCompletionsExtractor::extractAll(bool onlyFunctionOverloads)
|
||||
{
|
||||
CodeCompletions codeCompletions;
|
||||
codeCompletions.reserve(int(cxCodeCompleteResults->NumResults));
|
||||
@@ -93,9 +97,75 @@ CodeCompletions CodeCompletionsExtractor::extractAll()
|
||||
while (next())
|
||||
codeCompletions.append(currentCodeCompletion_);
|
||||
|
||||
handleCompletions(codeCompletions, onlyFunctionOverloads);
|
||||
|
||||
return codeCompletions;
|
||||
}
|
||||
|
||||
static CodeCompletions filterFunctionOverloads(const CodeCompletions &completions)
|
||||
{
|
||||
return ::Utils::filtered(completions, [](const CodeCompletion &completion) {
|
||||
return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind;
|
||||
});
|
||||
}
|
||||
|
||||
static ::Utils::optional<bool> classBeforeCXXConstructor(const CodeCompletion &first,
|
||||
const CodeCompletion &second)
|
||||
{
|
||||
// Put ClassCompletionKind elements before ConstructorCompletionKind elements
|
||||
// when they have the same name.
|
||||
if (first.completionKind == CodeCompletion::ClassCompletionKind
|
||||
&& second.completionKind == CodeCompletion::ConstructorCompletionKind
|
||||
&& first.text == second.text) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (first.completionKind == CodeCompletion::ConstructorCompletionKind
|
||||
&& second.completionKind == CodeCompletion::ClassCompletionKind
|
||||
&& first.text == second.text) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::Utils::optional<bool>();
|
||||
}
|
||||
|
||||
static void sortCodeCompletions(CodeCompletions &codeCompletions)
|
||||
{
|
||||
auto currentItemsCompare = [](const CodeCompletion &first,
|
||||
const CodeCompletion &second) {
|
||||
// Items without fix-its come first.
|
||||
if (first.requiredFixIts.empty() != second.requiredFixIts.empty())
|
||||
return first.requiredFixIts.empty() > second.requiredFixIts.empty();
|
||||
|
||||
const ::Utils::optional<bool> classBeforeConstructorWithTheSameName
|
||||
= classBeforeCXXConstructor(first, second);
|
||||
if (classBeforeConstructorWithTheSameName)
|
||||
return classBeforeConstructorWithTheSameName.value();
|
||||
|
||||
return (first.priority > 0
|
||||
&& (first.priority < second.priority
|
||||
|| (first.priority == second.priority && first.text < second.text)));
|
||||
};
|
||||
|
||||
// Keep the order for the items with the same priority and name.
|
||||
std::stable_sort(codeCompletions.begin(), codeCompletions.end(), currentItemsCompare);
|
||||
}
|
||||
|
||||
void CodeCompletionsExtractor::handleCompletions(CodeCompletions &codeCompletions,
|
||||
bool onlyFunctionOverloads)
|
||||
{
|
||||
if (onlyFunctionOverloads) {
|
||||
const CodeCompletions overloadCompletions = filterFunctionOverloads(codeCompletions);
|
||||
|
||||
// If filtered completions are empty the assumption we need function overloads is wrong
|
||||
// therefore we do not use filtered results in that case.
|
||||
if (!overloadCompletions.isEmpty())
|
||||
codeCompletions = overloadCompletions;
|
||||
}
|
||||
|
||||
sortCodeCompletions(codeCompletions);
|
||||
}
|
||||
|
||||
void CodeCompletionsExtractor::extractCompletionKind()
|
||||
{
|
||||
switch (currentCxCodeCompleteResult.CursorKind) {
|
||||
|
@@ -50,7 +50,7 @@ public:
|
||||
bool next();
|
||||
bool peek(const Utf8String &name);
|
||||
|
||||
CodeCompletions extractAll();
|
||||
CodeCompletions extractAll(bool onlyFunctionOverloads);
|
||||
|
||||
const CodeCompletion ¤tCodeCompletion() const;
|
||||
|
||||
@@ -73,6 +73,8 @@ private:
|
||||
void decreasePriorityForQObjectInternals();
|
||||
void decreasePriorityForOperators();
|
||||
|
||||
void handleCompletions(CodeCompletions &codeCompletions, bool onlyFunctionOverloads);
|
||||
|
||||
bool hasText(const Utf8String &text, CXCompletionString cxCompletionString) const;
|
||||
|
||||
private:
|
||||
|
@@ -43,6 +43,7 @@ using ::testing::Not;
|
||||
using ::testing::PrintToString;
|
||||
|
||||
using ClangBackEnd::CodeCompletion;
|
||||
using ClangBackEnd::CodeCompletionChunk;
|
||||
using ClangBackEnd::CodeCompleter;
|
||||
|
||||
namespace {
|
||||
@@ -65,6 +66,29 @@ MATCHER_P2(IsCodeCompletion, text, completionKind,
|
||||
return true;
|
||||
}
|
||||
|
||||
MATCHER_P(IsOverloadCompletion, text,
|
||||
std::string(negation ? "isn't" : "is") + " overload completion with text " + PrintToString(text))
|
||||
{
|
||||
Utf8String overloadName;
|
||||
for (auto &chunk : arg.chunks) {
|
||||
if (chunk.kind == CodeCompletionChunk::Text) {
|
||||
overloadName = chunk.text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overloadName != text) {
|
||||
*result_listener << "text is " + PrintToString(overloadName) + " and not " + PrintToString(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arg.completionKind != CodeCompletion::FunctionOverloadCompletionKind) {
|
||||
*result_listener << "kind is " + PrintToString(arg.completionKind) + " and not " + PrintToString(CodeCompletion::FunctionOverloadCompletionKind);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MATCHER(HasFixIts, "")
|
||||
{
|
||||
return !arg.requiredFixIts.empty();
|
||||
@@ -195,6 +219,12 @@ protected:
|
||||
readFileContent("/complete_smartpointer.cpp"),
|
||||
true
|
||||
};
|
||||
ClangBackEnd::FileContainer completionsOrder{
|
||||
Utf8StringLiteral(TESTDATA_DIR"/completions_order.cpp"),
|
||||
{includePathArgument},
|
||||
readFileContent("/completions_order.cpp"),
|
||||
true
|
||||
};
|
||||
};
|
||||
|
||||
using CodeCompleterSlowTest = CodeCompleter;
|
||||
@@ -306,27 +336,24 @@ TEST_F(CodeCompleterSlowTest, UniquePointerCompletion)
|
||||
{
|
||||
auto myCompleter = setupCompleter(smartPointerCompletion);
|
||||
|
||||
ASSERT_THAT(myCompleter.complete(55, 54, 55, 32),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("Bar"),
|
||||
CodeCompletion::ConstructorCompletionKind)));
|
||||
ASSERT_THAT(myCompleter.complete(59, 54, 59, 32),
|
||||
Contains(IsOverloadCompletion(Utf8StringLiteral("Bar"))));
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, SharedPointerCompletion)
|
||||
{
|
||||
auto myCompleter = setupCompleter(smartPointerCompletion);
|
||||
|
||||
ASSERT_THAT(myCompleter.complete(56, 55, 56, 33),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("Bar"),
|
||||
CodeCompletion::ConstructorCompletionKind)));
|
||||
ASSERT_THAT(myCompleter.complete(60, 55, 60, 33),
|
||||
Contains(IsOverloadCompletion(Utf8StringLiteral("Bar"))));
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, QSharedPointerCompletion)
|
||||
{
|
||||
auto myCompleter = setupCompleter(smartPointerCompletion);
|
||||
|
||||
ASSERT_THAT(myCompleter.complete(57, 60, 57, 32),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("Bar"),
|
||||
CodeCompletion::ConstructorCompletionKind)));
|
||||
ASSERT_THAT(myCompleter.complete(61, 60, 61, 32),
|
||||
Contains(IsOverloadCompletion(Utf8StringLiteral("Bar"))));
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, FunctionInUnsavedIncludedHeader)
|
||||
@@ -499,6 +526,60 @@ TEST_F(CodeCompleterSlowTest, GlobalCompletionAfterForwardDeclaredClassPointer)
|
||||
ASSERT_TRUE(!completions.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, ConstructorCompletionExists)
|
||||
{
|
||||
auto myCompleter = setupCompleter(completionsOrder);
|
||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1);
|
||||
|
||||
int constructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind;
|
||||
});
|
||||
|
||||
ASSERT_THAT(constructorIndex != -1, true);
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, ClassConstructorCompletionsOrder)
|
||||
{
|
||||
auto myCompleter = setupCompleter(completionsOrder);
|
||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1);
|
||||
|
||||
int classIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ClassCompletionKind;
|
||||
});
|
||||
int constructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind;
|
||||
});
|
||||
|
||||
ASSERT_THAT(classIndex < constructorIndex, true);
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, SharedPointerCompletionsOrder)
|
||||
{
|
||||
auto myCompleter = setupCompleter(smartPointerCompletion);
|
||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(62, 11);
|
||||
|
||||
int resetIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "reset";
|
||||
});
|
||||
int barDestructorIndex = Utils::indexOf(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "~Bar";
|
||||
});
|
||||
|
||||
ASSERT_THAT(barDestructorIndex < resetIndex, true);
|
||||
}
|
||||
|
||||
TEST_F(CodeCompleterSlowTest, ConstructorHasOverloadCompletions)
|
||||
{
|
||||
auto myCompleter = setupCompleter(completionsOrder);
|
||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(8, 1);
|
||||
|
||||
int constructorsCount = Utils::count(completions, [](const CodeCompletion &codeCompletion) {
|
||||
return codeCompletion.text == "Constructor" && codeCompletion.completionKind == CodeCompletion::ConstructorCompletionKind;
|
||||
});
|
||||
|
||||
ASSERT_THAT(constructorsCount, 2);
|
||||
}
|
||||
|
||||
ClangBackEnd::CodeCompleter CodeCompleter::setupCompleter(
|
||||
const ClangBackEnd::FileContainer &fileContainer)
|
||||
{
|
||||
|
@@ -794,6 +794,18 @@ TEST_F(CodeCompletionsExtractorSlowTest, OverloadCandidate)
|
||||
})));
|
||||
}
|
||||
|
||||
TEST_F(CodeCompletionsExtractorSlowTest, ExtractAll)
|
||||
{
|
||||
ClangCodeCompleteResults completeResults(getResults(constructorDocument, 25));
|
||||
::CodeCompletionsExtractor extractor(
|
||||
constructorDocument.translationUnit().cxTranslationUnit(),
|
||||
completeResults.data());
|
||||
|
||||
auto codeCompletions = extractor.extractAll(false);
|
||||
|
||||
ASSERT_THAT(codeCompletions.empty(), false);
|
||||
}
|
||||
|
||||
ClangCodeCompleteResults CodeCompletionsExtractor::getResults(const Document &document,
|
||||
uint line,
|
||||
uint column,
|
||||
|
@@ -27,7 +27,11 @@ template<class Type, class... Args>
|
||||
class unique_ptr {};
|
||||
|
||||
template<class Type, class... Args>
|
||||
class shared_ptr {};
|
||||
class shared_ptr {
|
||||
public:
|
||||
void reset();
|
||||
Type *operator->();
|
||||
};
|
||||
|
||||
template<class Type, class... Args>
|
||||
unique_ptr<Type> make_unique(Args&&... args);
|
||||
@@ -55,4 +59,5 @@ void f2()
|
||||
std::unique_ptr<Bar> bar = std::make_unique<Bar>();
|
||||
std::shared_ptr<Bar> bar2 = std::make_shared<Bar>();
|
||||
QSharedPointer<Bar> bar3 = QSharedPointer<Bar>::create();
|
||||
bar2->
|
||||
}
|
||||
|
9
tests/unit/unittest/data/completions_order.cpp
Normal file
9
tests/unit/unittest/data/completions_order.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
class Constructor {
|
||||
public:
|
||||
Constructor() = default;
|
||||
Constructor(int) {}
|
||||
};
|
||||
|
||||
void testConstructor() {
|
||||
|
||||
}
|
Reference in New Issue
Block a user