Merge remote-tracking branch 'origin/4.8'

Change-Id: Ife02e25f89a601e066851cddf0e000ac9491fc35
This commit is contained in:
Eike Ziller
2018-10-04 09:39:10 +02:00
54 changed files with 583 additions and 365 deletions

View File

@@ -203,6 +203,8 @@ public:
virtual bool check(bool enable = true);
};
bool Derived2::
// performance-unnecessary-value-param
void use(Base b)
{

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -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));
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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,34 +140,16 @@ 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()) {
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) {
if (items.empty()) {
addAssistProposalItem(items, codeCompletion, name);
} 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);
}
} else {
addAssistProposalItem(items, codeCompletion, name);
}
}
@@ -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));
if (m_sentRequestType == FunctionHintCompletion) {
const CodeCompletion &firstCompletion = completions.front();
if (firstCompletion.completionKind == CodeCompletion::FunctionOverloadCompletionKind) {
setAsyncProposalAvailable(createFunctionHintProposal(completions));
return;
}
// else: Proceed with a normal completion in case:

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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,9 +3302,17 @@ public:
// Write class qualification, if any.
if (matchingClass) {
const Name *name = rewriteName(matchingClass->name(), &env, control);
funcDef.append(printer.prettyName(name));
funcDef.append(QLatin1String("::"));
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.

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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 &registeredDocs = 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();

View File

@@ -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()

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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))

View File

@@ -390,15 +390,15 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
}
QList<FileNode *>
FileNode::scanForFilesWithVersionControls(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory,
const QList<Core::IVersionControl *> &versionControls,
QFutureInterface<QList<FileNode *>> *future)
FileNode::scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory,
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

View File

@@ -36,7 +36,6 @@
#include <functional>
namespace Utils { class MimeType; }
namespace Core { class IVersionControl; }
namespace ProjectExplorer {
@@ -191,10 +190,9 @@ public:
const FileNode *asFileNode() const final { return this; }
static QList<FileNode *>
scanForFilesWithVersionControls(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
const QList<Core::IVersionControl *> &versionControls,
QFutureInterface<QList<FileNode *>> *future = nullptr);
scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
QFutureInterface<QList<FileNode *>> *future = nullptr);
bool supportsAction(ProjectAction action, const Node *node) const override;
private:

View File

@@ -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();
}
}

View File

@@ -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()
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -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"));
}

View File

@@ -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() ?

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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");

View File

@@ -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.

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -40,9 +40,6 @@ public:
static const char *IdPrefix;
private:
void doAdditionalSetup(const ProjectExplorer::RunConfigurationCreationInfo &) override;
QString defaultDisplayName() const;
void updateTargetInformation();
};

View File

@@ -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

View File

@@ -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,

View File

@@ -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";

View File

@@ -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,
column,
funcNameStartLine,
funcNameStartColumn);
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();

View File

@@ -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) {

View File

@@ -50,7 +50,7 @@ public:
bool next();
bool peek(const Utf8String &name);
CodeCompletions extractAll();
CodeCompletions extractAll(bool onlyFunctionOverloads);
const CodeCompletion &currentCodeCompletion() 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:

View File

@@ -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)
{

View File

@@ -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,

View File

@@ -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->
}

View File

@@ -0,0 +1,9 @@
class Constructor {
public:
Constructor() = default;
Constructor(int) {}
};
void testConstructor() {
}