Commit 208c58bf authored by Nikolai Kosjar's avatar Nikolai Kosjar

CppEditor: Extract some functions in AddIncludeForUndefinedIdentifier

...to make the high level code path easier to follow.

Change-Id: If0ff9a15c9de399286e3a7f59a571949ca8f04de
Reviewed-by: default avatarChristian Stenger <christian.stenger@digia.com>
parent 2835fb03
......@@ -1829,6 +1829,79 @@ void AddIncludeForUndefinedIdentifierOp::perform()
insertNewIncludeDirective(m_include, file);
}
namespace {
QString findShortestInclude(const QString currentDocumentFilePath,
const QString candidateFilePath,
const ProjectPart::HeaderPaths &headerPaths)
{
QString result;
const QFileInfo fileInfo(candidateFilePath);
if (fileInfo.path() == QFileInfo(currentDocumentFilePath).path()) {
result = QLatin1Char('"') + fileInfo.fileName() + QLatin1Char('"');
} else {
foreach (const ProjectPart::HeaderPath &headerPath, headerPaths) {
if (!candidateFilePath.startsWith(headerPath.path))
continue;
QString relativePath = candidateFilePath.mid(headerPath.path.size());
if (!relativePath.isEmpty() && relativePath.at(0) == QLatin1Char('/'))
relativePath = relativePath.mid(1);
if (result.isEmpty() || relativePath.size() + 2 < result.size())
result = QLatin1Char('<') + relativePath + QLatin1Char('>');
}
}
return result;
}
QString findIncludeForQtClass(const QString &className,
const ProjectPart::HeaderPaths &headerPaths,
bool classFoundInLocator)
{
QString result;
// for QSomething, propose a <QSomething> include -- if such a class was in the locator
if (classFoundInLocator) {
result = QLatin1Char('<') + className + QLatin1Char('>');
// otherwise, check for a header file with the same name in the Qt include paths
} else {
foreach (const ProjectPart::HeaderPath &headerPath, headerPaths) {
if (!headerPath.path.contains(QLatin1String("/Qt"))) // "QtCore", "QtGui" etc...
continue;
const QString headerPathCandidate = headerPath.path + QLatin1Char('/') + className;
const QFileInfo fileInfo(headerPathCandidate);
if (fileInfo.exists() && fileInfo.isFile()) {
result = QLatin1Char('<') + className + QLatin1Char('>');
break;
}
}
}
return result;
}
ProjectPart::HeaderPaths relevantHeaderPaths(const QString &filePath)
{
ProjectPart::HeaderPaths headerPaths;
CppModelManager *modelManager = CppModelManager::instance();
const QList<ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
if (projectParts.isEmpty()) { // Not part of any project, better use all include paths than none
headerPaths += modelManager->headerPaths();
} else {
foreach (const ProjectPart::Ptr &part, projectParts)
headerPaths += part->headerPaths;
}
return headerPaths;
}
} // anonymous namespace
void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
......@@ -1877,84 +1950,29 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa
return;
// find the include paths
ProjectPart::HeaderPaths headerPaths;
CppModelManager *modelManager = CppModelManager::instance();
QList<ProjectInfo> projectInfos = modelManager->projectInfos();
bool inProject = false;
foreach (const ProjectInfo &info, projectInfos) {
foreach (ProjectPart::Ptr part, info.projectParts()) {
foreach (const ProjectFile &file, part->files) {
if (file.path == doc->fileName()) {
inProject = true;
headerPaths += part->headerPaths;
}
}
}
}
if (!inProject) {
// better use all include paths than none
headerPaths = modelManager->headerPaths();
}
const ProjectPart::HeaderPaths headerPaths = relevantHeaderPaths(doc->fileName());
// find a include file through the locator
QFutureInterface<Core::LocatorFilterEntry> dummyInterface;
QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface, className);
bool classExists = false;
bool classFoundInLocator = false;
foreach (const Core::LocatorFilterEntry &entry, matches) {
IndexItem::Ptr info = entry.internalData.value<IndexItem::Ptr>();
if (info->symbolName() != className)
continue;
classExists = true;
const QString &fileName = info->fileName();
const QFileInfo fileInfo(fileName);
classFoundInLocator = true;
// find the shortest way to include fileName given the includePaths
QString shortestInclude;
if (fileInfo.path() == QFileInfo(doc->fileName()).path()) {
shortestInclude = QLatin1Char('"') + fileInfo.fileName() + QLatin1Char('"');
} else {
foreach (const ProjectPart::HeaderPath &headerPath, headerPaths) {
if (!fileName.startsWith(headerPath.path))
continue;
QString relativePath = fileName.mid(headerPath.path.size());
if (!relativePath.isEmpty() && relativePath.at(0) == QLatin1Char('/'))
relativePath = relativePath.mid(1);
if (shortestInclude.isEmpty() || relativePath.size() + 2 < shortestInclude.size())
shortestInclude = QLatin1Char('<') + relativePath + QLatin1Char('>');
const QString include = findShortestInclude(doc->fileName(), info->fileName(), headerPaths);
if (!include.isEmpty())
result.append(new AddIncludeForUndefinedIdentifierOp(interface, 0, include));
}
}
if (!shortestInclude.isEmpty())
result.append(new AddIncludeForUndefinedIdentifierOp(interface, 0, shortestInclude));
}
const bool isProbablyAQtClass = className.size() > 2
&& className.at(0) == QLatin1Char('Q')
&& className.at(1).isUpper();
if (!isProbablyAQtClass)
return;
// for QSomething, propose a <QSomething> include -- if such a class was in the locator
if (classExists) {
const QString include = QLatin1Char('<') + className + QLatin1Char('>');
// If e.g. QString was found in "<qstring.h>" propose an extra prioritized entry "<QString>".
if (className.size() > 2 && className.at(0) == QLatin1Char('Q') && className.at(1).isUpper()) {
const QString include = findIncludeForQtClass(className, headerPaths, classFoundInLocator);
if (!include.isEmpty())
result.append(new AddIncludeForUndefinedIdentifierOp(interface, 1, include));
// otherwise, check for a header file with the same name in the Qt include paths
} else {
foreach (const ProjectPart::HeaderPath &headerPath, headerPaths) {
if (!headerPath.path.contains(QLatin1String("/Qt"))) // "QtCore", "QtGui" etc...
continue;
const QString headerPathCandidate = headerPath.path + QLatin1Char('/') + className;
const QFileInfo fileInfo(headerPathCandidate);
if (fileInfo.exists() && fileInfo.isFile()) {
const QString include = QLatin1Char('<') + className + QLatin1Char('>');
result.append(new AddIncludeForUndefinedIdentifierOp(interface, 1, include));
break;
}
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment