From 208c58bf886a29ddbbb4cf6ece69f54c5848602c Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 7 Oct 2014 10:50:08 +0200 Subject: [PATCH] CppEditor: Extract some functions in AddIncludeForUndefinedIdentifier ...to make the high level code path easier to follow. Change-Id: If0ff9a15c9de399286e3a7f59a571949ca8f04de Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfixes.cpp | 150 +++++++++++++----------- 1 file changed, 84 insertions(+), 66 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index b6a4148f561..adea8de2e22 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -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 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 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 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 dummyInterface; QList matches = classesFilter->matchesFor(dummyInterface, className); - bool classExists = false; + bool classFoundInLocator = false; foreach (const Core::LocatorFilterEntry &entry, matches) { IndexItem::Ptr info = entry.internalData.value(); 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('>'); - } - } - - if (!shortestInclude.isEmpty()) - result.append(new AddIncludeForUndefinedIdentifierOp(interface, 0, shortestInclude)); + const QString include = findShortestInclude(doc->fileName(), info->fileName(), headerPaths); + if (!include.isEmpty()) + result.append(new AddIncludeForUndefinedIdentifierOp(interface, 0, include)); } - const bool isProbablyAQtClass = className.size() > 2 - && className.at(0) == QLatin1Char('Q') - && className.at(1).isUpper(); - - if (!isProbablyAQtClass) - return; - - // for QSomething, propose a include -- if such a class was in the locator - if (classExists) { - const QString include = QLatin1Char('<') + className + QLatin1Char('>'); - 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; - } - } + // If e.g. QString was found in "" propose an extra prioritized entry "". + 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)); } }