void SourceView::selectedSlot(QListViewItem * i) { if (!i) return; // programatically selected items are not signalled if (_inSelectionUpdate) return; TraceLineCall* lc = ((SourceItem*) i)->lineCall(); TraceLineJump* lj = ((SourceItem*) i)->lineJump(); if (!lc && !lj) { TraceLine* l = ((SourceItem*) i)->line(); if (l) { _selectedItem = l; selected(l); } return; } TraceFunction* f = lc ? lc->call()->called() : 0; if (f) { _selectedItem = f; selected(f); } else { TraceLine* line = lj ? lj->lineTo() : 0; if (line) { _selectedItem = line; selected(line); } } }
void SourceView::context(QListViewItem* i, const QPoint & p, int c) { QPopupMenu popup; // Menu entry: TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0; TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0; TraceFunction* f = lc ? lc->call()->called() : 0; TraceLine* line = lj ? lj->lineTo() : 0; if (f) { QString name = f->name(); if ((int)name.length()>Configuration::maxSymbolLength()) name = name.left(Configuration::maxSymbolLength()) + "..."; popup.insertItem(i18n("Go to '%1'").arg(name), 93); popup.insertSeparator(); } else if (line) { popup.insertItem(i18n("Go to Line %1").arg(line->name()), 93); popup.insertSeparator(); } if ((c == 1) || (c == 2)) { addCostMenu(&popup); popup.insertSeparator(); } addGoMenu(&popup); int r = popup.exec(p); if (r == 93) { if (f) activated(f); if (line) activated(line); } }
void SourceView::activatedSlot(QListViewItem * i) { if (!i) return; TraceLineCall* lc = ((SourceItem*) i)->lineCall(); TraceLineJump* lj = ((SourceItem*) i)->lineJump(); if (!lc && !lj) { TraceLine* l = ((SourceItem*) i)->line(); if (l) activated(l); return; } TraceFunction* f = lc ? lc->call()->called() : 0; if (f) activated(f); else { TraceLine* line = lj ? lj->lineTo() : 0; if (line) activated(line); } }
/** * The main import function... */ int CachegrindLoader::loadInternal(TraceData* data, QIODevice* device, const QString& filename) { if (!data || !device) return 0; _data = data; _filename = filename; _lineNo = 0; loadStart(_filename); FixFile file(device, _filename); if (!file.exists()) { loadFinished(QStringLiteral("File does not exist")); return 0; } int statusProgress = 0; #if USE_FIXCOST // FixCost Memory Pool FixPool* pool = _data->fixPool(); #endif _part = 0; partsAdded = 0; prepareNewPart(); FixString line; char c; // current position nextLineType = SelfCost; // default if there is no "positions:" line hasLineInfo = true; hasAddrInfo = false; while (file.nextLine(line)) { _lineNo++; #if TRACE_LOADER qDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo << " - '" << QString(line) << "'"; #endif // if we cannot strip a character, this was an empty line if (!line.first(c)) continue; if (c <= '9') { if (c == '#') continue; // parse position(s) if (!parsePosition(line, currentPos)) { error(QStringLiteral("Invalid position specification '%1'").arg(line)); continue; } // go through after big switch } else { // if (c > '9') line.stripFirst(c); /* in order of probability */ switch(c) { case 'f': // fl= if (line.stripPrefix("l=")) { setFile(line); // this is the default for new functions currentFunctionFile = currentFile; continue; } // fi=, fe= if (line.stripPrefix("i=") || line.stripPrefix("e=")) { setFile(line); continue; } // fn= if (line.stripPrefix("n=")) { if (currentFile != currentFunctionFile) currentFile = currentFunctionFile; setFunction(line); // on a new function, update status int progress = (int)(100.0 * file.current() / file.len() +.5); if (progress != statusProgress) { statusProgress = progress; /* When this signal is connected, it most probably * should lead to GUI update. Thus, when multiple * "long operations" (like file loading) are in progress, * this can temporarly switch to another operation. */ loadProgress(statusProgress); } continue; } break; case 'c': // cob= if (line.stripPrefix("ob=")) { setCalledObject(line); continue; } // cfi= / cfl= if (line.stripPrefix("fl=") || line.stripPrefix("fi=")) { setCalledFile(line); continue; } // cfn= if (line.stripPrefix("fn=")) { setCalledFunction(line); continue; } // calls= if (line.stripPrefix("alls=")) { // ignore long lines... line.stripUInt64(currentCallCount); nextLineType = CallCost; continue; } // cmd: if (line.stripPrefix("md:")) { QString command = QString(line).trimmed(); if (!_data->command().isEmpty() && _data->command() != command) { error(QStringLiteral("Redefined command, was '%1'").arg(_data->command())); } _data->setCommand(command); continue; } // creator: if (line.stripPrefix("reator:")) { // ignore ... continue; } break; case 'j': // jcnd= if (line.stripPrefix("cnd=")) { bool valid; valid = line.stripUInt64(jumpsFollowed) && line.stripPrefix("/") && line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jcnd'")); } else nextLineType = CondJump; continue; } if (line.stripPrefix("ump=")) { bool valid; valid = line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jump'")); } else nextLineType = BoringJump; continue; } // jfi= if (line.stripPrefix("fi=")) { currentJumpToFile = compressedFile(line); continue; } // jfn= if (line.stripPrefix("fn=")) { if (!currentJumpToFile) { // !=0 as functions needs file currentJumpToFile = currentFile; } currentJumpToFunction = compressedFunction(line, currentJumpToFile, currentObject); continue; } break; case 'o': // ob= if (line.stripPrefix("b=")) { setObject(line); continue; } break; case '#': continue; case 'a': // "arch: arm" if (line.stripPrefix("rch: arm")) { TraceData::Arch a = _data->architecture(); if ((a != TraceData::ArchUnknown) && (a != TraceData::ArchARM)) { error(QStringLiteral("Redefined architecture!")); } _data->setArchitecture(TraceData::ArchARM); continue; } break; case 't': // totals: if (line.stripPrefix("otals:")) continue; // thread: if (line.stripPrefix("hread:")) { prepareNewPart(); _part->setThreadID(QString(line).toInt()); continue; } // timeframe (BB): if (line.stripPrefix("imeframe (BB):")) { _part->setTimeframe(line); continue; } break; case 'd': // desc: if (line.stripPrefix("esc:")) { line.stripSurroundingSpaces(); // desc: Trigger: if (line.stripPrefix("Trigger:")) { _part->setTrigger(line); } continue; } break; case 'e': // events: if (line.stripPrefix("vents:")) { prepareNewPart(); mapping = _data->eventTypes()->createMapping(line); _part->setEventMapping(mapping); continue; } // event:<name>[=<formula>][:<long name>] if (line.stripPrefix("vent:")) { line.stripSurroundingSpaces(); FixString e, f, l; if (!line.stripName(e)) { error(QStringLiteral("Invalid event")); continue; } line.stripSpaces(); if (!line.stripFirst(c)) continue; if (c=='=') f = line.stripUntil(':'); line.stripSpaces(); // add to known cost types if (line.isEmpty()) line = e; EventType::add(new EventType(e,line,f)); continue; } break; case 'p': // part: if (line.stripPrefix("art:")) { prepareNewPart(); _part->setPartNumber(QString(line).toInt()); continue; } // pid: if (line.stripPrefix("id:")) { prepareNewPart(); _part->setProcessID(QString(line).toInt()); continue; } // positions: if (line.stripPrefix("ositions:")) { prepareNewPart(); QString positions(line); hasLineInfo = positions.contains(QStringLiteral("line")); hasAddrInfo = positions.contains(QStringLiteral("instr")); continue; } break; case 'v': // version: if (line.stripPrefix("ersion:")) { // ignore for now continue; } break; case 's': // summary: if (line.stripPrefix("ummary:")) { if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } _part->totals()->set(mapping, line); continue; } case 'r': // rcalls= (deprecated) if (line.stripPrefix("calls=")) { // handle like normal calls: we need the sum of call count // recursive cost is discarded in cycle detection line.stripUInt64(currentCallCount); nextLineType = CallCost; warning(QStringLiteral("Old file format using deprecated 'rcalls'")); continue; } break; default: break; } error(QStringLiteral("Invalid line '%1%2'").arg(c).arg(line)); continue; } if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } // for a cost line, we always need a current function ensureFunction(); if (!currentFunctionSource || (currentFunctionSource->file() != currentFile)) { currentFunctionSource = currentFunction->sourceFile(currentFile, true); } #if !USE_FIXCOST if (hasAddrInfo) { if (!currentInstr || (currentInstr->addr() != currentPos.fromAddr)) { currentInstr = currentFunction->instr(currentPos.fromAddr, true); if (!currentInstr) { error(QString("Invalid address '%1'").arg(currentPos.fromAddr.toString())); continue; } currentPartInstr = currentInstr->partInstr(_part, currentPartFunction); } } if (hasLineInfo) { if (!currentLine || (currentLine->lineno() != currentPos.fromLine)) { currentLine = currentFunctionSource->line(currentPos.fromLine, true); currentPartLine = currentLine->partLine(_part, currentPartFunction); } if (hasAddrInfo && currentInstr) currentInstr->setLine(currentLine); } #endif #if TRACE_LOADER qDebug() << _filename << ":" << _lineNo; qDebug() << " currentInstr " << (currentInstr ? qPrintable(currentInstr->toString()) : "."); qDebug() << " currentLine " << (currentLine ? qPrintable(currentLine->toString()) : ".") << "( file " << currentFile->name() << ")"; qDebug() << " currentFunction " << qPrintable(currentFunction->prettyName()); qDebug() << " currentCalled " << (currentCalledFunction ? qPrintable(currentCalledFunction->prettyName()) : "."); #endif // create cost item if (nextLineType == SelfCost) { #if USE_FIXCOST new (pool) FixCost(_part, pool, currentFunctionSource, currentPos, currentPartFunction, line); #else if (hasAddrInfo) { TracePartInstr* partInstr; partInstr = currentInstr->partInstr(_part, currentPartFunction); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstr->addCost(mapping, line); line.set(s,l); } else partInstr->addCost(mapping, line); } if (hasLineInfo) { TracePartLine* partLine; partLine = currentLine->partLine(_part, currentPartFunction); partLine->addCost(mapping, line); } #endif if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of cost line ('%1')").arg(line)); } } else if (nextLineType == CallCost) { nextLineType = SelfCost; TraceCall* calling = currentFunction->calling(currentCalledFunction); TracePartCall* partCalling = calling->partCall(_part, currentPartFunction, currentCalledPartFunction); #if USE_FIXCOST FixCallCost* fcc; fcc = new (pool) FixCallCost(_part, pool, currentFunctionSource, hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : Addr(0), partCalling, currentCallCount, line); fcc->setMax(_data->callMax()); _data->updateMaxCallCount(fcc->callCount()); #else if (hasAddrInfo) { TraceInstrCall* instrCall; TracePartInstrCall* partInstrCall; instrCall = calling->instrCall(currentInstr); partInstrCall = instrCall->partInstrCall(_part, partCalling); partInstrCall->addCallCount(currentCallCount); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstrCall->addCost(mapping, line); line.set(s,l); } else partInstrCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partInstrCall); _data->updateMaxCallCount(partInstrCall->callCount()); } if (hasLineInfo) { TraceLineCall* lineCall; TracePartLineCall* partLineCall; lineCall = calling->lineCall(currentLine); partLineCall = lineCall->partLineCall(_part, partCalling); partLineCall->addCallCount(currentCallCount); partLineCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partLineCall); _data->updateMaxCallCount(partLineCall->callCount()); } #endif currentCalledFile = 0; currentCalledPartFile = 0; currentCalledObject = 0; currentCalledPartObject = 0; currentCallCount = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of call cost line ('%1')").arg(line)); } } else { // (nextLineType == BoringJump || nextLineType == CondJump) TraceFunctionSource* targetSource; if (!currentJumpToFunction) currentJumpToFunction = currentFunction; targetSource = (currentJumpToFile) ? currentJumpToFunction->sourceFile(currentJumpToFile, true) : currentFunctionSource; #if USE_FIXCOST new (pool) FixJump(_part, pool, /* source */ hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : 0, currentPartFunction, currentFunctionSource, /* target */ hasLineInfo ? targetPos.fromLine : 0, hasAddrInfo ? targetPos.fromAddr : Addr(0), currentJumpToFunction, targetSource, (nextLineType == CondJump), jumpsExecuted, jumpsFollowed); #else if (hasAddrInfo) { TraceInstr* jumpToInstr; TraceInstrJump* instrJump; TracePartInstrJump* partInstrJump; jumpToInstr = currentJumpToFunction->instr(targetPos.fromAddr, true); instrJump = currentInstr->instrJump(jumpToInstr, (nextLineType == CondJump)); partInstrJump = instrJump->partInstrJump(_part); partInstrJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partInstrJump->addFollowedCount(jumpsFollowed); } if (hasLineInfo) { TraceLine* jumpToLine; TraceLineJump* lineJump; TracePartLineJump* partLineJump; jumpToLine = targetSource->line(targetPos.fromLine, true); lineJump = currentLine->lineJump(jumpToLine, (nextLineType == CondJump)); partLineJump = lineJump->partLineJump(_part); partLineJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partLineJump->addFollowedCount(jumpsFollowed); } #endif if (0) { qDebug() << _filename << ":" << _lineNo << " - jump from 0x" << currentPos.fromAddr.toString() << " (line " << currentPos.fromLine << ") to 0x" << targetPos.fromAddr.toString() << " (line " << targetPos.fromLine << ")"; if (nextLineType == BoringJump) qDebug() << " Boring Jump, count " << jumpsExecuted.pretty(); else qDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty() << ", executed " << jumpsExecuted.pretty(); } nextLineType = SelfCost; currentJumpToFunction = 0; currentJumpToFile = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of jump cost line ('%1')").arg(line)); } } } loadFinished(); if (mapping) { _part->invalidate(); _part->totals()->clear(); _part->totals()->addCost(_part); data->addPart(_part); partsAdded++; } else { delete _part; } device->close(); return partsAdded; }
void SourceItemDelegate::paintArrows(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { QTreeWidget *lv = _parent; if ( !lv ) return; SourceView* sv = (SourceView*) lv; SourceItem* item = static_cast<SourceItem*>(index.internalPointer()); const QRect& rect = option.rect; int height = rect.height(); p->save(); drawBackground(p, option, index); p->translate(rect.topLeft()); int marg = 1; int yy = height/2, y1, y2; QColor c; int start = -1, end = -1; TraceLineJump* lineJump = item->lineJump(); uint lineno = item->lineno(); TraceLineCall* lineCall = item->lineCall(); // draw line borders, detect start/stop of a line for(int i=0; i< item->jumpCount(); i++) { TraceLineJump* jump = item->jump(i); if (jump == 0) continue; y1 = 0; y2 = height; if (lineJump && (lineJump->lineTo() == jump->lineTo()) && (jump->lineFrom()->lineno() == lineno)) { if (start<0) start = i; if (lineJump == jump) { if (jump->lineTo()->lineno() <= lineno) y2 = yy; else y1 = yy; } } else if (!lineJump && !lineCall && (jump->lineTo()->lineno() == lineno)) { if (end<0) end = i; if (jump->lineFrom()->lineno() < lineno) y2 = yy; else y1 = yy; } c = jump->isCondJump() ? Qt::red : Qt::blue; p->fillRect( marg + 6*i, y1, 4, y2, c); p->setPen(c.light()); p->drawLine( marg + 6*i, y1, marg + 6*i, y2); p->setPen(c.dark()); p->drawLine( marg + 6*i +3, y1, marg + 6*i +3, y2); } // draw start/stop horizontal line int x, y = yy-2, w, h = 4; if (start >= 0) { c = item->jump(start)->isCondJump() ? Qt::red : Qt::blue; x = marg + 6*start; w = 6*(sv->arrowLevels() - start) + 10; p->fillRect( x, y, w, h, c); p->setPen(c.light()); p->drawLine(x, y, x+w-1, y); p->drawLine(x, y, x, y+h-1); p->setPen(c.dark()); p->drawLine(x+w-1, y, x+w-1, y+h-1); p->drawLine(x+1, y+h-1, x+w-1, y+h-1); } if (end >= 0) { c = item->jump(end)->isCondJump() ? Qt::red : Qt::blue; x = marg + 6*end; w = 6*(sv->arrowLevels() - end) + 10; QPolygon a; a.putPoints(0, 8, x,y+h, x,y, x+w-8,y, x+w-8,y-2, x+w,yy, x+w-8,y+h+2, x+w-8,y+h, x,y+h); p->setBrush(c); p->drawConvexPolygon(a); p->setPen(c.light()); p->drawPolyline(a.constData(), 5); p->setPen(c.dark()); p->drawPolyline(a.constData() + 4, 2); p->setPen(c.light()); p->drawPolyline(a.constData() + 5, 2); p->setPen(c.dark()); p->drawPolyline(a.constData() + 6, 2); } // draw inner vertical line for start/stop // this overwrites borders of horizontal line for(int i=0;i< item->jumpCount();i++) { TraceLineJump* jump = item->jump(i); if (jump == 0) continue; c = jump->isCondJump() ? Qt::red : Qt::blue; if (jump->lineFrom()->lineno() == lineno) { bool drawUp = true; if (jump->lineTo()->lineno() == lineno) if (start<0) drawUp = false; if (jump->lineTo()->lineno() > lineno) drawUp = false; if (drawUp) p->fillRect( marg + 6*i +1, 0, 2, yy, c); else p->fillRect( marg + 6*i +1, yy, 2, height-yy, c); } else if (jump->lineTo()->lineno() == lineno) { if (end<0) end = i; if (jump->lineFrom()->lineno() < lineno) p->fillRect( marg + 6*i +1, 0, 2, yy, c); else p->fillRect( marg + 6*i +1, yy, 2, height-yy, c); } } p->restore(); }
/* If sourceList is empty we set the source file name into the header, * else this code is of a inlined function, and we add "inlined from..." */ void SourceView::fillSourceFile(TraceFunctionSource* sf, int fileno) { if (!sf) return; if (0) qDebug("Selected Item %s", _selectedItem ? _selectedItem->name().ascii() : "(none)"); TraceLineMap::Iterator lineIt, lineItEnd; int nextCostLineno = 0, lastCostLineno = 0; bool validSourceFile = (!sf->file()->name().isEmpty()); TraceLine* sLine = 0; if (_selectedItem) { if (_selectedItem->type() == TraceItem::Line) sLine = (TraceLine*) _selectedItem; if (_selectedItem->type() == TraceItem::Instr) sLine = ((TraceInstr*)_selectedItem)->line(); } if (validSourceFile) { TraceLineMap* lineMap = sf->lineMap(); if (lineMap) { lineIt = lineMap->begin(); lineItEnd = lineMap->end(); // get first line with cost of selected type while(lineIt != lineItEnd) { if (&(*lineIt) == sLine) break; if ((*lineIt).hasCost(_costType)) break; if (_costType2 && (*lineIt).hasCost(_costType2)) break; ++lineIt; } nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno(); if (nextCostLineno<0) { kdError() << "SourceView::fillSourceFile: Negative line number " << nextCostLineno << endl << " Function '" << sf->function()->name() << "'" << endl << " File '" << sf->file()->name() << "'" << endl; nextCostLineno = 0; } } if (nextCostLineno == 0) { new SourceItem(this, this, fileno, 0, false, i18n("There is no cost of current selected type associated")); new SourceItem(this, this, fileno, 1, false, i18n("with any source line of this function in file")); new SourceItem(this, this, fileno, 2, false, QString(" '%1'").arg(sf->function()->prettyName())); new SourceItem(this, this, fileno, 3, false, i18n("Thus, no annotated source can be shown.")); return; } } QString filename = sf->file()->shortName(); QString dir = sf->file()->directory(); if (!dir.isEmpty()) filename = dir + "/" + filename; if (nextCostLineno>0) { // we have debug info... search for source file if (!QFile::exists(filename)) { QStringList list = Configuration::sourceDirs(_data, sf->function()->object()); QStringList::Iterator it; for ( it = list.begin(); it != list.end(); ++it ) { dir = *it; if (checkFileExistance(dir, sf->file()->shortName())) break; } if (it == list.end()) nextCostLineno = 0; else { filename = dir + "/" + sf->file()->shortName(); // no need to search again sf->file()->setDirectory(dir); } } } // do it here, because the source directory could have been set before if (childCount()==0) { setColumnText(4, validSourceFile ? i18n("Source ('%1')").arg(filename) : i18n("Source (unknown)")); } else { new SourceItem(this, this, fileno, 0, true, validSourceFile ? i18n("--- Inlined from '%1' ---").arg(filename) : i18n("--- Inlined from unknown source ---")); } if (nextCostLineno == 0) { new SourceItem(this, this, fileno, 0, false, i18n("There is no source available for the following function:")); new SourceItem(this, this, fileno, 1, false, QString(" '%1'").arg(sf->function()->prettyName())); if (sf->file()->name().isEmpty()) { new SourceItem(this, this, fileno, 2, false, i18n("This is because no debug information is present.")); new SourceItem(this, this, fileno, 3, false, i18n("Recompile source and redo the profile run.")); if (sf->function()->object()) { new SourceItem(this, this, fileno, 4, false, i18n("The function is located in this ELF object:")); new SourceItem(this, this, fileno, 5, false, QString(" '%1'") .arg(sf->function()->object()->prettyName())); } } else { new SourceItem(this, this, fileno, 2, false, i18n("This is because its source file cannot be found:")); new SourceItem(this, this, fileno, 3, false, QString(" '%1'").arg(sf->file()->name())); new SourceItem(this, this, fileno, 4, false, i18n("Add the folder of this file to the source folder list.")); new SourceItem(this, this, fileno, 5, false, i18n("The list can be found in the configuration dialog.")); } return; } // initialisation for arrow drawing // create sorted list of jumps (for jump arrows) TraceLineMap::Iterator it = lineIt, nextIt; _lowList.clear(); _highList.clear(); while(1) { nextIt = it; ++nextIt; while(nextIt != lineItEnd) { if (&(*nextIt) == sLine) break; if ((*nextIt).hasCost(_costType)) break; if (_costType2 && (*nextIt).hasCost(_costType2)) break; ++nextIt; } TraceLineJumpList jlist = (*it).lineJumps(); TraceLineJump* lj; for (lj=jlist.first();lj;lj=jlist.next()) { if (lj->executedCount()==0) continue; // skip jumps to next source line with cost //if (lj->lineTo() == &(*nextIt)) continue; _lowList.append(lj); _highList.append(lj); } it = nextIt; if (it == lineItEnd) break; } _lowList.sort(); _highList.sort(); _lowList.first(); // iterators to list start _highList.first(); _jump.resize(0); char buf[256]; bool inside = false, skipLineWritten = true; int readBytes; int fileLineno = 0; SubCost most = 0; TraceLine* currLine; SourceItem *si, *si2, *item = 0, *first = 0, *selected = 0; QFile file(filename); if (!file.open(IO_ReadOnly)) return; while (1) { readBytes=file.readLine(buf, sizeof( buf )); if (readBytes<=0) { // for nice empty 4 lines after function with EOF buf[0] = 0; } if (readBytes >= (int) sizeof( buf )) { qDebug("%s:%d Line too long\n", sf->file()->name().ascii(), fileLineno); } else if ((readBytes>0) && (buf[readBytes-1] == '\n')) buf[readBytes-1] = 0; // keep fileLineno inside [lastCostLineno;nextCostLineno] fileLineno++; if (fileLineno == nextCostLineno) { currLine = &(*lineIt); // get next line with cost of selected type ++lineIt; while(lineIt != lineItEnd) { if (&(*lineIt) == sLine) break; if ((*lineIt).hasCost(_costType)) break; if (_costType2 && (*lineIt).hasCost(_costType2)) break; ++lineIt; } lastCostLineno = nextCostLineno; nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno(); } else currLine = 0; // update inside if (!inside) { if (currLine) inside = true; } else { if ( (fileLineno > lastCostLineno) && ((nextCostLineno == 0) || (fileLineno < nextCostLineno - Configuration::noCostInside()) )) inside = false; } int context = Configuration::context(); if ( ((lastCostLineno==0) || (fileLineno > lastCostLineno + context)) && ((nextCostLineno==0) || (fileLineno < nextCostLineno - context))) { if (lineIt == lineItEnd) break; if (!skipLineWritten) { skipLineWritten = true; // a "skipping" line: print "..." instead of a line number strcpy(buf,"..."); } else continue; } else skipLineWritten = false; si = new SourceItem(this, this, fileno, fileLineno, inside, QString(buf), currLine); if (!currLine) continue; if (!selected && (currLine == sLine)) selected = si; if (!first) first = si; if (currLine->subCost(_costType) > most) { item = si; most = currLine->subCost(_costType); } si->setOpen(true); TraceLineCallList list = currLine->lineCalls(); TraceLineCall* lc; for (lc=list.first();lc;lc=list.next()) { if ((lc->subCost(_costType)==0) && (lc->subCost(_costType2)==0)) continue; if (lc->subCost(_costType) > most) { item = si; most = lc->subCost(_costType); } si2 = new SourceItem(this, si, fileno, fileLineno, currLine, lc); if (!selected && (lc->call()->called() == _selectedItem)) selected = si2; } TraceLineJumpList jlist = currLine->lineJumps(); TraceLineJump* lj; for (lj=jlist.first();lj;lj=jlist.next()) { if (lj->executedCount()==0) continue; new SourceItem(this, si, fileno, fileLineno, currLine, lj); } } if (selected) item = selected; if (item) first = item; if (first) { ensureItemVisible(first); _inSelectionUpdate = true; setCurrentItem(first); _inSelectionUpdate = false; } file.close(); // for arrows: go down the list according to list sorting sort(); QListViewItem *item1, *item2; for (item1=firstChild();item1;item1 = item1->nextSibling()) { si = (SourceItem*)item1; updateJumpArray(si->lineno(), si, true, false); for (item2=item1->firstChild();item2;item2 = item2->nextSibling()) { si2 = (SourceItem*)item2; if (si2->lineJump()) updateJumpArray(si->lineno(), si2, false, true); else si2->setJumpArray(_jump); } } if (arrowLevels()) setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2); else setColumnWidth(3, 0); }
void SourceView::updateJumpArray(uint lineno, SourceItem* si, bool ignoreFrom, bool ignoreTo) { TraceLineJump* lj; uint lowLineno, highLineno; int iEnd = -1, iStart = -1; if (0) qDebug("updateJumpArray(line %d, jump to %s)", lineno, si->lineJump() ? si->lineJump()->lineTo()->name().ascii() : "?" ); lj=_lowList.current(); while(lj) { lowLineno = lj->lineFrom()->lineno(); if (lj->lineTo()->lineno() < lowLineno) lowLineno = lj->lineTo()->lineno(); if (lowLineno > lineno) break; if (ignoreFrom && (lowLineno < lj->lineTo()->lineno())) break; if (ignoreTo && (lowLineno < lj->lineFrom()->lineno())) break; if (si->lineJump() && (lj != si->lineJump())) break; int asize = (int)_jump.size(); #if 0 for(iStart=0;iStart<asize;iStart++) if (_jump[iStart] && (_jump[iStart]->lineTo() == lj->lineTo())) break; #else iStart = asize; #endif if (iStart == asize) { for(iStart=0;iStart<asize;iStart++) if (_jump[iStart] == 0) break; if (iStart== asize) { asize++; _jump.resize(asize); if (asize > _arrowLevels) _arrowLevels = asize; } if (0) qDebug(" start %d (%s to %s)", iStart, lj->lineFrom()->name().ascii(), lj->lineTo()->name().ascii()); _jump[iStart] = lj; } lj=_lowList.next(); } si->setJumpArray(_jump); lj=_highList.current(); while(lj) { highLineno = lj->lineFrom()->lineno(); if (lj->lineTo()->lineno() > highLineno) { highLineno = lj->lineTo()->lineno(); if (ignoreTo) break; } else if (ignoreFrom) break; if (highLineno > lineno) break; for(iEnd=0;iEnd< (int)_jump.size();iEnd++) if (_jump[iEnd] == lj) break; if (iEnd == (int)_jump.size()) { qDebug("LineView: no jump start for end at %x ?", highLineno); iEnd = -1; } lj=_highList.next(); if (0 && (iEnd>=0)) qDebug(" end %d (%s to %s)", iEnd, _jump[iEnd]->lineFrom()->name().ascii(), _jump[iEnd]->lineTo()->name().ascii()); if (0 && lj) qDebug("next end: %s to %s", lj->lineFrom()->name().ascii(), lj->lineTo()->name().ascii()); if (highLineno > lineno) break; else { if (iEnd>=0) _jump[iEnd] = 0; iEnd = -1; } } if (iEnd>=0) _jump[iEnd] = 0; }