無料のKrita 4.0グラフィカルエディターのソースコードを確認する

少し前に、無料のグラフィカルエディターKrita 4.0の新しいバージョンがリリースされました。 PVS-Studioを使用してこのプロジェクトを確認するときが来ました。







写真1








はじめに



開発者が2015年にKrita 2.9.2のバージョンですでにPVS-Studioを使用し、 それで エラーを正常に修正したことは注目に値します。 ただし、明らかに、アナライザーは使用されていません。 開発者が引き続きPVS-Studioを使用する場合、この記事で説明するエラーはリリースに含まれないため、すべての記事で定期的なチェックが重要であると言います。



役に立たない範囲ベース



PVS-Studio警告: V714変数行は参照によってforeachループに渡されませんが、その値はループ内で変更されます。 kis_algebra_2d.cpp 532



DecomposedMatix::DecomposedMatix(const QTransform &t0) { .... if (!qFuzzyCompare(t.m33(), 1.0)) { const qreal invM33 = 1.0 / t.m33(); for (auto row : rows) { // <= row *= invM33; } } .... }
      
      





この例では、プログラマーは明らかに、 コンテナーの各要素にinvM33を掛けることを望んでいましたが、これは起こりません。 ループの各反復で、 rowという名前の新しい変数が作成され、その後単純に破棄されます。 エラーを修正するには、コンテナに保存されている要素へのリンクを作成する必要があります。



 for (auto &row : rows) { row *= invM33; }
      
      





間違った条件



PVS-Studio 警告 V547式 'j == 0'は常にfalseです。 KoColorSpace.cpp 218



 QPolygonF KoColorSpace::estimatedTRCXYY() const { .... for (int j = 5; j>0; j--) { channelValuesF.fill(0.0); channelValuesF[i] = ((max / 4)*(5 - j)); if (colorModelId().id() != "XYZA") { fromNormalisedChannelsValue(data, channelValuesF); convertPixelsTo(....); xyzColorSpace->normalisedChannelsValue(....); } if (j == 0) { // <= colorantY = channelValuesF[1]; if (d->colorants.size()<2) { d->colorants.resize(3 * colorChannelCount()); d->colorants[i] = .... d->colorants[i + 1] = .... d->colorants[i + 2] = .... } } } .... }
      
      





プログラムは、条件j == 0でブロックに入ることはありません。この条件は、上記のforループで制限j> 0が課せられているため 、常にfalseであるためです。



同様のアナライザー警告:





PVS-Studio警告: V560条件式の一部は常に真です。 KoTextLayoutArea.cpp 1622



 qreal KoTextLayoutArea::addLine(QTextLine &line, FrameIterator *cursor, KoTextBlockData &blockData) { if (!d->documentLayout->changeTracker() || !d->documentLayout->changeTracker()->displayChanges() // <= || !d->documentLayout->changeTracker()->... || !d->documentLayout->changeTracker()->... || !d->documentLayout->changeTracker()->elementById(....) || !d->documentLayout->changeTracker()->elementById(....) || .... || d->documentLayout->changeTracker()->displayChanges()) { // <= .... } }
      
      





よく見ると、この複雑な条件の中にフォームのチェックがあることに気付くでしょう(!A || a)



 d->documentLayout->changeTracker()->displayChanges() || !d->documentLayout->changeTracker()->displayChanges()
      
      





このような条件は常に真であり、アナライザーが報告するように、この大きなチェック全体が無意味になるのはこのためです。



PVS-Studioの 警告 V547式 'n == 128'は常にfalseです。 compression.cpp 110

PVS-Studio 警告 V547式 'n> 128'は常にfalseです。 compression.cpp 112



 quint32 decode_packbits(const char *src, char* dst, quint16 packed_len, quint32 unpacked_len) { qint32 n; .... while (unpack_left > 0 && pack_left > 0) { n = *src; src++; pack_left--; if (n == 128) // <= continue; else if (n > 128) // <= n -= 256; .... } .... }
      
      





この例では、 srcポインターを逆参照して取得したconst char型の値がqint32型の変数nに書き込まれるため、変数nの有効な値の範囲次のとおりです 。[-128; 127]。 次に、変数nが数値128と比較されます 、このチェックの結果が常にfalseであることは明らかです。



注:プロジェクトは-funsigned-charなしでビルドされます。



PVS-Studio警告: V590 'state ==(-3)の検査を検討してください|| state!= 0 '式。 表現が過剰であるか、誤植が含まれています。 psd_pixel_utils.cpp 335



 psd_status psd_unzip_without_prediction(psd_uchar *src_buf, psd_int src_len, psd_uchar *dst_buf, psd_int dst_len) { do { state = inflate(&stream, Z_PARTIAL_FLUSH); if(state == Z_STREAM_END) break; if(state == Z_DATA_ERROR || state != Z_OK) // <= break; } while (stream.avail_out > 0); }
      
      





ここでは、2番目の条件があまりにも賢明でした。 正しいオプションは次のとおりであると仮定します。



  do { state = inflate(&stream, Z_PARTIAL_FLUSH); if(state != Z_OK) break; } while (stream.avail_out > 0);
      
      





PVS-Studio警告: V547式は常にfalseです。 SvgTextEditor.cpp 472



 void SvgTextEditor::setTextWeightDemi() { if (m_textEditorWidget.richTextEdit->textCursor() .charFormat().fontWeight() > QFont::Normal && m_textEditorWidget.richTextEdit->textCursor() .charFormat().fontWeight() < QFont::Normal) { // <= setTextBold(QFont::Normal); } else { setTextBold(QFont::DemiBold); } }
      
      





アナライザーは、フォーム(a> b && a <b)の条件を検出しましたが、これは明らかに偽です。 著者が正確に何を書きたかったのかを言うのは途方に暮れていますが、このコードは間違いなく間違いであり、修正する必要があります。



まぶた



PVS-Studio警告: V547式は常に真です。 ここでは、おそらく「&&」演算子を使用する必要があります。 KoResourceItemChooser.cpp 408



 void KoResourceItemChooser::updatePreview(KoResource *resource) { .... if (image.format() != QImage::Format_RGB32 || // <= image.format() != QImage::Format_ARGB32 || // <= image.format() != QImage::Format_ARGB32_Premultiplied) { image = image.convertToFormat(....); } .... }
      
      





プログラマーがミスを犯し、 &&演算子の代わりに||演算子を書いた 、彼の状態のすべてが無意味になったため、 次の形式の条件が判明しました: a!= const_1 || a!= const_2、これは常に真です。



PVS-Studio警告: V547式は常に真です。 ここでは、おそらく「&&」演算子を使用する必要があります。 KoSvgTextShapeMarkupConverter.cpp 1000



 QString KoSvgTextShapeMarkupConverter::style(....) { .... if (format.underlineStyle() != QTextCharFormat::NoUnderline || format.underlineStyle() != QTextCharFormat::SpellCheckUnderline) { .... } .... }
      
      





ケースは前のケースに似ています:彼らは論理演算子を混ぜて&&の代わりに||を書きました 。



PVS-Studio警告: V501 「||」の左側と右側に同一のサブ式「センサー(FUZZY_PER_DAB、true)」があります 演算子。 kis_pressure_size_option.cpp 43



 void KisPressureSizeOption::lodLimitations(....) const { if (sensor(FUZZY_PER_DAB, true) || sensor(FUZZY_PER_DAB, true)) { l->limitations << KoID("size-fade", i18nc("....")); } if (sensor(FADE, true)) { l->blockers << KoID("....")); } }
      
      





アナライザーは、オペレーターの左右||の状況を検出しました 同じ式が見つかりました。 DynamicSensorType列挙を見ると:



 enum DynamicSensorType { FUZZY_PER_DAB, FUZZY_PER_STROKE, SPEED, FADE, .... UNKNOWN = 255 };
      
      





右側に、おそらくFUZZY_PER_DABではなくFUZZY_PER_STROKEを書きたいと思っていることが明らかになります。



静的アナライザーは、このようなエラーを見つけるのに適していますが、特に多数の変更を表示する必要がある場合は、コードレビューを見落としがちです。



コピー貼り付けエラー



写真6









PVS-Studio 警告 V583 「?:」演算子は、その条件式に関係なく、常に同じ値を返します:d-> paragraphStylesDotXmlStyles.values()。 KoTextSharedLoadingData.cpp 594



 QList<KoParagraphStyle *> KoTextSharedLoadingData::paragraphStyles(bool stylesDotXml) const { return stylesDotXml ? d->paragraphStylesDotXmlStyles.values() : d->paragraphStylesDotXmlStyles.values(); // <= }
      
      





ここでは、おそらく、三項演算子のthenブロックをコピーし、呼び出されたメソッドの名前を変更するのを忘れたため、条件に関係なく、常に単一の値が返されます。



前の方法による判断:



 KoParagraphStyle * KoTextSharedLoadingData::paragraphStyle(const QString &name, bool stylesDotXml) const { return stylesDotXml ? d->paragraphStylesDotXmlStyles.value(name) : d->paragraphContentDotXmlStyles.value(name); }
      
      





elseブロックで、 paragraphStylesDotXmlStylesの代わりにparagraphContentDotXmlStylesを記述します。



警告PVS-Studio: V583 「?:」演算子は、その条件式に関係なく、常に同じ値qFloor(axis)を返します。 kis_transform_worker.cc 456



 void mirror_impl(KisPaintDeviceSP dev, qreal axis, bool isHorizontal) { .... int leftCenterPoint = qFloor(axis) < axis ? qFloor(axis) : qFloor(axis); // <= int leftEnd = qMin(leftCenterPoint, rightEnd); int rightCenterPoint = qFloor(axis) < axis ? qCeil(axis) : qFloor(axis); int rightStart = qMax(rightCenterPoint, leftStart); .... }
      
      





前の操作と非常によく似た別の操作。 おそらく最初の三項演算子のthenブロックで、 qFloor(axis)ではなくqCeil(axis)を書きたかったのか、ここでは一般的に条件が不要です。



PVS-Studio警告: V656変数「vx」、「vy」は、同じ関数の呼び出しを通じて初期化されます。 おそらくエラーまたは最適化されていないコードです。 行を確認してください:218、219。KarbonSimplifyPath.cpp 219



 bool KarbonSimplifyPath::isSufficentlyFlat(QPointF curve[4]) { qreal ux = 3 * curve[1].x() - 2 * curve[0].x() - curve[3].x(); qreal uy = 3 * curve[1].y() - 2 * curve[0].y() - curve[3].y(); qreal vx = 3 * curve[2].x() - 2 * curve[3].x() - curve[0].x(); // <= qreal vy = 3 * curve[2].x() - 2 * curve[3].x() - curve[0].x(); // <= .... }
      
      





このコードはかなり疑わしく見えます。ほとんどの場合、 vyの式を書くときに前の行コピーしたが、 x()の呼び出しをy()に変更するのを忘れていたためです。 ここにまだエラーがない場合は、次のようにコードを書き直すことをお勧めします。



 qreal vx = 3 * curve[2].x() - 2 * curve[3].x() - curve[0].x(); qreal vy = vx;
      
      





PVS-Studio警告: V581互いに並んでいる「if」ステートメントの条件式は同一です。 行を確認してください:675、679。KoTableCellStyle.cpp 679



 void KoTableCellStyle::loadOdfProperties( KoShapeLoadingContext &context, KoStyleStack &styleStack) { .... if (styleStack.hasProperty(KoXmlNS::style, "print-content")) { setPrintContent(styleStack.property(KoXmlNS::style, "print-content") == "true"); } if (styleStack.hasProperty(KoXmlNS::style, "repeat-content")) // <= { setRepeatContent(styleStack.property(KoXmlNS::style, "repeat-content") == "true"); } if (styleStack.hasProperty(KoXmlNS::style, "repeat-content")) // <= { setRepeatContent(styleStack.property(KoXmlNS::style, "repeat-content") == "true"); } .... }
      
      





同じチェックが2回実行されます。 この方法では、余分なものをコピーするか、何かを混ぜます。 エラーがなければ、重複コードを削除する価値があります。



PVS-Studio警告: V523 「then」ステートメントは「else」ステートメントと同等です。 kis_processing_applicator.cpp 227



 void KisProcessingApplicator::applyVisitorAllFrames(....) { KisLayerUtils::FrameJobs jobs; if (m_flags.testFlag(RECURSIVE)) { KisLayerUtils::updateFrameJobsRecursive(&jobs, m_node); // <= } else { KisLayerUtils::updateFrameJobsRecursive(&jobs, m_node); // <= } .... }
      
      





ほとんどの場合、ここでコードをthenブロックからelseブロックにコピーし、呼び出されたメソッドを変更するのを忘れていました。 プロジェクトのコードから判断すると、 elseブランチでは、おそらくKisLayerUtils :: updateFrameJobsを書きたいと思っていました



条件の重複(条件のエラー)



PVS-Studio 警告 V517 「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行をチェックしてください:255、269。KoInlineTextObjectManager.cpp 255



 void KoInlineTextObjectManager::documentInformationUpdated( const QString &info, const QString &data) { if (info == "title") // <= setProperty(KoInlineObject::Title, data); else if (info == "description") setProperty(KoInlineObject::Description, data); else if (info == "abstract") setProperty(KoInlineObject::Comments, data); else if (info == "subject") setProperty(KoInlineObject::Subject, data); else if (info == "keyword") setProperty(KoInlineObject::Keywords, data); else if (info == "creator") setProperty(KoInlineObject::AuthorName, data); else if (info == "initial") setProperty(KoInlineObject::AuthorInitials, data); else if (info == "title") // <= setProperty(KoInlineObject::SenderTitle, data); else if (info == "email") setProperty(KoInlineObject::SenderEmail, data); .... }
      
      





ここでは、同じチェックが2回実行されます。 おそらく、2番目のケースでは、 「sender-title」のようなものを書く必要がありました。



列挙定数を操作するときのエラー



PVS-Studio警告: V768列挙定数「BatchMode」はブール型の変数として使用されます。 KisMainWindow.cpp 811



 bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags) { if (!QFile(url.toLocalFile()).exists()) { if (!flags && BatchMode) { // <= QMessageBox::critical(0, i18nc("....", "Krita"), i18n("....", url.url())); } .... } .... }
      
      





BatchModeは、値が0x2の OpenFlag列挙要素です。



 enum OpenFlag { None = 0, Import = 0x1, BatchMode = 0x2, RecoveryFile = 0x4 };
      
      





ただし、この例では、変数であるかのように動作します。 その結果、条件の一部が常に真であることがわかりました。



この場合、上記のコードでは、 BatchModeで正しく動作します



 if (flags & BatchMode) { newdoc->setFileBatchMode(true); }
      
      





これから、次のようなものを書きたかったと結論付けることができます。



 bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags) { if (!QFile(url.toLocalFile()).exists()) { if (!(flags & BatchMode)) { // <= QMessageBox::critical(0, i18nc("....", "Krita"), i18n("....", url.url())); } .... } .... }
      
      







PVS-Studio警告: V768列挙定数 'State_Active'はブール型の変数として使用されます。 KisOpenPane.cpp 104



 void paint(....) const override { QStyledItemDelegate::paint(painter, option, index); if(!(option.state & (int)(QStyle::State_Active && // <= QStyle::State_Enabled))) // <= { .... } }
      
      





この場合、どうやら、演算子は混乱しており、 |の代わりに マスク内では、 &&演算子が使用されました。 修正されたバージョンは次のようになります。



 void paint(....) const override { QStyledItemDelegate::paint(painter, option, index); if(!(option.state & (int)(QStyle::State_Active | QStyle::State_Enabled))) { .... } }
      
      





疑わしい再割り当て



PVS-Studio警告: V519 「値」変数には連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:61、66。kis_draggable_tool_button.cpp 66



 int KisDraggableToolButton::continueDrag(const QPoint &pos) { .... if (m_orientation == Qt::Horizontal) { value = diff.x(); // <= } else { value = -diff.y(); // <= } value = diff.x() - diff.y(); // <= return value; }
      
      





変数には条件内の値が割り当てられますが、その後すぐに上書きされます。 おそらく、何らかの間違いがあります。



PVS-Studio警告: V519 「uf.f」変数には連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認:263、265。lut.h 265

PVS-Studio警告: V519 「uf.f」変数には連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認:271、273。lut.h 273



 LutKey<float>(float min, float max, float precision) : m_min(min), m_max(max), m_precision(precision) { .... if(m_min > 0 && m_max > 0) { uf.f = m_min; // <= m_tMin_p = uf.i >> m_shift; uf.f = m_max; // <= m_tMax_p = uf.i >> m_shift; m_tMin_n = m_tMax_p; m_tMax_n = m_tMax_p; } else if( m_max < 0) { uf.f = m_min; // <= m_tMax_n = uf.i >> m_shift; uf.f = m_max; // <= m_tMin_n = uf.i >> m_shift; m_tMin_p = m_tMax_n; m_tMax_p = m_tMax_n; } .... }
      
      





変数uf.fには、異なる値が連続して2回割り当てられます。 これは疑わしいものであり、他の変数に値を割り当てたい可能性があります。



おそらくスキップされました



PVS-Studio警告: V646アプリケーションのロジックの検査を検討してください。 「else」キーワードが欠落している可能性があります。 SvgStyleWriter.cpp 82



 void SvgStyleWriter::saveSvgBasicStyle(KoShape *shape, SvgSavingContext &context) { if (!shape->isVisible(false)) { .... } if (shape->transparency() > 0.0) { // <= .... } }
      
      





ここで、 elseキーワードを忘れている可能性があります 。 ここでエラーが発生していなくても、アナライザーや他のプログラマーを混乱させないように、コードのフォーマットを調整する価値があります。



同様の警告:

ヌルポインターの問題



写真3









PVS-Studio警告: V595 nullptrに対して検証される前に「l」ポインターが使用されました。 行を確認してください:428、429。kis_node_manager.cpp 428



 void KisNodeManager::moveNodeAt(....) { .... KisLayer *l = qobject_cast<KisLayer*>(parent.data()); KisSelectionMaskSP selMask = l->selectionMask(); // <= if (m && m->active() && l && l->selectionMask()) // <= selMask->setActive(false); .... }
      
      





ここでは、ポインターlが最初に逆参照され、次にnullptrがチェックされます。



同様のアナライザー警告:





PVS-Studio警告: V1004 nullptrに対して検証された後、 'sb'ポインターが安全に使用されませんでした。 行を確認してください:665、670。KisView.cpp 670



 void KisView::slotSavingStatusMessage(const QString &text, int timeout, bool isAutoSaving) { QStatusBar *sb = statusBar(); if (sb) // <= sb->showMessage(text, timeout); KisConfig cfg; if (sb->isHidden() || // <= (!isAutoSaving && cfg.forceShowSaveMessages()) || (cfg.forceShowAutosaveMessages() && isAutoSaving)) { viewManager()->showFloatingMessage(text, QIcon()); } }
      
      





アナライザーは、 nullptrをチェックした後、このsbポインターの使用が安全でないと見なします。 実際、ポインターがnullの場合(このような条件は上記のように記述されているため許可されます)、 sb-> isHidden()が呼び出されると、nullポインターの逆参照が発生する可能性があります。 修正として、 nullptrのチェックを2番目の条件に追加するか、何らかの形でこの状況を処理できます。



同様のアナライザー警告:





PVS-Studio警告: V522ヌルポインター「スロット」の参照が行われる場合があります。 kis_spriter_export.cpp 568



 KisImportExportFilter::ConversionStatus KisSpriterExport::convert( KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/) { .... SpriterSlot *slot = 0; // <= // layer.name format: "base_name bone(bone_name) slot(slot_name)" if (file.layerName.contains("slot(")) { int start = file.layerName.indexOf("slot(") + 5; int end = file.layerName.indexOf(')', start); slot->name = file.layerName.mid(start, end - start); // <= slot->defaultAttachmentFlag = .... // <= } .... }
      
      





この例では、null スロットポインターの逆参照が発生することが保証されており、これが未定義のプログラムの動作につながります。



メモリリーク



PVS-Studio警告: V773 'svgSymbol'ポインターを解放せずに関数が終了しました。 メモリリークが発生する可能性があります。 SvgParser.cpp 681



 bool SvgParser::parseSymbol(const KoXmlElement &e) { .... KoSvgSymbol *svgSymbol = new KoSvgSymbol(); // <= // ensure that the clip path is loaded in local coordinates system m_context.pushGraphicsContext(e, false); m_context.currentGC()->matrix = QTransform(); m_context.currentGC()->currentBoundingBox = QRectF(0.0, 0.0, 1.0, 1.0); QString title = e.firstChildElement("title").toElement().text(); KoShape *symbolShape = parseGroup(e); m_context.popGraphicsContext(); if (!symbolShape) return false; // <= .... }
      
      





この例では、メソッドを終了するときに、 svgSymbolに割り当てられたメモリを解放するのを忘れていました。 これはメモリリークです。 プロジェクトには多くの同様のリークがありますが、それらは同じタイプであるため、それらについては説明しません。



同様のアナライザー警告:





新しい後にnullptrをチェックします



PVS-Studio警告: V668メモリは「new」演算子を使用して割り当てられたため、「charStyle」ポインターをnullに対してテストする意味はありません。 メモリ割り当てエラーの場合、例外が生成されます。 CharacterGeneral.cpp 153



 bool KoPathShape::separate(QList<KoPathShape*> & separatedPaths) { .... Q_FOREACH (KoSubpath* subpath, d->subpaths) { KoPathShape *shape = new KoPathShape(); if (! shape) continue; // <= .... } }
      
      





記事のこのセクションは、すでに恒久的になっているようです。 new演算子を使用してメモリが割り当てられている場合、 nullptrへのポインタをチェックしても意味がありません。 メモリを割り当てることができない場合、new演算子は例外std :: bad_alloc()をスローし、 nullptrを返しません。 このコードを修正するには、例外ハンドラーを追加するか、 new(std :: nothrow)を使用します。



同様のアナライザー警告:





リファクタリング



PVS-Studio警告: V728過剰なチェックを簡素化できます。 「||」 演算子は反対の表現「!nodeJuggler」と「nodeJuggler」に囲まれています。 kis_node_manager.cpp 809



 if (!nodeJuggler || // <= (nodeJuggler && // <= (nodeJuggler->isEnded() || !nodeJuggler->canMergeAction(actionName)))) { .... }
      
      





このような検証は単純化できます。



 if (!nodeJuggler || (nodeJuggler->isEnded() || !nodeJuggler->canMergeAction(actionName))) { .... }
      
      





同様のアナライザー警告:





警告PVS-Studio: V501 '&&'演算子の左右に同じ部分式があります:!Iterator.atEnd()&&!Iterator.atEnd()KoTextDebug.cpp 867



 void KoTextDebug::dumpFrame(const QTextFrame *frame, QTextStream &out) { .... QTextFrame::iterator iterator = frame->begin(); for (; !iterator.atEnd() && !iterator.atEnd(); ++iterator) { // <= .... } .... }
      
      





forループの状態でエラーをチェックする価値があります。 エラーがない場合は、重複チェックを削除する必要があります。



同様のアナライザー警告:





PVS-Studio警告: V799 「cmd」変数は、メモリが割り当てられた後は使用されません。 この変数の使用を確認することを検討してください。 kis_all_filter_test.cpp 154



 bool testFilter(KisFilterSP f) { .... KisTransaction * cmd = new KisTransaction(kundo2_noi18n(f->name()), dev); // <= // Get the predefined configuration from a file KisFilterConfigurationSP kfc = f->defaultConfiguration(); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; delete cmd; // <= .... }
      
      





ここでは、 cmdオブジェクトにメモリを割り当てて解放しましたが、使用しませんでした。



PVS-Studio警告: V732単項マイナス演算子はブール型の値を変更しません。 「!」の使用を検討してください 演算子。 kis_equalizer_slider.cpp 75



 QRect KisEqualizerSlider::Private::boundingRect() const { QRect bounds = q->rect().adjusted(0, 0, -isRightmost, -1); return bounds; }
      
      





この例では、 isRightmost変数の型はboolです。 単項マイナスを使用すると、変数は暗黙的にint型に変換され、結果の数値が調整された()メソッドに渡されます。 そのようなコードは理解を複雑にします。 明示的は暗黙的よりも優れているため、このスニペットを次のように書き換える価値があると思います。



 QRect KisEqualizerSlider::Private::boundingRect() const { QRect bounds = q->rect().adjusted(0, 0, isRightmost ? -1 : 0, -1); return bounds; }
      
      





同様のアナライザー警告:





おわりに



結論として、Kritaの開発者に連絡し、無料でアナライザーの使用を再開するよう提案したいと思います。



開発者が前回PVS-Studioを使用して以来、LinuxとMacOSのバージョンがあり(私自身もこのプロジェクトをLinuxでテストしました)、分析も大幅に改善されました。



さらに、プロジェクトのコードでPVS-Studioをダウンロードして試してみてください。











この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Egor Bredikhin。 Krita 4.0フリーソースコードグラフィックスエディターの確認



記事を読んで質問がありますか?
多くの場合、記事には同じ質問が寄せられます。 ここで回答を収集しました: PVS-Studioバージョン2015に関する記事の読者からの質問への回答 。 リストをご覧ください。



All Articles