forked from qt-creator/qt-creator
Clang: Fix unresolved #includes for ui_*.h headers
...with an extra parse.
Previously, the creation of an e.g. "Qt Widgets Application" from the
wizard could show code model errors in mainwindow.cpp. Depending on
timing issues, the first error is either
1. 'ui_mainwindow.h' file not found (QTCREATORBUG-15187)
The parse happened before the in-memory ui_mainwindow.h was
generated by uic. The file system watcher can't help here as the
#include was not resolved successfully. And libclang's reparse does
not handle this case (it would need to remember all failed #include
stats...).
==> Detect this case with the help of the include paths and trigger
a full parse.
2. or: allocation of incomplete type... (QTCREATORBUG-15187)
The parse happened after the generation of the in-memory
ui_mainwindow.h, but before the clangbackend received the unsaved
file.
==> Fix this by also writing the content of the unsaved file to our
behind-the-scenes-created ui_mainwindow.h.
Fixes: QTCREATORBUG-15187
Fixes: QTCREATORBUG-17002
Change-Id: I4f3a81adaa3d604746977a402c29f83fbc5b0e44
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
@@ -37,7 +37,10 @@
|
||||
|
||||
#include <clangcodemodelservermessages.h>
|
||||
|
||||
#include <clangcodemodel/clanguiheaderondiskmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
@@ -119,11 +122,13 @@ protected:
|
||||
int expectedAnnotationsMessages = AnnotationJobsMultiplier);
|
||||
void openDocument(const Utf8String &filePath,
|
||||
const Utf8StringVector &compilationArguments,
|
||||
const Utf8StringVector &headerPaths,
|
||||
int expectedAnnotationsMessages = AnnotationJobsMultiplier);
|
||||
void openDocuments(int expectedAnnotationsMessages);
|
||||
void openDocumentWithUnsavedContent(const Utf8String &filePath, const Utf8String &content);
|
||||
void closeDocument(const Utf8String &filePath);
|
||||
|
||||
void updateUnsavedFile(const Utf8String &filePath, const Utf8String &fileContent);
|
||||
void updateUnsavedContent(const Utf8String &filePath,
|
||||
const Utf8String &fileContent,
|
||||
quint32 revisionNumber);
|
||||
@@ -172,6 +177,8 @@ protected:
|
||||
const Utf8String aFilePath = Utf8StringLiteral("afile.cpp");
|
||||
const Utf8String anExistingFilePath
|
||||
= Utf8StringLiteral(TESTDATA_DIR"/complete_translationunit_parse_error.cpp");
|
||||
|
||||
const Utf8String uicMainPath = Utf8StringLiteral(TESTDATA_DIR"/uicmain.cpp");
|
||||
};
|
||||
|
||||
using ClangCodeModelServerSlowTest = ClangCodeModelServer;
|
||||
@@ -428,6 +435,52 @@ TEST_F(ClangCodeModelServerSlowTest, TakeOverJobsOnDocumentChange)
|
||||
updateVisibilty(filePathC, filePathC); // Enable processing jobs
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, UicHeaderAvailableBeforeParse)
|
||||
{
|
||||
// Write ui file
|
||||
ClangCodeModel::Internal::UiHeaderOnDiskManager uiManager;
|
||||
const QByteArray content = "class UicObject{};";
|
||||
const QString uiHeaderFilePath = uiManager.write("uicheader.h", content);
|
||||
|
||||
// Open document
|
||||
openDocument(uicMainPath,
|
||||
{Utf8StringLiteral("-I"), Utf8String(uiManager.directoryPath())},
|
||||
{uiManager.directoryPath()},
|
||||
AnnotationJobsMultiplier);
|
||||
updateVisibilty(uicMainPath, uicMainPath);
|
||||
ASSERT_TRUE(waitUntilAllJobsFinished());
|
||||
|
||||
// Check
|
||||
ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(),
|
||||
Contains(uiHeaderFilePath));
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, UicHeaderAvailableAfterParse)
|
||||
{
|
||||
ClangCodeModel::Internal::UiHeaderOnDiskManager uiManager;
|
||||
const QString uiHeaderFilePath = uiManager.mapPath("uicheader.h");
|
||||
|
||||
// Open document
|
||||
openDocument(uicMainPath,
|
||||
{Utf8StringLiteral("-I"), Utf8String(uiManager.directoryPath())},
|
||||
{uiManager.directoryPath()},
|
||||
2 * AnnotationJobsMultiplier);
|
||||
updateVisibilty(uicMainPath, uicMainPath);
|
||||
ASSERT_TRUE(waitUntilAllJobsFinished());
|
||||
ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(),
|
||||
Not(Contains(uiHeaderFilePath)));
|
||||
|
||||
// Write ui file and notify backend
|
||||
const QByteArray content = "class UicObject{};";
|
||||
uiManager.write("uicheader.h", content);
|
||||
updateUnsavedFile(Utf8String(uiHeaderFilePath), Utf8String::fromByteArray(content));
|
||||
|
||||
// Check
|
||||
ASSERT_TRUE(waitUntilAllJobsFinished());
|
||||
ASSERT_THAT(documents.document(uicMainPath).dependedFilePaths(),
|
||||
Contains(uiHeaderFilePath));
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::SetUp()
|
||||
{
|
||||
clangServer.setClient(&mockClangCodeModelClient);
|
||||
@@ -454,14 +507,15 @@ bool ClangCodeModelServer::waitUntilAllJobsFinished(int timeOutInMs)
|
||||
void ClangCodeModelServer::openDocument(const Utf8String &filePath,
|
||||
int expectedAnnotationsMessages)
|
||||
{
|
||||
openDocument(filePath, {}, expectedAnnotationsMessages);
|
||||
openDocument(filePath, {}, {}, expectedAnnotationsMessages);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::openDocument(const Utf8String &filePath,
|
||||
const Utf8StringVector &compilationArguments,
|
||||
const Utf8StringVector &headerPaths,
|
||||
int expectedAnnotationsMessages)
|
||||
{
|
||||
const FileContainer fileContainer(filePath, compilationArguments);
|
||||
const FileContainer fileContainer(filePath, compilationArguments, headerPaths);
|
||||
const DocumentsOpenedMessage message({fileContainer}, filePath, {filePath});
|
||||
|
||||
expectAnnotations(expectedAnnotationsMessages);
|
||||
@@ -608,7 +662,7 @@ void ClangCodeModelServer::requestAnnotations(const Utf8String &filePath)
|
||||
|
||||
void ClangCodeModelServer::requestReferences(quint32 documentRevision)
|
||||
{
|
||||
const FileContainer fileContainer{filePathC, Utf8StringVector(), documentRevision};
|
||||
const FileContainer fileContainer{filePathC, {}, {}, documentRevision};
|
||||
const RequestReferencesMessage message{fileContainer, 3, 9};
|
||||
|
||||
clangServer.requestReferences(message);
|
||||
@@ -616,7 +670,7 @@ void ClangCodeModelServer::requestReferences(quint32 documentRevision)
|
||||
|
||||
void ClangCodeModelServer::requestFollowSymbol(quint32 documentRevision)
|
||||
{
|
||||
const FileContainer fileContainer{filePathC, Utf8StringVector(), documentRevision};
|
||||
const FileContainer fileContainer{filePathC, {}, {}, documentRevision};
|
||||
const RequestFollowSymbolMessage message{fileContainer, 43, 9};
|
||||
|
||||
clangServer.requestFollowSymbol(message);
|
||||
@@ -647,7 +701,7 @@ void ClangCodeModelServer::updateUnsavedContent(const Utf8String &filePath,
|
||||
|
||||
void ClangCodeModelServer::removeUnsavedFile(const Utf8String &filePath)
|
||||
{
|
||||
const FileContainer fileContainer(filePath, Utf8StringVector(), 74);
|
||||
const FileContainer fileContainer(filePath, {}, {}, 74);
|
||||
const DocumentsChangedMessage message({fileContainer});
|
||||
|
||||
clangServer.documentsChanged(message);
|
||||
@@ -661,6 +715,15 @@ void ClangCodeModelServer::closeDocument(const Utf8String &filePath)
|
||||
clangServer.documentsClosed(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::updateUnsavedFile(const Utf8String &filePath,
|
||||
const Utf8String &fileContent)
|
||||
{
|
||||
const FileContainer fileContainer(filePath, fileContent, true, 0);
|
||||
const UnsavedFilesUpdatedMessage message({fileContainer});
|
||||
|
||||
clangServer.unsavedFilesUpdated(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::openDocumentAndWaitForFinished(
|
||||
const Utf8String &filePath, int expectedAnnotationsMessages)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user