// Goto slot invoked by the designer context menu. Either navigates // to an existing slot function or create a new one. bool navigateToSlot(const QString &uiFileName, const QString & /* objectName */, const QString & /* signalSignature */, const QStringList & /* parameterNames */, QString *errorMessage) { // Find the generated header. const QString generatedHeaderFile = generatedHeaderOf(uiFileName); if (generatedHeaderFile.isEmpty()) { *errorMessage = QCoreApplication::translate("Designer", "The generated header of the form '%1' could not be found.\nRebuilding the project might help.").arg(uiFileName); return false; } const CPlusPlus::Snapshot snapshot = CPlusPlus::CppModelManagerInterface::instance()->snapshot(); const DocumentPtr generatedHeaderDoc = snapshot.document(generatedHeaderFile); if (!generatedHeaderDoc) { *errorMessage = QCoreApplication::translate("Designer", "The generated header '%1' could not be found in the code model.\nRebuilding the project might help.").arg(generatedHeaderFile); return false; } // Look for setupUi SearchFunction searchFunc(setupUiC); const SearchFunction::FunctionList funcs = searchFunc(generatedHeaderDoc); if (funcs.size() != 1) { *errorMessage = QString::fromLatin1("Internal error: The function '%1' could not be found in in %2").arg(QLatin1String(setupUiC), generatedHeaderFile); return false; } return true; }
QString AbstractEditorSupport::functionAt(const CppModelManagerInterface *modelManager, const QString &fileName, int line, int column) { const CPlusPlus::Snapshot snapshot = modelManager->snapshot(); const CPlusPlus::Document::Ptr document = snapshot.document(fileName); if (!document) return QString(); if (const CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column)) if (const CPlusPlus::Scope *scope = symbol->enclosingScope()) if (const CPlusPlus::Scope *functionScope = scope->enclosingFunction()) if (const CPlusPlus::Symbol *function = functionScope) { const CPlusPlus::Overview o; QString rc = o.prettyName(function->name()); // Prepend namespace "Foo::Foo::foo()" up to empty root namespace for (const CPlusPlus::Symbol *owner = function->enclosingNamespace(); owner; owner = owner->enclosingNamespace()) { const QString name = o.prettyName(owner->name()); if (name.isEmpty()) { break; } else { rc.prepend(QLatin1String("::")); rc.prepend(name); } } return rc; } return QString(); }
static ClassDocumentPtrPair findClassRecursively(const CPlusPlus::Snapshot &docTable, const Document::Ptr &doc, const QString &className, unsigned maxIncludeDepth, QString *namespaceName) { if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << doc->fileName() << className << maxIncludeDepth; // Check document if (const Class *cl = findClass(doc->globalNamespace(), className, namespaceName)) return ClassDocumentPtrPair(cl, doc); if (maxIncludeDepth) { // Check the includes const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u; foreach (const QString &include, doc->includedFiles()) { const CPlusPlus::Snapshot::const_iterator it = docTable.find(include); if (it != docTable.end()) { const Document::Ptr includeDoc = it.value(); const ClassDocumentPtrPair irc = findClassRecursively(docTable, it.value(), className, recursionMaxIncludeDepth, namespaceName); if (irc.first) return irc; } } } return ClassDocumentPtrPair(0, Document::Ptr()); }
static bool includesQtTest(const CPlusPlus::Document::Ptr &doc, const CppTools::CppModelManager *cppMM) { static QString expectedHeaderPrefix = Utils::HostOsInfo::isMacHost() ? QLatin1String("QtTest.framework/Headers") : QLatin1String("QtTest"); const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes(); foreach (const CPlusPlus::Document::Include &inc, includes) { // TODO this short cut works only for #include <QtTest> // bad, as there could be much more different approaches if (inc.unresolvedFileName() == QLatin1String("QtTest") && inc.resolvedFileName().endsWith( QString::fromLatin1("%1/QtTest").arg(expectedHeaderPrefix))) { return true; } } if (cppMM) { CPlusPlus::Snapshot snapshot = cppMM->snapshot(); const QSet<QString> allIncludes = snapshot.allIncludesForDocument(doc->fileName()); foreach (const QString &include, allIncludes) { if (include.endsWith(QString::fromLatin1("%1/qtest.h").arg(expectedHeaderPrefix))) { return true; } } } return false; }
CPlusPlus::Function *CppFunction::function(int line, int column, const QString &fileName) { const CPlusPlus::Snapshot snapshot = CppTools::CppModelManagerInterface::instance()->snapshot(); const CPlusPlus::Document::Ptr document = snapshot.document(fileName); if (!document) return 0; CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column); if (!symbol) return 0; // Find the enclosing function scope (which might be several levels up, or we might be standing on it) CPlusPlus::Scope *scope; if (symbol->isScope()) scope = symbol->asScope(); else scope = symbol->enclosingScope(); while (scope && !scope->isFunction() ) scope = scope->enclosingScope(); if (!scope) return 0; return scope->asFunction(); }
QList<CPlusPlus::Document::Ptr> Utils::snapshotToList(const CPlusPlus::Snapshot &snapshot) { QList<CPlusPlus::Document::Ptr> documents; CPlusPlus::Snapshot::const_iterator it = snapshot.begin(), end = snapshot.end(); for (; it != end; ++it) documents.append(it.value()); return documents; }
// Inline helper with integer error return codes. static inline int getUninitializedVariablesI(const CPlusPlus::Snapshot &snapshot, const QString &functionName, const QString &file, int line, QStringList *uninitializedVariables) { uninitializedVariables->clear(); // Find document if (snapshot.isEmpty() || functionName.isEmpty() || file.isEmpty() || line < 1) return 1; const CPlusPlus::Snapshot::const_iterator docIt = snapshot.find(file); if (docIt == snapshot.end()) return 2; const CPlusPlus::Document::Ptr doc = docIt.value(); // Look at symbol at line and find its function. Either it is the // function itself or some expression/variable. const CPlusPlus::Symbol *symbolAtLine = doc->lastVisibleSymbolAt(line, 0); if (!symbolAtLine) return 4; // First figure out the function to do a safety name check // and the innermost scope at cursor position const CPlusPlus::Function *function = 0; const CPlusPlus::Scope *innerMostScope = 0; if (symbolAtLine->isFunction()) { function = symbolAtLine->asFunction(); if (function->memberCount() == 1) // Skip over function block if (CPlusPlus::Block *block = function->memberAt(0)->asBlock()) innerMostScope = block; } else { if (const CPlusPlus::Scope *functionScope = symbolAtLine->enclosingFunction()) { function = functionScope->asFunction(); innerMostScope = symbolAtLine->isBlock() ? symbolAtLine->asBlock() : symbolAtLine->enclosingBlock(); } } if (!function || !innerMostScope) return 7; // Compare function names with a bit off fuzz, // skipping modules from a CDB symbol "lib!foo" or namespaces // that the code model does not show at this point CPlusPlus::Overview overview; const QString name = overview.prettyName(function->name()); if (!functionName.endsWith(name)) return 11; if (functionName.size() > name.size()) { const char previousChar = functionName.at(functionName.size() - name.size() - 1).toLatin1(); if (previousChar != ':' && previousChar != '!' ) return 11; } // Starting from the innermost block scope, collect declarations. SeenHash seenHash; blockRecursion(overview, innerMostScope, line, uninitializedVariables, &seenHash); return 0; }
static bool includesGTest(const CPlusPlus::Document::Ptr &doc, const CppTools::CppModelManager *cppMM) { const QString gtestH = QLatin1String("gtest/gtest.h"); foreach (const CPlusPlus::Document::Include &inc, doc->resolvedIncludes()) { if (inc.resolvedFileName().endsWith(gtestH)) return true; } if (cppMM) { const CPlusPlus::Snapshot snapshot = cppMM->snapshot(); foreach (const QString &include, snapshot.allIncludesForDocument(doc->fileName())) { if (include.endsWith(gtestH)) return true; } } return false; }
static bool snapshotContains(const CPlusPlus::Snapshot &snapshot, const QSet<QString> &filePaths) { foreach (const QString &filePath, filePaths) { if (!snapshot.contains(filePath)) { const QString warning = QLatin1String("Missing file in snapshot: ") + filePath; QWARN(qPrintable(warning)); return false; } } return true; }
bool getUninitializedVariables(const CPlusPlus::Snapshot &snapshot, const QString &function, const QString &file, int line, QStringList *uninitializedVariables) { const int rc = getUninitializedVariablesI(snapshot, function, file, line, uninitializedVariables); if (debug) { QString msg; QTextStream str(&msg); str << "getUninitializedVariables() " << function << ' ' << file << ':' << line << " returns (int) " << rc << " '" << uninitializedVariables->join(QString(QLatin1Char(','))) << '\''; if (rc) str << " of " << snapshot.size() << " documents"; qDebug() << msg; } return rc == 0; }
bool QtCreatorIntegration::navigateToSlot(const QString &objectName, const QString &signalSignature, const QStringList ¶meterNames, QString *errorMessage) { const EditorData ed = m_few->activeEditor(); QTC_ASSERT(ed, return false) const QString currentUiFile = ed.formWindowEditor->file()->fileName(); #if 0 return Designer::Internal::navigateToSlot(currentUiFile, objectName, signalSignature, parameterNames, errorMessage); #endif // TODO: we should pass to findDocumentsIncluding an absolute path to generated .h file from ui. // Currently we are guessing the name of ui_<>.h file and pass the file name only to the findDocumentsIncluding(). // The idea is that the .pro file knows if the .ui files is inside, and the .pro file knows it will // be generating the ui_<>.h file for it, and the .pro file knows what the generated file's name and its absolute path will be. // So we should somehow get that info from project manager (?) const QFileInfo fi(currentUiFile); const QString uicedName = QLatin1String("ui_") + fi.completeBaseName() + QLatin1String(".h"); // Retrieve code model snapshot restricted to project of ui file. const ProjectExplorer::Project *uiProject = ProjectExplorer::ProjectExplorerPlugin::instance()->session()->projectForFile(currentUiFile); if (!uiProject) { *errorMessage = tr("Internal error: No project could be found for %1.").arg(currentUiFile); return false; } CPlusPlus::Snapshot docTable = CppModelManagerInterface::instance()->snapshot(); CPlusPlus::Snapshot newDocTable; for (CPlusPlus::Snapshot::iterator it = docTable.begin(); it != docTable.end(); ++it) { const ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::instance()->session()->projectForFile(it.key()); if (project == uiProject) newDocTable.insert(it.value()); } docTable = newDocTable; // take all docs, find the ones that include the ui_xx.h. QList<Document::Ptr> docList = findDocumentsIncluding(docTable, uicedName, true); // change to false when we know the absolute path to generated ui_<>.h file if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << objectName << signalSignature << "Looking for " << uicedName << " returned " << docList.size(); if (docList.isEmpty()) { *errorMessage = tr("No documents matching '%1' could be found.\nRebuilding the project might help.").arg(uicedName); return false; } QDesignerFormWindowInterface *fwi = ed.widgetHost->formWindow(); const QString uiClass = uiClassName(fwi->mainContainer()->objectName()); if (Designer::Constants::Internal::debug) qDebug() << "Checking docs for " << uiClass; // Find the class definition (ui class defined as member or base class) // in the file itself or in the directly included files (order 1). QString namespaceName; const Class *cl = 0; Document::Ptr doc; foreach (const Document::Ptr &d, docList) { const ClassDocumentPtrPair cd = findClassRecursively(docTable, d, uiClass, 1u , &namespaceName); if (cd.first) { cl = cd.first; doc = cd.second; break; } } if (!cl) { *errorMessage = msgClassNotFound(uiClass, docList); return false; } Overview o; const QString className = namespaceName + o.prettyName(cl->name()); if (Designer::Constants::Internal::debug) qDebug() << "Found class " << className << doc->fileName(); const QString functionName = QLatin1String("on_") + objectName + QLatin1Char('_') + signalSignature; const QString functionNameWithParameterNames = addParameterNames(functionName, parameterNames); if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << "Found " << uiClass << doc->fileName() << " checking " << functionName << functionNameWithParameterNames; int line = 0; Document::Ptr sourceDoc; if (Function *fun = findDeclaration(cl, functionName)) { sourceDoc = findDefinition(fun, &line); if (!sourceDoc) { // add function definition to cpp file sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line); } } else { // add function declaration to cl CppModelManagerInterface::WorkingCopy workingCopy = CppModelManagerInterface::instance()->workingCopy(); const QString fileName = doc->fileName(); getParsedDocument(fileName, workingCopy, docTable); addDeclaration(docTable, fileName, cl, functionNameWithParameterNames); // add function definition to cpp file sourceDoc = addDefinition(docTable, fileName, className, functionNameWithParameterNames, &line); } if (!sourceDoc) { *errorMessage = tr("Unable to add the method definition."); return false; } // jump to function definition, position within code TextEditor::BaseTextEditorWidget::openEditorAt(sourceDoc->fileName(), line + 2, indentation); return true; }