forked from qt-creator/qt-creator
ClassView: Minimize the mutating API of ParserTreeItem
Make the API of ParserTreeItem const only. Reorganize the code a bit: Transform ParserTreeItem::add() method into private mergeWith() and add a static method ParserTreeItem::mergeTrees(). Remove ParserTreeItem::copy(), as in case of adding projects we may use directly the instance from cache. Remove now unneeded Parser::addProject() and use directly getCachedOrParseProjectTree(). Transform ParserTreeItem::copyTree() into private cloneTree() and make it a const method. Move document symbols parsing code from Parser into ParserTreeItem and add a static method ParserTreeItem::parseDocument(). Remove ParserTreeItem::addChild() and provide instead an overloaded constructor. Allocate QElapedTimer object only when debug is on. Fix some const correctness. Remove some ugly usings. Added some TODOs. Task-number: QTCREATORBUG-25317 Change-Id: I6e7c48bb118b0d826fbb463cae94d59bf43a6938 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -29,6 +29,11 @@
|
||||
#include "classviewconstants.h"
|
||||
#include "classviewutils.h"
|
||||
|
||||
#include <cplusplus/Icons.h>
|
||||
#include <cplusplus/Name.h>
|
||||
#include <cplusplus/Overview.h>
|
||||
#include <cplusplus/Symbol.h>
|
||||
#include <cplusplus/Symbols.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QHash>
|
||||
@@ -42,6 +47,8 @@
|
||||
namespace ClassView {
|
||||
namespace Internal {
|
||||
|
||||
static CPlusPlus::Overview g_overview;
|
||||
|
||||
///////////////////////////////// ParserTreeItemPrivate //////////////////////////////////
|
||||
|
||||
/*!
|
||||
@@ -53,16 +60,121 @@ namespace Internal {
|
||||
class ParserTreeItemPrivate
|
||||
{
|
||||
public:
|
||||
//! symbol locations
|
||||
QSet<SymbolLocation> symbolLocations;
|
||||
void mergeWith(const ParserTreeItem::ConstPtr &target);
|
||||
void mergeSymbol(const CPlusPlus::Symbol *symbol);
|
||||
ParserTreeItem::Ptr cloneTree() const;
|
||||
|
||||
//! symbol information
|
||||
QHash<SymbolInformation, ParserTreeItem::Ptr> symbolInformations;
|
||||
|
||||
//! An icon
|
||||
QSet<SymbolLocation> symbolLocations;
|
||||
QIcon icon;
|
||||
};
|
||||
|
||||
void ParserTreeItemPrivate::mergeWith(const ParserTreeItem::ConstPtr &target)
|
||||
{
|
||||
if (target.isNull())
|
||||
return;
|
||||
|
||||
symbolLocations.unite(target->d->symbolLocations);
|
||||
|
||||
// merge children
|
||||
for (auto it = target->d->symbolInformations.cbegin();
|
||||
it != target->d->symbolInformations.cend(); ++it) {
|
||||
const SymbolInformation &inf = it.key();
|
||||
const ParserTreeItem::Ptr &targetChild = it.value();
|
||||
|
||||
ParserTreeItem::Ptr child = symbolInformations.value(inf);
|
||||
if (!child.isNull()) {
|
||||
child->d->mergeWith(targetChild);
|
||||
} else {
|
||||
const ParserTreeItem::Ptr clone = targetChild.isNull() ? ParserTreeItem::Ptr()
|
||||
: targetChild->d->cloneTree();
|
||||
symbolInformations.insert(inf, clone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParserTreeItemPrivate::mergeSymbol(const CPlusPlus::Symbol *symbol)
|
||||
{
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
// easy solution - lets add any scoped symbol and
|
||||
// any symbol which does not contain :: in the name
|
||||
|
||||
//! \todo collect statistics and reorder to optimize
|
||||
if (symbol->isForwardClassDeclaration()
|
||||
|| symbol->isExtern()
|
||||
|| symbol->isFriend()
|
||||
|| symbol->isGenerated()
|
||||
|| symbol->isUsingNamespaceDirective()
|
||||
|| symbol->isUsingDeclaration()
|
||||
)
|
||||
return;
|
||||
|
||||
const CPlusPlus::Name *symbolName = symbol->name();
|
||||
if (symbolName && symbolName->isQualifiedNameId())
|
||||
return;
|
||||
|
||||
QString name = g_overview.prettyName(symbolName).trimmed();
|
||||
QString type = g_overview.prettyType(symbol->type()).trimmed();
|
||||
int iconType = CPlusPlus::Icons::iconTypeForSymbol(symbol);
|
||||
|
||||
SymbolInformation information(name, type, iconType);
|
||||
|
||||
// If next line will be removed, 5% speed up for the initial parsing.
|
||||
// But there might be a problem for some files ???
|
||||
// Better to improve qHash timing
|
||||
ParserTreeItem::Ptr childItem = symbolInformations.value(information);
|
||||
|
||||
if (childItem.isNull())
|
||||
childItem = ParserTreeItem::Ptr(new ParserTreeItem());
|
||||
|
||||
// locations have 1-based column in Symbol, use the same here.
|
||||
SymbolLocation location(QString::fromUtf8(symbol->fileName() , symbol->fileNameLength()),
|
||||
symbol->line(), symbol->column());
|
||||
|
||||
childItem->d->symbolLocations.insert(location);
|
||||
|
||||
// prevent showing a content of the functions
|
||||
if (!symbol->isFunction()) {
|
||||
if (const CPlusPlus::Scope *scope = symbol->asScope()) {
|
||||
CPlusPlus::Scope::iterator cur = scope->memberBegin();
|
||||
CPlusPlus::Scope::iterator last = scope->memberEnd();
|
||||
while (cur != last) {
|
||||
const CPlusPlus::Symbol *curSymbol = *cur;
|
||||
++cur;
|
||||
if (!curSymbol)
|
||||
continue;
|
||||
|
||||
childItem->d->mergeSymbol(curSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if item is empty and has not to be added
|
||||
if (!symbol->isNamespace() || childItem->childCount())
|
||||
symbolInformations.insert(information, childItem);
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a deep clone of this tree.
|
||||
*/
|
||||
ParserTreeItem::Ptr ParserTreeItemPrivate::cloneTree() const
|
||||
{
|
||||
ParserTreeItem::Ptr newItem(new ParserTreeItem);
|
||||
newItem->d->symbolLocations = symbolLocations;
|
||||
newItem->d->icon = icon;
|
||||
|
||||
for (auto it = symbolInformations.cbegin(); it != symbolInformations.cend(); ++it) {
|
||||
ParserTreeItem::ConstPtr child = it.value();
|
||||
if (child.isNull())
|
||||
continue;
|
||||
newItem->d->symbolInformations.insert(it.key(), child->d->cloneTree());
|
||||
}
|
||||
|
||||
return newItem;
|
||||
}
|
||||
|
||||
///////////////////////////////// ParserTreeItem //////////////////////////////////
|
||||
|
||||
/*!
|
||||
@@ -72,72 +184,22 @@ public:
|
||||
Not virtual - to speed up its work.
|
||||
*/
|
||||
|
||||
ParserTreeItem::ParserTreeItem() :
|
||||
d(new ParserTreeItemPrivate())
|
||||
ParserTreeItem::ParserTreeItem()
|
||||
: d(new ParserTreeItemPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ParserTreeItem::ParserTreeItem(const QHash<SymbolInformation, Ptr> &children)
|
||||
: d(new ParserTreeItemPrivate({children, {}, {}}))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ParserTreeItem::~ParserTreeItem()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
Copies a parser tree item from the location specified by \a from to this
|
||||
item.
|
||||
*/
|
||||
|
||||
void ParserTreeItem::copy(const ParserTreeItem::ConstPtr &from)
|
||||
{
|
||||
if (from.isNull())
|
||||
return;
|
||||
|
||||
d->symbolLocations = from->d->symbolLocations;
|
||||
d->icon = from->d->icon;
|
||||
d->symbolInformations = from->d->symbolInformations;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void copyTree(const ParserTreeItem::ConstPtr &from)
|
||||
Copies a parser tree item with children from the location specified by
|
||||
\a from to this item.
|
||||
*/
|
||||
|
||||
void ParserTreeItem::copyTree(const ParserTreeItem::ConstPtr &target)
|
||||
{
|
||||
if (target.isNull())
|
||||
return;
|
||||
|
||||
// copy content
|
||||
d->symbolLocations = target->d->symbolLocations;
|
||||
d->icon = target->d->icon;
|
||||
d->symbolInformations.clear();
|
||||
|
||||
// reserve memory
|
||||
// int amount = qMin(100 , target->d_ptr->symbolInformations.count() * 2);
|
||||
// d_ptr->symbolInformations.reserve(amount);
|
||||
|
||||
// every child
|
||||
CitSymbolInformations cur = target->d->symbolInformations.constBegin();
|
||||
CitSymbolInformations end = target->d->symbolInformations.constEnd();
|
||||
|
||||
for (; cur != end; ++cur) {
|
||||
ParserTreeItem::Ptr item(new ParserTreeItem());
|
||||
item->copyTree(cur.value());
|
||||
appendChild(item, cur.key());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds information about symbol location from a \location.
|
||||
\sa SymbolLocation, removeSymbolLocation, symbolLocations
|
||||
*/
|
||||
|
||||
void ParserTreeItem::addSymbolLocation(const SymbolLocation &location)
|
||||
{
|
||||
d->symbolLocations.insert(location);
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets information about symbol positions.
|
||||
\sa SymbolLocation, addSymbolLocation, removeSymbolLocation
|
||||
@@ -148,19 +210,6 @@ QSet<SymbolLocation> ParserTreeItem::symbolLocations() const
|
||||
return d->symbolLocations;
|
||||
}
|
||||
|
||||
/*!
|
||||
Appends the child item \a item to \a inf symbol information.
|
||||
*/
|
||||
|
||||
void ParserTreeItem::appendChild(const ParserTreeItem::Ptr &item, const SymbolInformation &inf)
|
||||
{
|
||||
// removeChild must be used to remove an item
|
||||
if (item.isNull())
|
||||
return;
|
||||
|
||||
d->symbolInformations[inf] = item;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the child item specified by \a inf symbol information.
|
||||
*/
|
||||
@@ -197,38 +246,24 @@ void ParserTreeItem::setIcon(const QIcon &icon)
|
||||
d->icon = icon;
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds an internal state with \a target, which contains the correct current
|
||||
state.
|
||||
*/
|
||||
|
||||
void ParserTreeItem::add(const ParserTreeItem::ConstPtr &target)
|
||||
ParserTreeItem::Ptr ParserTreeItem::parseDocument(const CPlusPlus::Document::Ptr &doc)
|
||||
{
|
||||
if (target.isNull())
|
||||
return;
|
||||
Ptr item(new ParserTreeItem());
|
||||
|
||||
// add locations
|
||||
d->symbolLocations = d->symbolLocations.unite(target->d->symbolLocations);
|
||||
const unsigned total = doc->globalSymbolCount();
|
||||
for (unsigned i = 0; i < total; ++i)
|
||||
item->d->mergeSymbol(doc->globalSymbolAt(i));
|
||||
|
||||
// add children
|
||||
// every target child
|
||||
CitSymbolInformations cur = target->d->symbolInformations.constBegin();
|
||||
CitSymbolInformations end = target->d->symbolInformations.constEnd();
|
||||
while (cur != end) {
|
||||
const SymbolInformation &inf = cur.key();
|
||||
const ParserTreeItem::Ptr &targetChild = cur.value();
|
||||
return item;
|
||||
}
|
||||
|
||||
ParserTreeItem::Ptr child = d->symbolInformations.value(inf);
|
||||
if (!child.isNull()) {
|
||||
child->add(targetChild);
|
||||
} else {
|
||||
ParserTreeItem::Ptr add(new ParserTreeItem());
|
||||
add->copyTree(targetChild);
|
||||
d->symbolInformations[inf] = add;
|
||||
}
|
||||
// next item
|
||||
++cur;
|
||||
}
|
||||
ParserTreeItem::Ptr ParserTreeItem::mergeTrees(const QList<ConstPtr> &docTrees)
|
||||
{
|
||||
Ptr item(new ParserTreeItem());
|
||||
for (const ConstPtr &docTree : docTrees)
|
||||
item->d->mergeWith(docTree);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -256,23 +291,14 @@ void ParserTreeItem::convertTo(QStandardItem *item) const
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QMap<SymbolInformation, ParserTreeItem::Ptr> map;
|
||||
|
||||
// convert to map - to sort it
|
||||
CitSymbolInformations curHash = d->symbolInformations.constBegin();
|
||||
CitSymbolInformations endHash = d->symbolInformations.constEnd();
|
||||
while (curHash != endHash) {
|
||||
map.insert(curHash.key(), curHash.value());
|
||||
++curHash;
|
||||
}
|
||||
QMap<SymbolInformation, Ptr> map;
|
||||
for (auto it = d->symbolInformations.cbegin(); it != d->symbolInformations.cend(); ++it)
|
||||
map.insert(it.key(), it.value());
|
||||
|
||||
using MapCitSymbolInformations = QMap<SymbolInformation, ParserTreeItem::Ptr>::const_iterator;
|
||||
// add to item
|
||||
MapCitSymbolInformations cur = map.constBegin();
|
||||
MapCitSymbolInformations end = map.constEnd();
|
||||
while (cur != end) {
|
||||
const SymbolInformation &inf = cur.key();
|
||||
ParserTreeItem::Ptr ptr = cur.value();
|
||||
for (auto it = map.cbegin(); it != map.cend(); ++it) {
|
||||
const SymbolInformation &inf = it.key();
|
||||
Ptr ptr = it.value();
|
||||
|
||||
auto add = new QStandardItem;
|
||||
add->setData(inf.name(), Constants::SymbolNameRole);
|
||||
@@ -291,7 +317,6 @@ void ParserTreeItem::convertTo(QStandardItem *item) const
|
||||
add->setData(locationsToRole(ptr->symbolLocations()), Constants::SymbolLocationsRole);
|
||||
}
|
||||
item->appendRow(add);
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,18 +350,15 @@ void ParserTreeItem::fetchMore(QStandardItem *item) const
|
||||
Debug dump.
|
||||
*/
|
||||
|
||||
void ParserTreeItem::debugDump(int ident) const
|
||||
void ParserTreeItem::debugDump(int indent) const
|
||||
{
|
||||
CitSymbolInformations curHash = d->symbolInformations.constBegin();
|
||||
CitSymbolInformations endHash = d->symbolInformations.constEnd();
|
||||
while (curHash != endHash) {
|
||||
const SymbolInformation &inf = curHash.key();
|
||||
qDebug() << QString(2*ident, QLatin1Char(' ')) << inf.iconType() << inf.name() << inf.type()
|
||||
<< curHash.value().isNull();
|
||||
if (!curHash.value().isNull())
|
||||
curHash.value()->debugDump(ident + 1);
|
||||
|
||||
++curHash;
|
||||
for (auto it = d->symbolInformations.cbegin(); it != d->symbolInformations.cend(); ++it) {
|
||||
const SymbolInformation &inf = it.key();
|
||||
const Ptr &child = it.value();
|
||||
qDebug() << QString(2 * indent, QLatin1Char(' ')) << inf.iconType() << inf.name()
|
||||
<< inf.type() << child.isNull();
|
||||
if (!child.isNull())
|
||||
child->debugDump(indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user