Clang: Clean up exceptions

* Extract common stuff into the base class ClangException
* Remove unused exceptions TranslationUnitParseErrorException and
  TranslationUnitReparseErrorException
* Do not send error messages to the Qt Creator side. The messages were
  only generated when the backend crashed and while it was not yet fully
  re-initialized (e.g. do code completion right after crash where the
  document was not yet registered at the backend).

Change-Id: I91d98d5ef681ad487f7a2fd66f78fa7cd1e958df
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Nikolai Kosjar
2016-09-09 15:18:25 +02:00
parent 26cb17bb65
commit cb0e730bb5
8 changed files with 73 additions and 385 deletions

View File

@@ -188,18 +188,6 @@ void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMes
}
}
void IpcReceiver::translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message)
{
QTC_CHECK(!"Got TranslationUnitDoesNotExistMessage");
qCDebug(log) << "<<< ERROR:" << message;
}
void IpcReceiver::projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message)
{
QTC_CHECK(!"Got ProjectPartsDoNotExistMessage");
qCDebug(log) << "<<< ERROR:" << message;
}
class IpcSender : public IpcSenderInterface
{
public:

View File

@@ -79,8 +79,8 @@ private:
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override;
void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &message) override;
void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &message) override;
void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &) override {}
void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &) override {}
private:
AliveHandler m_aliveHandler;

View File

