diff options
author | Leandro Melo <leandro.melo@nokia.com> | 2010-08-13 16:38:45 +0200 |
---|---|---|
committer | Leandro Melo <leandro.melo@nokia.com> | 2010-08-13 16:44:59 +0200 |
commit | f79187ca9772b70a07694becabd936b0184337ed (patch) | |
tree | d196bb186e1c46f6eb3cb6dc5f62422c03874515 /src/plugins/cppeditor/cpphoverhandler.cpp | |
parent | 761a9694f9413bf11425b7f1607a2ae04cf8ab3b (diff) | |
download | qt-creator-f79187ca9772b70a07694becabd936b0184337ed.tar.gz |
Create type hierarchy widget; Refactor code from C++ hover into a simple reusable model.
Hierarchy information removed from tooltips now.
Diffstat (limited to 'src/plugins/cppeditor/cpphoverhandler.cpp')
-rw-r--r-- | src/plugins/cppeditor/cpphoverhandler.cpp | 409 |
1 files changed, 23 insertions, 386 deletions
diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index 0d4d24241b..15922d906e 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -29,6 +29,7 @@ #include "cpphoverhandler.h" #include "cppeditor.h" +#include "cppelementevaluator.h" #include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/editormanager.h> @@ -37,29 +38,9 @@ #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> -#include <FullySpecifiedType.h> -#include <Names.h> -#include <CoreTypes.h> -#include <Scope.h> -#include <Symbol.h> -#include <Symbols.h> -#include <cplusplus/ExpressionUnderCursor.h> -#include <cplusplus/Overview.h> -#include <cplusplus/TypeOfExpression.h> -#include <cplusplus/LookupContext.h> -#include <cplusplus/LookupItem.h> - -#include <QtCore/QSet> -#include <QtCore/QDir> -#include <QtCore/QFileInfo> -#include <QtCore/QtAlgorithms> -#include <QtCore/QStringBuilder> #include <QtGui/QTextCursor> -#include <algorithm> - using namespace CppEditor::Internal; -using namespace CPlusPlus; using namespace Core; namespace { @@ -70,73 +51,13 @@ namespace { else return name.right(name.length() - index - 1); } - - void moveCursorToEndOfName(QTextCursor *tc) { - QTextDocument *doc = tc->document(); - if (!doc) - return; - - QChar ch = doc->characterAt(tc->position()); - while (ch.isLetterOrNumber() || ch == QLatin1Char('_')) { - tc->movePosition(QTextCursor::NextCharacter); - ch = doc->characterAt(tc->position()); - } - } - - void buildClassHierarchyHelper(ClassOrNamespace *classSymbol, - const LookupContext &context, - const Overview &overview, - QList<QStringList> *hierarchy, - QSet<ClassOrNamespace *> *visited) { - visited->insert(classSymbol); - const QList<ClassOrNamespace *> &bases = classSymbol->usings(); - foreach (ClassOrNamespace *baseClass, bases) { - const QList<Symbol *> &symbols = baseClass->symbols(); - foreach (Symbol *baseSymbol, symbols) { - if (baseSymbol->isClass() && ( - classSymbol = context.lookupType(baseSymbol)) && - !visited->contains(classSymbol)) { - const QString &qualifiedName = overview.prettyName( - LookupContext::fullyQualifiedName(baseSymbol)); - if (!qualifiedName.isEmpty()) { - hierarchy->back().append(qualifiedName); - buildClassHierarchyHelper(classSymbol, - context, - overview, - hierarchy, - visited); - hierarchy->append(hierarchy->back()); - hierarchy->back().removeLast(); - } - } - } - } - } - - void buildClassHierarchy(Symbol *symbol, - const LookupContext &context, - const Overview &overview, - QList<QStringList> *hierarchy) { - if (ClassOrNamespace *classSymbol = context.lookupType(symbol)) { - hierarchy->append(QStringList()); - QSet<ClassOrNamespace *> visited; - buildClassHierarchyHelper(classSymbol, context, overview, hierarchy, &visited); - hierarchy->removeLast(); - } - } - - struct ClassHierarchyComp - { - bool operator()(const QStringList &a, const QStringList &b) - { return a.size() < b.size(); } - }; } -CppHoverHandler::CppHoverHandler(QObject *parent) : BaseHoverHandler(parent), m_modelManager(0) -{ - m_modelManager = - ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>(); -} +CppHoverHandler::CppHoverHandler(QObject *parent) : BaseHoverHandler(parent) +{} + +CppHoverHandler::~CppHoverHandler() +{} bool CppHoverHandler::acceptEditor(IEditor *editor) { @@ -148,191 +69,25 @@ bool CppHoverHandler::acceptEditor(IEditor *editor) void CppHoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos) { - if (!m_modelManager) - return; - - const Snapshot &snapshot = m_modelManager->snapshot(); - Document::Ptr doc = snapshot.document(editor->file()->fileName()); - if (!doc) + CPPEditor *cppEditor = qobject_cast<CPPEditor *>(editor->widget()); + if (!cppEditor) return; - int line = 0; - int column = 0; - editor->convertPosition(pos, &line, &column); - - if (!matchDiagnosticMessage(doc, line)) { - if (!matchIncludeFile(doc, line) && !matchMacroInUse(doc, pos)) { - TextEditor::BaseTextEditor *baseEditor = baseTextEditor(editor); - if (!baseEditor) - return; - - bool extraSelectionTooltip = false; - if (!baseEditor->extraSelectionTooltip(pos).isEmpty()) { - setToolTip(baseEditor->extraSelectionTooltip(pos)); - extraSelectionTooltip = true; - } - - QTextCursor tc(baseEditor->document()); - tc.setPosition(pos); - moveCursorToEndOfName(&tc); - - // Fetch the expression's code - ExpressionUnderCursor expressionUnderCursor; - const QString &expression = expressionUnderCursor(tc); - Scope *scope = doc->scopeAt(line, column); - - TypeOfExpression typeOfExpression; - typeOfExpression.init(doc, snapshot); - const QList<LookupItem> &lookupItems = typeOfExpression(expression, scope); - if (lookupItems.isEmpty()) - return; - - const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate. - handleLookupItemMatch(lookupItem, typeOfExpression.context(), !extraSelectionTooltip); - } - } -} - -bool CppHoverHandler::matchDiagnosticMessage(const CPlusPlus::Document::Ptr &document, - unsigned line) -{ - foreach (const Document::DiagnosticMessage &m, document->diagnosticMessages()) { - if (m.line() == line) { - setToolTip(m.text()); - return true; - } - } - return false; -} - -bool CppHoverHandler::matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line) -{ - foreach (const Document::Include &includeFile, document->includes()) { - if (includeFile.line() == line) { - setToolTip(QDir::toNativeSeparators(includeFile.fileName())); - const QString &fileName = QFileInfo(includeFile.fileName()).fileName(); - addHelpCandidate(HelpCandidate(fileName, fileName, HelpCandidate::Brief)); - return true; - } - } - return false; -} - -bool CppHoverHandler::matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos) -{ - foreach (const Document::MacroUse &use, document->macroUses()) { - if (use.contains(pos)) { - const unsigned begin = use.begin(); - const QString &name = use.macro().name(); - if (pos < begin + name.length()) { - setToolTip(use.macro().toString()); - addHelpCandidate(HelpCandidate(name, name, HelpCandidate::Macro)); - return true; - } - } - } - return false; -} - -void CppHoverHandler::handleLookupItemMatch(const LookupItem &lookupItem, - const LookupContext &context, - const bool assignTooltip) -{ - Symbol *matchingDeclaration = lookupItem.declaration(); - FullySpecifiedType matchingType = lookupItem.type(); - - Overview overview; - overview.setShowArgumentNames(true); - overview.setShowReturnTypes(true); - - if (!matchingDeclaration && assignTooltip) { - setToolTip(overview.prettyType(matchingType, QString())); + if (!cppEditor->extraSelectionTooltip(pos).isEmpty()) { + setToolTip(cppEditor->extraSelectionTooltip(pos)); } else { - QString name; - if (matchingDeclaration->scope()->isClass() || - matchingDeclaration->scope()->isNamespace() || - matchingDeclaration->scope()->isEnum()) { - name.append(overview.prettyName( - LookupContext::fullyQualifiedName(matchingDeclaration))); - - if (matchingDeclaration->isClass() || - matchingDeclaration->isForwardClassDeclaration()) { - buildClassHierarchy(matchingDeclaration, context, overview, &m_classHierarchy); - } - } else { - name.append(overview.prettyName(matchingDeclaration->name())); - } - - if (assignTooltip) { - if (matchingDeclaration->isClass() || - matchingDeclaration->isNamespace() || - matchingDeclaration->isForwardClassDeclaration() || - matchingDeclaration->isEnum()) { - setToolTip(name); - } else { - setToolTip(overview.prettyType(matchingType, name)); - } - } - - HelpCandidate::Category helpCategory = HelpCandidate::Unknown; - if (matchingDeclaration->isNamespace() || - matchingDeclaration->isClass() || - matchingDeclaration->isForwardClassDeclaration()) { - helpCategory = HelpCandidate::ClassOrNamespace; - } else if (matchingDeclaration->isEnum() || - matchingDeclaration->scope()->isEnum()) { - helpCategory = HelpCandidate::Enum; - } else if (matchingDeclaration->isTypedef()) { - helpCategory = HelpCandidate::Typedef; - } else if (matchingDeclaration->isFunction() || - (matchingType.isValid() && matchingType->isFunctionType())){ - helpCategory = HelpCandidate::Function; - } else if (matchingDeclaration->isDeclaration() && matchingType.isValid()) { - const Name *typeName = 0; - if (matchingType->isNamedType()) { - typeName = matchingType->asNamedType()->name(); - } else if (matchingType->isPointerType() || matchingType->isReferenceType()) { - FullySpecifiedType type; - if (matchingType->isPointerType()) - type = matchingType->asPointerType()->elementType(); - else - type = matchingType->asReferenceType()->elementType(); - if (type->isNamedType()) - typeName = type->asNamedType()->name(); - } - - if (typeName) { - if (ClassOrNamespace *clazz = context.lookupType(typeName, lookupItem.scope())) { - if (!clazz->symbols().isEmpty()) { - Symbol *symbol = clazz->symbols().at(0); - matchingDeclaration = symbol; - name = overview.prettyName(LookupContext::fullyQualifiedName(symbol)); - setToolTip(name); - buildClassHierarchy(symbol, context, overview, &m_classHierarchy); - helpCategory = HelpCandidate::ClassOrNamespace; - } - } - } - } - - if (helpCategory != HelpCandidate::Unknown) { - QString docMark = overview.prettyName(matchingDeclaration->name()); - - if (matchingType.isValid() && matchingType->isFunctionType()) { - // Functions marks can be found either by the main overload or signature based - // (with no argument names and no return). Help ids have no signature at all. - overview.setShowArgumentNames(false); - overview.setShowReturnTypes(false); - docMark = overview.prettyType(matchingType, docMark); - overview.setShowFunctionSignatures(false); - const QString &functionName = overview.prettyName(matchingDeclaration->name()); - addHelpCandidate(HelpCandidate(functionName, docMark, helpCategory)); - } else if (matchingDeclaration->scope()->isEnum()) { - Symbol *enumSymbol = matchingDeclaration->scope()->asEnum(); - docMark = overview.prettyName(enumSymbol->name()); - } - - addHelpCandidate(HelpCandidate(name, docMark, helpCategory)); + QTextCursor tc(cppEditor->document()); + tc.setPosition(pos); + + CppElementEvaluator evaluator(cppEditor); + evaluator.setTextCursor(tc); + QSharedPointer<CppElement> cppElement = evaluator.identifyCppElement(); + if (!cppElement.isNull()) { + setToolTip(cppElement->tooltip()); + foreach (const QString &helpId, cppElement->helpIdCandidates()) + addHelpCandidate(HelpCandidate(helpId, + cppElement->helpMark(), + cppElement->helpCategory())); } } } @@ -357,121 +112,8 @@ void CppHoverHandler::evaluateHelpCandidates() void CppHoverHandler::decorateToolTip(TextEditor::ITextEditor *editor) { - if (!m_classHierarchy.isEmpty()) - generateDiagramTooltip(extendToolTips(editor)); - else - generateNormalTooltip(extendToolTips(editor)); -} - -void CppHoverHandler::generateDiagramTooltip(const bool extendTooltips) -{ - QString clazz = toolTip(); - - qSort(m_classHierarchy.begin(), m_classHierarchy.end(), ClassHierarchyComp()); - - // Remove duplicates (in case there are any). - m_classHierarchy.erase(std::unique(m_classHierarchy.begin(), m_classHierarchy.end()), - m_classHierarchy.end()); - - QStringList directBaseClasses; - foreach (const QStringList &hierarchy, m_classHierarchy) { - if (hierarchy.size() > 1) - break; - directBaseClasses.append(hierarchy.at(0)); - } - - QString diagram(QLatin1String("<table>")); - for (int i = 0; i < directBaseClasses.size(); ++i) { - if (i == 0) { - diagram.append(QString( - "<tr><td>%1</td><td>" - "<img src=\":/cppeditor/images/rightarrow.png\"></td>" - "<td>%2</td></tr>").arg(toolTip()).arg(directBaseClasses.at(i))); - } else { - diagram.append(QString( - "<tr><td></td><td>" - "<img src=\":/cppeditor/images/larrow.png\"></td>" - "<td>%1</td></tr>").arg(directBaseClasses.at(i))); - } - } - diagram.append(QLatin1String("</table>")); - setToolTip(diagram); - - if (matchingHelpCandidate() != -1) { - appendToolTip(getDocContents(extendTooltips)); - } else { - // Look for documented base classes. Diagram the nearest one or the nearest ones (in - // the case there are many at the same level). - int helpLevel = 0; - QList<int> baseClassesWithHelp; - for (int i = 0; i < m_classHierarchy.size(); ++i) { - const QStringList &hierarchy = m_classHierarchy.at(i); - if (helpLevel != 0 && hierarchy.size() != helpLevel) - break; - - bool exists = false; - QString name = hierarchy.last(); - if (helpIdExists(name)) { - exists = true; - } else { - name = removeClassNameQualification(name); - if (helpIdExists(name)) { - exists = true; - m_classHierarchy[i].last() = name; - } - } - if (exists) { - baseClassesWithHelp.append(i); - if (helpLevel == 0) - helpLevel = hierarchy.size(); - } - } - - if (!baseClassesWithHelp.isEmpty()) { - // Choose the first one as the help match. - QString base = m_classHierarchy.at(baseClassesWithHelp.at(0)).last(); - HelpCandidate help(base, base, HelpCandidate::ClassOrNamespace); - addHelpCandidate(help); - setMatchingHelpCandidate(helpCandidates().size() - 1); - - if (baseClassesWithHelp.size() == 1 && helpLevel == 1) { - appendToolTip(getDocContents(help, extendTooltips)); - } else { - foreach (int hierarchyIndex, baseClassesWithHelp) { - appendToolTip(QLatin1String("<p>")); - const QStringList &hierarchy = m_classHierarchy.at(hierarchyIndex); - Q_ASSERT(helpLevel <= hierarchy.size()); - - // Following contents are inside tables so they are on the exact same - // alignment as the top level diagram. - diagram = QString(QLatin1String("<table><tr><td>%1</td>")).arg(clazz); - for (int i = 0; i < helpLevel; ++i) { - diagram.append( - QLatin1String("<td><img src=\":/cppeditor/images/rightarrow.png\">" - "</td><td>") % - hierarchy.at(i) % - QLatin1String("</td>")); - } - diagram.append(QLatin1String("</tr></table>")); - - base = hierarchy.at(helpLevel - 1); - const QString &contents = - getDocContents(HelpCandidate(base, base, HelpCandidate::Brief), false); - if (!contents.isEmpty()) { - appendToolTip(diagram % QLatin1String("<table><tr><td>") % - contents % QLatin1String("</td></tr></table>")); - } - appendToolTip(QLatin1String("</p>")); - } - } - } - } -} - -void CppHoverHandler::generateNormalTooltip(const bool extendTooltips) -{ if (matchingHelpCandidate() != -1) { - const QString &contents = getDocContents(extendTooltips); + const QString &contents = getDocContents(extendToolTips(editor)); if (!contents.isEmpty()) { HelpCandidate::Category cat = helpCandidate(matchingHelpCandidate()).m_category; if (cat == HelpCandidate::ClassOrNamespace) @@ -486,8 +128,3 @@ void CppHoverHandler::generateNormalTooltip(const bool extendTooltips) } } } - -void CppHoverHandler::resetExtras() -{ - m_classHierarchy.clear(); -} |