Merge remote-tracking branch 'origin/4.0' into 4.1

Conflicts:
	src/plugins/projectexplorer/runconfiguration.h
	tests/unit/unittest/unittest.pro

Change-Id: I3d327b1198df2a7e9268916af9624ce5d21195df
This commit is contained in:
Eike Ziller
2016-06-28 11:42:03 +02:00
15 changed files with 150 additions and 54 deletions

View File

@@ -153,13 +153,16 @@ public:
m_floatButton = new DockWidgetTitleButton(this);
m_floatButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
m_floatButton->setAccessibleName(QDockWidget::tr("Float"));
m_floatButton->setAccessibleDescription(QDockWidget::tr("Undocks and re-attaches the dock widget"));
m_closeButton = new DockWidgetTitleButton(this);
m_closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
#ifndef QT_NO_ACCESSIBILITY
m_floatButton->setAccessibleName(QDockWidget::tr("Float"));
m_floatButton->setAccessibleDescription(QDockWidget::tr("Undocks and re-attaches the dock widget"));
m_closeButton->setAccessibleName(QDockWidget::tr("Close"));
m_closeButton->setAccessibleDescription(QDockWidget::tr("Closes the dock widget"));
#endif
setActive(false);

View File

@@ -613,7 +613,7 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(
QTC_CHECK(m_completions.isEmpty());
m_completions = toAssistProposalItems(completions);
if (m_addSnippets)
if (m_addSnippets && !m_completions.isEmpty())
addSnippets();
setAsyncProposalAvailable(createProposal(neededCorrection));

View File

@@ -932,18 +932,28 @@ void ClangCodeCompletionTest::testCompleteConstructorAndFallbackToGlobalCompleti
QVERIFY(!hasSnippet(t.proposal, "class"));
}
void ClangCodeCompletionTest::testCompleteWithDotToArrowCorrection()
{
// Inserting the dot for this test is important since it will send the editor
// Explicitly Inserting The Dot
// ----------------------------
// Inserting the dot for is important since it will send the editor
// content to the backend and thus generate an unsaved file on the backend
// side. The unsaved file enables us to do the dot to arrow correction.
void ClangCodeCompletionTest::testCompleteWithDotToArrowCorrection()
{
ProjectLessCompletionTest t("dotToArrowCorrection.cpp",
QStringLiteral("."));
QStringLiteral(".")); // See above "Explicitly Inserting The Dot"
QVERIFY(hasItem(t.proposal, "member"));
}
void ClangCodeCompletionTest::testDontCompleteWithDotToArrowCorrectionForFloats()
{
ProjectLessCompletionTest t("noDotToArrowCorrectionForFloats.cpp",
QStringLiteral(".")); // See above "Explicitly Inserting The Dot"
QCOMPARE(t.proposal->size(), 0);
}
void ClangCodeCompletionTest::testCompleteProjectDependingCode()
{
const TestDocument testDocument("completionWithProject.cpp");

View File

@@ -48,6 +48,7 @@ private slots:
void testCompleteConstructorAndFallbackToGlobalCompletion();
void testCompleteWithDotToArrowCorrection();
void testDontCompleteWithDotToArrowCorrectionForFloats();
void testCompleteProjectDependingCode();
void testCompleteProjectDependingCodeAfterChangingProject();

View File

@@ -22,5 +22,6 @@
<file>objc_messages_3.mm</file>
<file>preprocessorKeywordsCompletion.cpp</file>
<file>dotToArrowCorrection.cpp</file>
<file>noDotToArrowCorrectionForFloats.cpp</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,4 @@
void f()
{
0 /* COMPLETE HERE */
}

View File

@@ -173,6 +173,8 @@ class PROJECTEXPLORER_EXPORT Runnable
bool canReUseOutputPane(const std::unique_ptr<Concept> &other) const override
{
if (!other.get())
return false;
if (other->typeId() != typeId())
return false;
auto that = static_cast<const Model<T> *>(other.get());

View File

@@ -68,8 +68,7 @@ CodeCompletions CodeCompleter::complete(uint line, uint column)
translationUnit.cxUnsavedFiles(),
translationUnit.unsavedFilesCount());
if (results.hasNoResultsForDotCompletion() && hasDotAt(line, column - 1))
results = completeWithArrowInsteadOfDot(line, column);
tryDotArrowCorrectionIfNoResults(results, line, column);
return toCodeCompletions(results);
}
@@ -93,13 +92,6 @@ ClangCodeCompleteResults CodeCompleter::complete(uint line,
defaultOptions());
}
bool CodeCompleter::hasDotAt(uint line, uint column) const
{
const UnsavedFile &unsavedFile = translationUnit.unsavedFile();
return unsavedFile.hasCharacterAt(line, column, '.');
}
uint CodeCompleter::defaultOptions() const
{
uint options = CXCodeComplete_IncludeMacros
@@ -111,12 +103,25 @@ uint CodeCompleter::defaultOptions() const
return options;
}
ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line, uint column)
void CodeCompleter::tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
uint line,
uint column)
{
if (results.hasNoResultsForDotCompletion()) {
const UnsavedFile &unsavedFile = translationUnit.unsavedFile();
bool positionIsOk = false;
const uint dotPosition = unsavedFile.toUtf8Position(line, column - 1, &positionIsOk);
if (positionIsOk && unsavedFile.hasCharacterAt(dotPosition, '.'))
results = completeWithArrowInsteadOfDot(line, column, dotPosition);
}
}
ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line,
uint column,
uint dotPosition)
{
ClangCodeCompleteResults results;
const SourceLocation location = translationUnit.sourceLocationAtWithoutReparsing(line, column - 1);
const bool replaced = translationUnit.unsavedFile().replaceAt(location.offset(),
const bool replaced = translationUnit.unsavedFile().replaceAt(dotPosition,
1,
Utf8StringLiteral("->"));

View File

@@ -45,18 +45,20 @@ public:
CompletionCorrection neededCorrection() const;
public: // for tests
bool hasDotAt(uint line, uint column) const;
private:
uint defaultOptions() const;
void tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
uint line,
uint column);
ClangCodeCompleteResults complete(uint line,
uint column,
CXUnsavedFile *unsavedFiles,
unsigned unsavedFileCount);
ClangCodeCompleteResults completeWithArrowInsteadOfDot(uint line, uint column);
ClangCodeCompleteResults completeWithArrowInsteadOfDot(uint line,
uint column,
uint dotPosition);
Utf8String filePath() const;
static void checkCodeCompleteResult(CXCodeCompleteResults *completeResults);

View File

@@ -71,15 +71,24 @@ const char *UnsavedFile::filePath() const
return cxUnsavedFile.Filename;
}
bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const
uint UnsavedFile::toUtf8Position(uint line, uint column, bool *ok) const
{
Utf8PositionFromLineColumn converter(cxUnsavedFile.Contents);
if (converter.find(line, column)) {
const uint utf8Position = converter.position();
return hasCharacterAt(utf8Position, character);
*ok = true;
return converter.position();
}
return false;
*ok = false;
return 0;
}
bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const
{
bool positionIsOk = false;
const uint utf8Position = toUtf8Position(line, column, &positionIsOk);
return positionIsOk && hasCharacterAt(utf8Position, character);
}
bool UnsavedFile::hasCharacterAt(uint position, char character) const