@@ -115,8 +115,6 @@ void ClangCodeModelServer::registerTranslationUnitsForEditor(const ClangBackEnd:
documents.setVisibleInEditors(message.visibleEditorFilePaths());
processInitialJobsForDocuments(createdDocuments);
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerTranslationUnitsForEditor:" << exception.what();
}
@@ -134,10 +132,6 @@ void ClangCodeModelServer::updateTranslationUnitsForEditor(const UpdateTranslati
updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
}
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const DocumentDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::updateTranslationUnitsForEditor:" << exception.what();
}
@@ -150,10 +144,6 @@ void ClangCodeModelServer::unregisterTranslationUnitsForEditor(const ClangBackEn
try {
documents.remove(message.fileContainers());
unsavedFiles.remove(message.fileContainers());
} catch (const DocumentDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterTranslationUnitsForEditor:" << exception.what();
}
@@ -179,8 +169,6 @@ void ClangCodeModelServer::unregisterProjectPartsForEditor(const UnregisterProje
try {
projects.remove(message.projectPartIds());
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterProjectPartsForEditor:" << exception.what();
}
@@ -195,8 +183,6 @@ void ClangCodeModelServer::registerUnsavedFilesForEditor(const RegisterUnsavedFi
documents.updateDocumentsWithChangedDependencies(message.fileContainers());
updateDocumentAnnotationsTimer.start(updateDocumentAnnotationsTimeOutInMs);
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::registerUnsavedFilesForEditor:" << exception.what();
}
@@ -209,10 +195,6 @@ void ClangCodeModelServer::unregisterUnsavedFilesForEditor(const UnregisterUnsav
try {
unsavedFiles.remove(message.fileContainers());
documents.updateDocumentsWithChangedDependencies(message.fileContainers());
} catch (const DocumentDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::unregisterUnsavedFilesForEditor:" << exception.what();
}
@@ -232,10 +214,6 @@ void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage
jobs().add(jobRequest);
jobs().process();
} catch (const DocumentDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::completeCode:" << exception.what();
}
@@ -254,10 +232,6 @@ void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnot
jobs().add(jobRequest);
jobs().process();
} catch (const DocumentDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) {
qWarning() << "Error in ClangCodeModelServer::requestDocumentAnnotations:" << exception.what();
}

View File

@@ -116,7 +116,7 @@ const Document &Documents::document(const Utf8String &filePath, const Utf8String
auto findIterator = findDocument(filePath, projectPartId);
if (findIterator == documents_.end())
throw DocumentDoesNotExistException(FileContainer(filePath, projectPartId));
throw DocumentDoesNotExistException(filePath, projectPartId);
return *findIterator;
}
@@ -279,16 +279,20 @@ void Documents::checkIfProjectPartsExists(const QVector<FileContainer> &fileCont
void Documents::checkIfDocumentsDoNotExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (hasDocument(fileContainer))
throw DocumentAlreadyExistsException(fileContainer);
if (hasDocument(fileContainer)) {
throw DocumentAlreadyExistsException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
}
void Documents::checkIfDocumentsForFilePathsExist(const QVector<FileContainer> &fileContainers) const
{
for (const FileContainer &fileContainer : fileContainers) {
if (!hasDocumentWithFilePath(fileContainer.filePath()))
throw DocumentDoesNotExistException(fileContainer);
if (!hasDocumentWithFilePath(fileContainer.filePath())) {
throw DocumentDoesNotExistException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
}
@@ -302,8 +306,11 @@ void Documents::removeDocuments(const QVector<FileContainer> &fileContainers)
documents_.erase(removeBeginIterator, documents_.end());
if (!processedFileContainers.isEmpty())
throw DocumentDoesNotExistException(processedFileContainers.first());
if (!processedFileContainers.isEmpty()) {
const FileContainer fileContainer = processedFileContainers.first();
throw DocumentDoesNotExistException(fileContainer.filePath(),
fileContainer.projectPartId());
}
}
} // namespace ClangBackEnd

View File

@@ -27,197 +27,51 @@
namespace ClangBackEnd {
const char *ClangBaseException::what() const Q_DECL_NOEXCEPT
{
return m_info.constData();
}
ProjectPartDoNotExistException::ProjectPartDoNotExistException(
const Utf8StringVector &projectPartIds)
: projectPartIds_(projectPartIds)
{
}
const Utf8StringVector &ProjectPartDoNotExistException::projectPartIds() const
{
return projectPartIds_;
}
const char *ProjectPartDoNotExistException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty())
what_ += Utf8StringLiteral("ProjectPart files ")
+ projectPartIds().join(Utf8StringLiteral(", "))
+ Utf8StringLiteral(" does not exist!");
return what_.constData();
}
DocumentAlreadyExistsException::DocumentAlreadyExistsException(
const FileContainer &fileContainer)
: fileContainer_(fileContainer)
{
m_info += Utf8StringLiteral("ProjectPart files ")
+ projectPartIds.join(Utf8StringLiteral(", "))
+ Utf8StringLiteral(" does not exist!");
}
DocumentAlreadyExistsException::DocumentAlreadyExistsException(
const Utf8String &filePath,
const Utf8String &projectPartId)
: fileContainer_(filePath, projectPartId)
{
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' with the project part id '")
+ projectPartId
+ Utf8StringLiteral("' already exists!");
}
const FileContainer &DocumentAlreadyExistsException::fileContainer() const
DocumentDoesNotExistException::DocumentDoesNotExistException(const Utf8String &filePath,
const Utf8String &projectPartId)
{
return fileContainer_;
}
const char *DocumentAlreadyExistsException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty()) {
what_ += Utf8StringLiteral("Translation unit '")
+ fileContainer_.filePath()
+ Utf8StringLiteral("' with the project part id '")
+ fileContainer_.projectPartId()
+ Utf8StringLiteral("' already exists!");
}
return what_.constData();
}
DocumentDoesNotExistException::DocumentDoesNotExistException(
const FileContainer &fileContainer)
: fileContainer_(fileContainer)
{
}
DocumentDoesNotExistException::DocumentDoesNotExistException(
const Utf8String &filePath,
const Utf8String &projectPartId)
: fileContainer_(filePath, projectPartId)
{
}
const FileContainer &DocumentDoesNotExistException::fileContainer() const
{
return fileContainer_;
}
const char *DocumentDoesNotExistException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty())
what_ += Utf8StringLiteral("Translation unit '")
+ fileContainer_.filePath()
+ Utf8StringLiteral("' with the project part id '")
+ fileContainer_.projectPartId()
+ Utf8StringLiteral("' does not exits!");
return what_.constData();
m_info += Utf8StringLiteral("Document '")
+ filePath
+ Utf8StringLiteral("' with the project part id '")
+ projectPartId
+ Utf8StringLiteral("' does not exits!");
}
DocumentFileDoesNotExistException::DocumentFileDoesNotExistException(
const Utf8String &filePath)
: filePath_(filePath)
{
m_info += Utf8StringLiteral("File ")
+ filePath
+ Utf8StringLiteral(" does not exist in file system!");
}
const Utf8String &DocumentFileDoesNotExistException::filePath() const
DocumentIsNullException::DocumentIsNullException()
{
return filePath_;
}
const char *DocumentFileDoesNotExistException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty())
what_ += Utf8StringLiteral("File ")
+ filePath()
+ Utf8StringLiteral(" does not exist in file system!");
return what_.constData();
}
const char *DocumentIsNullException::what() const Q_DECL_NOEXCEPT
{
return "Tried to access a null TranslationUnit!";
}
TranslationUnitParseErrorException::TranslationUnitParseErrorException(
const Utf8String &filePath,
const Utf8String &projectPartId,
CXErrorCode errorCode)
: filePath_(filePath),
projectPartId_(projectPartId),
errorCode_(errorCode)
{
}
const Utf8String &TranslationUnitParseErrorException::filePath() const
{
return filePath_;
}
const Utf8String &TranslationUnitParseErrorException::projectPartId() const
{
return projectPartId_;
}
#define RETURN_TEXT_FOR_CASE(enumValue) case enumValue: return #enumValue
static const char *errorCodeToText(CXErrorCode errorCode)
{
switch (errorCode) {
RETURN_TEXT_FOR_CASE(CXError_Success);
RETURN_TEXT_FOR_CASE(CXError_Failure);
RETURN_TEXT_FOR_CASE(CXError_Crashed);
RETURN_TEXT_FOR_CASE(CXError_InvalidArguments);
RETURN_TEXT_FOR_CASE(CXError_ASTReadError);
}
return "UnknownCXErrorCode";
}
#undef RETURN_TEXT_FOR_CASE
const char *TranslationUnitParseErrorException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty()) {
what_ += Utf8StringLiteral("clang_parseTranslationUnit() failed for file ")
+ filePath()
+ Utf8StringLiteral(" in project ")
+ projectPartId()
+ Utf8StringLiteral(": ")
+ Utf8String::fromUtf8(errorCodeToText(errorCode_))
+ Utf8StringLiteral(".");
}
return what_.constData();
}
TranslationUnitReparseErrorException::TranslationUnitReparseErrorException(
const Utf8String &filePath,
const Utf8String &projectPartId,
int errorCode)
: filePath_(filePath),
projectPartId_(projectPartId),
errorCode_(errorCode)
{
}
const Utf8String &TranslationUnitReparseErrorException::filePath() const
{
return filePath_;
}
const Utf8String &TranslationUnitReparseErrorException::projectPartId() const
{
return projectPartId_;
}
const char *TranslationUnitReparseErrorException::what() const Q_DECL_NOEXCEPT
{
if (what_.isEmpty()) {
what_ += Utf8StringLiteral("clang_reparseTranslationUnit() failed for file ")
+ filePath()
+ Utf8StringLiteral(" in project ")
+ projectPartId()
+ Utf8StringLiteral(": ")
+ Utf8String::fromString(QString::number(errorCode_))
+ Utf8StringLiteral(".");
}
return what_.constData();
m_info = Utf8String::fromUtf8("Tried to access a null Document!");
}
} // namespace ClangBackEnd

