forked from qt-creator/qt-creator
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:
@@ -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);
|
||||
|
||||
|
@@ -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));
|
||||
|
@@ -932,18 +932,28 @@ void ClangCodeCompletionTest::testCompleteConstructorAndFallbackToGlobalCompleti
|
||||
QVERIFY(!hasSnippet(t.proposal, "class"));
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Inserting the dot for this test 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.
|
||||
|
||||
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");
|
||||
|
@@ -48,6 +48,7 @@ private slots:
|
||||
void testCompleteConstructorAndFallbackToGlobalCompletion();
|
||||
|
||||
void testCompleteWithDotToArrowCorrection();
|
||||
void testDontCompleteWithDotToArrowCorrectionForFloats();
|
||||
|
||||
void testCompleteProjectDependingCode();
|
||||
void testCompleteProjectDependingCodeAfterChangingProject();
|
||||
|
@@ -22,5 +22,6 @@
|
||||
<file>objc_messages_3.mm</file>
|
||||
<file>preprocessorKeywordsCompletion.cpp</file>
|
||||
<file>dotToArrowCorrection.cpp</file>
|
||||
<file>noDotToArrowCorrectionForFloats.cpp</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -0,0 +1,4 @@
|
||||
void f()
|
||||
{
|
||||
0 /* COMPLETE HERE */
|
||||
}
|
@@ -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());
|
||||
|
@@ -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("->"));
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -0,0 +1,6 @@
|
||||
struct Foo { int member; };
|
||||
|
||||
void g(Foo *foo)
|
||||
{
|
||||
foo.
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
struct Foo { int member; };
|
||||
|
||||
void g(Foo *foo)
|
||||
{
|
||||
|
||||
}
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user