View File

@@ -55,6 +55,7 @@ public:
const char *filePath() const;
// 1-based line and column
uint toUtf8Position(uint line, uint column, bool *ok) const;
bool hasCharacterAt(uint line, uint column, char character) const;
bool hasCharacterAt(uint position, char character) const;
bool replaceAt(uint position, uint length, const Utf8String &replacement);

View File

@@ -112,6 +112,19 @@ protected:
readFileContent(QStringLiteral("/complete_withDotArrowCorrectionForPointer.cpp")),
true
};
ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerBeforeTyping{
Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"),
projectPart.projectPartId(),
readFileContent(QStringLiteral("/complete_withDotArrowCorrectionForPointer_beforeTyping.cpp")),
true
};
ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerAfterTyping{
Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"),
projectPart.projectPartId(),
readFileContent(QStringLiteral("/complete_withDotArrowCorrectionForPointer_afterTyping.cpp")),
true
};
ClangBackEnd::FileContainer dotArrowCorrectionForPointerFileContainerInitial{
Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForPointer.cpp"),
projectPart.projectPartId(),
@@ -313,30 +326,6 @@ TEST_F(CodeCompleter, ArrowCompletion)
ClangBackEnd::CompletionCorrection::NoCorrection);
}
TEST_F(CodeCompleter, HasDotAt)
{
auto myCompleter = setupCompleter(dotArrowCorrectionForPointerFileContainer);
ASSERT_TRUE(myCompleter.hasDotAt(5, 8));
}
TEST_F(CodeCompleter, HasDotAtWithUpdatedUnsavedFile)
{
auto myCompleter = setupCompleter(dotArrowCorrectionForPointerFileContainerInitial);
unsavedFiles.createOrUpdate({dotArrowCorrectionForPointerFileContainerUpdated});
ASSERT_TRUE(myCompleter.hasDotAt(5, 8));
}
TEST_F(CodeCompleter, HasNoDotAtDueToMissingUnsavedFile)
{
const ClangBackEnd::FileContainer fileContainer = dotArrowCorrectionForPointerFileContainer;
translationUnits.create({fileContainer});
ClangBackEnd::CodeCompleter myCompleter(translationUnits.translationUnit(fileContainer));
ASSERT_FALSE(myCompleter.hasDotAt(5, 8));
}
TEST_F(CodeCompleter, DotToArrowCompletionForPointer)
{
auto myCompleter = setupCompleter(dotArrowCorrectionForPointerFileContainer);
@@ -350,6 +339,24 @@ TEST_F(CodeCompleter, DotToArrowCompletionForPointer)
ClangBackEnd::CompletionCorrection::DotToArrowCorrection);
}
TEST_F(CodeCompleter, DotToArrowCompletionForPointerInOutdatedTranslationUnit)
{
auto fileContainerBeforeTyping = dotArrowCorrectionForPointerFileContainerBeforeTyping;
auto myCompleter = setupCompleter(fileContainerBeforeTyping);
auto translationUnit = translationUnits.translationUnit(fileContainerBeforeTyping.filePath(),
fileContainerBeforeTyping.projectPartId());
translationUnit.cxTranslationUnit(); // Parse
unsavedFiles.createOrUpdate({dotArrowCorrectionForPointerFileContainerAfterTyping});
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 9);
ASSERT_THAT(completions,
Contains(IsCodeCompletion(Utf8StringLiteral("member"),
CodeCompletion::VariableCompletionKind)));
ASSERT_THAT(myCompleter.neededCorrection(),
ClangBackEnd::CompletionCorrection::DotToArrowCorrection);
}
TEST_F(CodeCompleter, NoDotToArrowCompletionForObject)
{
auto myCompleter = setupCompleter(noDotArrowCorrectionForObjectFileContainer);

View File

@@ -0,0 +1,6 @@
struct Foo { int member; };
void g(Foo *foo)
{
foo.
}

View File

@@ -0,0 +1,6 @@
struct Foo { int member; };
void g(Foo *foo)
{
}

View File

@@ -34,6 +34,7 @@
using ClangBackEnd::UnsavedFile;
using ClangBackEnd::UnsavedFiles;
using ::testing::Eq;
using ::testing::PrintToString;
namespace {
@@ -150,6 +151,44 @@ TEST_F(UnsavedFile, Replace)
ASSERT_THAT(unsavedFile, IsUnsavedFile(filePath, expectedContent, expectedContent.byteSize()));
}
TEST_F(UnsavedFile, ToUtf8PositionForValidLineColumn)
{
::UnsavedFile unsavedFile(filePath, fileContent);
bool ok = false;
const uint position = unsavedFile.toUtf8Position(1, 1, &ok);
ASSERT_TRUE(ok);
ASSERT_THAT(position, Eq(0));
}
TEST_F(UnsavedFile, ToUtf8PositionForInValidLineColumn)
{
::UnsavedFile unsavedFile(filePath, fileContent);
bool ok = false;
unsavedFile.toUtf8Position(2, 1, &ok);
ASSERT_FALSE(ok);
}
TEST_F(UnsavedFile, ToUtf8PositionForDefaultConstructedUnsavedFile)
{
::UnsavedFile unsavedFile;
bool ok = false;
unsavedFile.toUtf8Position(1, 1, &ok);
ASSERT_FALSE(ok);
}
TEST_F(UnsavedFile, HasNoCharacterForDefaultConstructedUnsavedFile)
{
::UnsavedFile unsavedFile;
ASSERT_FALSE(unsavedFile.hasCharacterAt(0, 'x'));
}
TEST_F(UnsavedFile, HasNoCharacterForTooBigOffset)
{
::UnsavedFile unsavedFile(filePath, fileContent);