View File

@@ -25,8 +25,6 @@
#pragma once
#include <clangbackendipc/filecontainer.h>
#include <utf8stringvector.h>
#include <clang-c/Index.h>
@@ -35,108 +33,45 @@
namespace ClangBackEnd {
class ProjectPartDoNotExistException : public std::exception
class ClangBaseException : public std::exception
{
public:
const char *what() const Q_DECL_NOEXCEPT override;
protected:
Utf8String m_info;
};
class ProjectPartDoNotExistException : public ClangBaseException
{
public:
ProjectPartDoNotExistException(const Utf8StringVector &projectPartIds);
const Utf8StringVector &projectPartIds() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
Utf8StringVector projectPartIds_;
mutable Utf8String what_;
};
class DocumentAlreadyExistsException : public std::exception
class DocumentAlreadyExistsException : public ClangBaseException
{
public:
DocumentAlreadyExistsException(const FileContainer &fileContainer);
DocumentAlreadyExistsException(const Utf8String &filePath,
const Utf8String &projectPartId);
const FileContainer &fileContainer() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
FileContainer fileContainer_;
mutable Utf8String what_;
};
class DocumentDoesNotExistException : public std::exception
class DocumentDoesNotExistException : public ClangBaseException
{
public:
DocumentDoesNotExistException(const FileContainer &fileContainer);
DocumentDoesNotExistException(const Utf8String &filePath,
const Utf8String &projectPartId);
const FileContainer &fileContainer() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
FileContainer fileContainer_;
mutable Utf8String what_;
};
class DocumentFileDoesNotExistException : public std::exception
class DocumentFileDoesNotExistException : public ClangBaseException
{
public:
DocumentFileDoesNotExistException(const Utf8String &filePath);
const Utf8String &filePath() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
Utf8String filePath_;
mutable Utf8String what_;
};
class DocumentIsNullException : public std::exception
class DocumentIsNullException : public ClangBaseException
{
public:
const char *what() const Q_DECL_NOEXCEPT override;
};
class TranslationUnitParseErrorException : public std::exception
{
public:
TranslationUnitParseErrorException(const Utf8String &filePath,
const Utf8String &projectPartId,
CXErrorCode errorCode);
const Utf8String &filePath() const;
const Utf8String &projectPartId() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
Utf8String filePath_;
Utf8String projectPartId_;
CXErrorCode errorCode_;
mutable Utf8String what_;
};
class TranslationUnitReparseErrorException : public std::exception
{
public:
TranslationUnitReparseErrorException(const Utf8String &filePath,
const Utf8String &projectPartId,
int errorCode);
const Utf8String &filePath() const;
const Utf8String &projectPartId() const;
const char *what() const Q_DECL_NOEXCEPT override;
private:
Utf8String filePath_;
Utf8String projectPartId_;
int errorCode_;
mutable Utf8String what_;
DocumentIsNullException();
};
} // namespace ClangBackEnd

