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(); }
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; }
static bool includesQtQuickTest(const CPlusPlus::Document::Ptr &doc, const CppTools::CppModelManager *cppMM) { static QString expectedHeaderPrefix = Utils::HostOsInfo::isMacHost() ? QLatin1String("QtQuickTest.framework/Headers") : QLatin1String("QtQuickTest"); const QList<CPlusPlus::Document::Include> includes = doc->resolvedIncludes(); foreach (const CPlusPlus::Document::Include &inc, includes) { if (inc.unresolvedFileName() == QLatin1String("QtQuickTest/quicktest.h") && inc.resolvedFileName().endsWith( QString::fromLatin1("%1/quicktest.h").arg(expectedHeaderPrefix))) { return true; } } if (cppMM) { foreach (const QString &include, cppMM->snapshot().allIncludesForDocument(doc->fileName())) { if (include.endsWith(QString::fromLatin1("%1/quicktest.h").arg(expectedHeaderPrefix))) return true; } } return false; }
void CppTodoItemsScanner::processDocument(CPlusPlus::Document::Ptr doc) { QList<TodoItem> itemList; CPlusPlus::TranslationUnit *translationUnit = doc->translationUnit(); for (unsigned i = 0; i < translationUnit->commentCount(); ++i) { // Get comment source CPlusPlus::Token token = doc->translationUnit()->commentAt(i); QByteArray source = doc->utf8Source().mid(token.begin(), token.length()).trimmed(); if ((token.kind() == CPlusPlus::T_COMMENT) || (token.kind() == CPlusPlus::T_DOXY_COMMENT)) { // Remove trailing "*/" source = source.left(source.length() - 2); } // Process every line of the comment // TODO: Do not create QStringList, just iterate through a string tracking line endings. const QStringList commentLines = QString::fromUtf8(source).split(QLatin1Char('\n'), QString::SkipEmptyParts); unsigned lineNumber = 0; translationUnit->getPosition(token.begin(), &lineNumber); for (int j = 0; j < commentLines.count(); ++j) { const QString &commentLine = commentLines.at(j); processCommentLine(doc->fileName(), commentLine, lineNumber + j, itemList); } } emit itemsFetched(doc->fileName(), itemList); }
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(); }
// 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; }
void BuiltinEditorDocumentProcessor::onParserFinished(CPlusPlus::Document::Ptr document, CPlusPlus::Snapshot snapshot) { if (document.isNull()) return; if (document->fileName() != filePath()) return; // some other document got updated if (document->editorRevision() != revision()) return; // outdated content, wait for a new document to be parsed if (debug) { qDebug() << "BuiltinEditorDocumentProcessor: document parsed" << document->fileName() << document->editorRevision(); } // Emit ifdefed out blocks const auto ifdefoutBlocks = toTextEditorBlocks(document->skippedBlocks()); emit ifdefedOutBlocksUpdated(revision(), ifdefoutBlocks); // Emit code warnings auto codeWarnings = toTextEditorSelections(document->diagnosticMessages(), textDocument()); emit codeWarningsUpdated(revision(), codeWarnings); emit cppDocumentUpdated(document); m_documentSnapshot = snapshot; const auto source = createSemanticInfoSource(false); QTC_CHECK(source.snapshot.contains(document->fileName())); m_semanticInfoUpdater.updateDetached(source); }
static QString quickTestName(const CPlusPlus::Document::Ptr &doc) { const QList<CPlusPlus::Document::MacroUse> macros = doc->macroUses(); foreach (const CPlusPlus::Document::MacroUse ¯o, macros) { if (!macro.isFunctionLike()) continue; const QByteArray name = macro.macro().name(); if (QuickTestUtils::isQuickTestMacro(name)) { CPlusPlus::Document::Block arg = macro.arguments().at(0); return QLatin1String(CppParser::getFileContent(doc->fileName()) .mid(arg.bytesBegin(), arg.bytesEnd() - arg.bytesBegin())); } } return QString(); }
void CppIncludesIterator::fetchMore() { while (!m_queuedPaths.isEmpty() && m_resultQueue.isEmpty()) { const QString filePath = *m_queuedPaths.begin(); m_queuedPaths.remove(filePath); CPlusPlus::Document::Ptr doc = m_snapshot.document(filePath); if (!doc) continue; foreach (const QString &includedPath, doc->includedFiles()) { if (!m_allResultPaths.contains(includedPath)) { m_allResultPaths.insert(includedPath); m_queuedPaths.insert(includedPath); m_resultQueue.append(includedPath); } } } }
// TODO: Can this be improved? This code is ripped from CppEditor, especially CppElementEvaluater // We cannot depend on this since CppEditor plugin code is internal and requires building the implementation files ourselves CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() { EditorManager *editorManager = EditorManager::instance(); if (!editorManager) return 0; IEditor *editor = editorManager->currentEditor(); if (!editor) return 0; TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor *>(editor); if (!textEditor) return 0; TextEditor::BaseTextEditorWidget *editorWidget = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget()); if (!editorWidget) return 0; QPlainTextEdit *ptEdit = qobject_cast<QPlainTextEdit *>(editor->widget()); if (!ptEdit) return 0; QTextCursor tc; tc = ptEdit->textCursor(); int line = 0; int column = 0; const int pos = tc.position(); editorWidget->convertPosition(pos, &line, &column); const CPlusPlus::Snapshot &snapshot = CPlusPlus::CppModelManagerInterface::instance()->snapshot(); CPlusPlus::Document::Ptr doc = snapshot.document(editor->document()->fileName()); QTC_ASSERT(doc, return 0) // fetch the expression's code CPlusPlus::ExpressionUnderCursor expressionUnderCursor; moveCursorToEndOfName(&tc); const QString &expression = expressionUnderCursor(tc); CPlusPlus::Scope *scope = doc->scopeAt(line, column); CPlusPlus::TypeOfExpression typeOfExpression; typeOfExpression.init(doc, snapshot); const QList<CPlusPlus::LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope); if (lookupItems.isEmpty()) return 0; const CPlusPlus::LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate. return lookupItem.declaration(); }
void CppLocatorData::onDocumentUpdated(const CPlusPlus::Document::Ptr &document) { QMutexLocker locker(&m_pendingDocumentsMutex); int i = 0, ei = m_pendingDocuments.size(); for (; i < ei; ++i) { const CPlusPlus::Document::Ptr &doc = m_pendingDocuments.at(i); if (doc->fileName() == document->fileName() && doc->revision() < document->revision()) { m_pendingDocuments[i] = document; break; } } if (i == ei) m_pendingDocuments.append(document); flushPendingDocument(false); }
bool CppElementEvaluator::matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line) { foreach (const Document::Include &includeFile, document->includes()) { if (includeFile.line() == line) { m_element = QSharedPointer<CppElement>(new CppInclude(includeFile)); return true; } } return false; }
void CppElementEvaluator::checkDiagnosticMessage(const CPlusPlus::Document::Ptr &document, unsigned line) { foreach (const Document::DiagnosticMessage &m, document->diagnosticMessages()) { if (m.line() == line) { m_diagnosis = m.text(); break; } } }
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; }
bool CppElementEvaluator::matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos) { foreach (const Document::MacroUse &use, document->macroUses()) { if (use.contains(pos)) { const unsigned begin = use.begin(); if (pos < begin + use.macro().name().length()) { m_element = QSharedPointer<CppElement>(new CppMacro(use.macro())); return true; } } } return false; }
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface, CPlusPlus::Document::Ptr document, const Core::Id &id) { const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); if (quickTestName(document).isEmpty()) return false; const QString cppFileName = document->fileName(); QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName); if (ppList.isEmpty()) // happens if shutting down while parsing return false; const QString &proFile = ppList.at(0)->projectFile; const QString srcDir = quickTestSrcDir(modelManager, cppFileName); if (srcDir.isEmpty()) return false; const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); bool result = false; foreach (const QmlJS::Document::Ptr &qmlJSDoc, qmlDocs) result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile); return result; }
GTestVisitor::GTestVisitor(CPlusPlus::Document::Ptr doc) : CPlusPlus::ASTVisitor(doc->translationUnit()) , m_document(doc) { }
void CppLocatorFilter::onDocumentUpdated(CPlusPlus::Document::Ptr doc) { m_searchList[doc->fileName()] = search(doc); }
void CppTodoItemsScanner::documentUpdated(CPlusPlus::Document::Ptr doc) { if (shouldProcessFile(doc->fileName())) processDocument(doc); }