View File

@@ -83,6 +83,21 @@ void TranslationUnitUpdater::removeTranslationUnitIfProjectPartWasChanged()
}
}
#define RETURN_TEXT_FOR_CASE(enumValue) case enumValue: return #enumValue
static const char *errorCodeToText(CXErrorCode errorCode)
{
switch (errorCode) {
RETURN_TEXT_FOR_CASE(CXError_Success);
RETURN_TEXT_FOR_CASE(CXError_Failure);
RETURN_TEXT_FOR_CASE(CXError_Crashed);
RETURN_TEXT_FOR_CASE(CXError_InvalidArguments);
RETURN_TEXT_FOR_CASE(CXError_ASTReadError);
}
return "UnknownCXErrorCode";
}
#undef RETURN_TEXT_FOR_CASE
void TranslationUnitUpdater::createTranslationUnitIfNeeded()
{
if (!m_cxTranslationUnit) {
@@ -109,7 +124,8 @@ void TranslationUnitUpdater::createTranslationUnitIfNeeded()
updateIncludeFilePaths();
updateLastProjectPartChangeTimePoint();
} else {
qWarning() << "Parsing" << m_in.filePath << "failed:" << m_parseErrorCode;
qWarning() << "Parsing" << m_in.filePath << "failed:"
<< errorCodeToText(m_parseErrorCode);
m_out.hasParseOrReparseFailed = true;
}
}

View File

@@ -146,8 +146,6 @@ protected:
void expectCompletionFromFileAUnsavedMethodVersion2();
void expectCompletionWithTicketNumber(quint64 ticketNumber);
void expectNoCompletionWithUnsavedMethod();
void expectTranslationUnitDoesNotExist(const Utf8String &filePath);
void expectProjectPartsDoNoExist(const Utf8StringVector &projectFilePaths);
void expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark();
static const Utf8String unsavedContent(const QString &unsavedFilePath);
@@ -232,22 +230,6 @@ TEST_F(ClangClangCodeModelServer, CodeCompletionDependingOnProject)
completeCodeInFileB();
}
TEST_F(ClangClangCodeModelServer, GetTranslationUnitDoesNotExistForEditorOnNonExistingTranslationUnit)
{
registerProjectPart();
expectTranslationUnitDoesNotExist(aFilePath);
completeCode(aFilePath);
}
TEST_F(ClangClangCodeModelServer, GetTranslationUnitDoesNotExistForCompletingUnregisteredFile)
{
registerProjectPart();
expectTranslationUnitDoesNotExist(anExistingFilePath);
completeCode(anExistingFilePath, 20, 1);
}
TEST_F(ClangClangCodeModelServer, GetCodeCompletionForUnsavedFile)
{
registerProjectPart();
@@ -278,58 +260,6 @@ TEST_F(ClangClangCodeModelServer, GetNewCodeCompletionAfterUpdatingUnsavedFile)
completeCodeInFileA();
}
TEST_F(ClangClangCodeModelServer, GetTranslationUnitDoesNotExistForUnregisterTranslationUnitWithWrongFilePath)
{
registerProjectPart();
expectTranslationUnitDoesNotExist(aFilePath);
unregisterFile(aFilePath);
}
TEST_F(ClangClangCodeModelServer, UnregisterTranslationUnitAndTestFailingCompletion)
{
const int expectedDocumentAnnotationsChangedCount = 1; // Only for registration.
registerProjectAndFileAndWaitForFinished(filePathA, expectedDocumentAnnotationsChangedCount);
unregisterFile(filePathA);
expectTranslationUnitDoesNotExist(filePathA);
completeCodeInFileA();
}
TEST_F(ClangClangCodeModelServer, GetProjectPartDoesNotExistUnregisterProjectPartInexistingProjectPart)
{
expectProjectPartsDoNoExist({aProjectPartId});
unregisterProject(aProjectPartId);
}
TEST_F(ClangClangCodeModelServer, GetProjectPartDoesNotExistRegisterTranslationUnitWithInexistingProjectPart)
{
expectProjectPartsDoNoExist({aProjectPartId});
registerFile(filePathB, aProjectPartId);
}
TEST_F(ClangClangCodeModelServer, GetProjectPartDoesNotExistUnregisterTranslationUnitWithInexistingProjectPart)
{
expectProjectPartsDoNoExist({aProjectPartId});
unregisterFile(filePathB, aProjectPartId);
}
TEST_F(ClangClangCodeModelServer, GetProjectPartDoesNotExistForCompletingProjectPartFile)
{
registerProjectAndFile(filePathB, 1);
expectProjectPartsDoNoExist({aProjectPartId});
completeCode(filePathB, 1, 1, aProjectPartId);
}
TEST_F(ClangClangCodeModelServer, GetProjectPartDoesNotExistForCompletingUnregisteredFile)
{
registerProjectPart();
expectTranslationUnitDoesNotExist(anExistingFilePath);
completeCode(anExistingFilePath);
}
TEST_F(ClangClangCodeModelServer, TicketNumberIsForwarded)
{
registerProjectAndFile(filePathA, 1);
@@ -539,14 +469,6 @@ void ClangClangCodeModelServer::expectNoCompletionWithUnsavedMethod()
.Times(1);
}
void ClangClangCodeModelServer::expectTranslationUnitDoesNotExist(const Utf8String &filePath)
{
const TranslationUnitDoesNotExistMessage message(filePath, projectPartId);
EXPECT_CALL(mockClangCodeModelClient, translationUnitDoesNotExist(message))
.Times(1);
}
void ClangClangCodeModelServer::expectCompletionFromFileA()
{
const CodeCompletion completion(Utf8StringLiteral("Function"),
@@ -618,14 +540,6 @@ void ClangClangCodeModelServer::unregisterProject(const Utf8String &projectPartI
clangServer.unregisterProjectPartsForEditor(message);
}
void ClangClangCodeModelServer::expectProjectPartsDoNoExist(const Utf8StringVector &projectFilePaths)
{
const ProjectPartsDoNotExistMessage message(projectFilePaths);
EXPECT_CALL(mockClangCodeModelClient, projectPartsDoNotExist(message))
.Times(1);
}
void ClangClangCodeModelServer::registerProjectPart()
{
RegisterProjectPartsForEditorMessage message({ProjectPartContainer(projectPartId)});