Analisis kode Platform CUBA menggunakan PVS-Studio

Gambar 2

Untuk programmer Java, ada alat yang berguna untuk membantu Anda menulis kode berkualitas tinggi, misalnya, lingkungan pengembangan IntelliJ IDEA yang kuat, SpotBugs gratis, analisis PMD, dan lainnya. Semua ini sudah digunakan dalam pengembangan proyek Platform CUBA, dan dalam ulasan tentang cacat kode yang ditemukan ini, saya akan memberi tahu Anda bagaimana cara lain Anda dapat meningkatkan kualitas proyek menggunakan penganalisis kode statis PVS-Studio.

Tentang proyek dan penganalisa


Platform CUBA adalah kerangka kerja Java tingkat tinggi untuk membuat aplikasi perusahaan dengan cepat dengan antarmuka web penuh. Platform ini mengabstraksi pengembang dari teknologi heterogen sehingga Anda dapat fokus pada penyelesaian masalah bisnis, pada saat yang sama, tanpa membuatnya mustahil untuk bekerja dengan mereka secara langsung. Kode sumber diambil dari repositori di GitHub .

PVS-Studio adalah alat untuk mendeteksi kesalahan dan kerentanan potensial dalam kode sumber program yang ditulis dalam C, C ++, C # dan Java. Ini bekerja pada sistem 64-bit pada Windows, Linux dan macOS. Untuk kenyamanan programmer Java, kami telah mengembangkan plugin untuk Maven, Gradle, dan IntelliJ IDEA. Proyek Platform CUBA mudah diverifikasi menggunakan plugin Gradle.

Kesalahan dalam kondisi


Peringatan 1

Ekspresi V6007 'StringUtils.isNotEmpty ("handleTabKey")' selalu benar. SourceCodeEditorLoader.java (60)

@Override public void loadComponent() { .... String handleTabKey = element.attributeValue("handleTabKey"); if (StringUtils.isNotEmpty("handleTabKey")) { resultComponent.setHandleTabKey(Boolean.parseBoolean(handleTabKey)); } .... } 

Setelah mengambil nilai atribut dari suatu elemen, verifikasi nilai ini tidak dilakukan. Sebagai gantinya, string konstan diteruskan ke fungsi isNotEmpty , tetapi kami harus melewati variabel handleTabKey .

Ada kesalahan serupa lainnya di file AbstractTableLoader.java:

  • Ekspresi V6007 'StringUtils.isNotEmpty ("dapat diedit")' selalu benar. AbstractTableLoader.java (596)

Peringatan 2

Ekspresi V6007 'previousMenuItemFlatIndex> = 0' selalu benar. CubaSideMenuWidget.java (328)

 protected MenuItemWidget findNextMenuItem(MenuItemWidget currentItem) { List<MenuTreeNode> menuTree = buildVisibleTree(this); List<MenuItemWidget> menuItemWidgets = menuTreeToList(menuTree); int menuItemFlatIndex = menuItemWidgets.indexOf(currentItem); int previousMenuItemFlatIndex = menuItemFlatIndex + 1; if (previousMenuItemFlatIndex >= 0) { return menuItemWidgets.get(previousMenuItemFlatIndex); } return null; } 

Fungsi indexOf dapat mengembalikan -1 jika item tidak ditemukan dalam daftar. Kemudian satu ditambahkan ke indeks, sehingga menyembunyikan situasi ketika elemen yang diinginkan hilang. Masalah potensial lainnya mungkin adalah fakta bahwa variabel beforeMenuItemFlatIndex akan selalu lebih besar atau sama dengan nol. Jika, misalnya, daftar menuItemWidgets kosong, maka menjadi mungkin untuk melampaui batas array.

Peringatan 3

V6009 Fungsi 'delete' dapat menerima nilai '-1' sementara nilai non-negatif diharapkan. Periksa argumen: 1. AbstractCollectionDatasource.java (556)

 protected DataLoadContextQuery createDataQuery(....) { .... StringBuilder orderBy = new StringBuilder(); .... if (orderBy.length() > 0) { orderBy.delete(orderBy.length() - 2, orderBy.length()); orderBy.insert(0, " order by "); } .... } 

Dalam pesanan buffer karakter Dengan 2 karakter terakhir dihapus jika jumlah totalnya lebih besar dari nol, yaitu. string berisi satu karakter atau lebih. Tetapi posisi awal untuk menghapus karakter diatur dengan offset 2 karakter. Jadi, jika orderBy tiba-tiba terdiri dari 1 karakter, upaya untuk menghapus akan melempar StringIndexOutOfBoundsException .

Peringatan 4

Objek V6013 'masterCollection' dan 'entitas' dibandingkan dengan referensi. Mungkin perbandingan kesetaraan dimaksudkan. CollectionPropertyContainerImpl.java (81)

 @Override public void setItems(@Nullable Collection<E> entities) { super.setItems(entities); Entity masterItem = master.getItemOrNull(); if (masterItem != null) { MetaProperty masterProperty = getMasterProperty(); Collection masterCollection = masterItem.getValue(masterProperty.getName()); if (masterCollection != entities) { updateMasterCollection(masterProperty, masterCollection, entities); } } } 

Dalam fungsi updateMasterCollection, nilai dari entitas disalin ke masterCollection . Sebelum ini, koleksi dibandingkan dengan referensi, tetapi mungkin mereka direncanakan untuk dibandingkan dengan nilai.

Peringatan 5

V6013 Objek 'nilai' dan 'nilai lama' dibandingkan dengan referensi. Mungkin perbandingan kesetaraan dimaksudkan. WebOptionsList.java (278)

 protected boolean isCollectionValuesChanged(Collection<I> value, Collection<I> oldValue) { return value != oldValue; } 

Contoh ini mirip dengan yang sebelumnya. Inilah isCollectionValuesChanged untuk membandingkan koleksi. Mungkin perbandingan dengan referensi juga bukan cara yang diharapkan.

Kelebihan kondisi


Peringatan 1

Ekspresi V6007 'mask.charAt (i + offset)! = PlaceHolder' selalu benar. DatePickerDocument.java (238)

 private String calculateFormattedString(int offset, String text) .... { .... if ((mask.charAt(i + offset) == placeHolder)) { // <= .... } else if ((mask.charAt(i + offset) != placeHolder) && // <= (Character.isDigit(text.charAt(i)))) { .... } .... } 

Dalam perbandingan kedua, ekspresi yang berlawanan dengan yang pertama diperiksa. Pemeriksaan kedua dapat dihapus untuk menyederhanakan kode.

Konektor V6007 Ekspresi '== null' selalu salah. HTML5Support.java (169)

 private boolean validate(NativeEvent event) { .... while (connector == null) { widget = widget.getParent(); connector = Util.findConnectorFor(widget); } if (this.connector == connector) { return true; } else if (connector == null) { // <= return false; } else if (connector.getWidget() instanceof VDDHasDropHandler) { return false; } return true; } 

Setelah loop sementara selesai, nilai variabel konektor tidak akan nol , oleh karena itu, pemeriksaan redundan dapat dihapus.

Tempat mencurigakan lain yang harus diperhatikan pengembang:

  • Ekspresi V6007 'StringUtils.isBlank (strValue)' selalu benar. Param.java (818)

Kode yang tidak terjangkau dalam tes


V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. TransactionTest.java (283)

 private void throwException() { throw new RuntimeException(TEST_EXCEPTION_MSG); } @Test public void testSuspendRollback() { Transaction tx = cont.persistence().createTransaction(); try { .... Transaction tx1 = cont.persistence().createTransaction(); try { EntityManager em1 = cont.persistence().getEntityManager(); assertTrue(em != em1); Server server1 = em1.find(Server.class, server.getId()); assertNull(server1); throwException(); // <= tx1.commit(); // <= } catch (Exception e) { // } finally { tx1.end(); } tx.commit(); } finally { tx.end(); } } 

Fungsi throwException melempar pengecualian yang mencegah panggilan ke fungsi tx1.commit. Mungkin garis-garis ini harus dipertukarkan.

Beberapa tempat serupa di tes lain:

  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. TransactionTest.java (218)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. TransactionTest.java (163)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. TransactionTest.java (203)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. TransactionTest.java (137)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. UpdateDetachedTest.java (153)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. EclipseLinkDetachedTest.java (132)
  • V6019 Kode tidak terjangkau terdeteksi. Mungkin saja ada kesalahan. PersistenceTest.java (223)

Argumen Fungsi Mencurigakan


Peringatan 1

V6023 Parameter 'garam' selalu ditulis ulang dalam tubuh metode sebelum digunakan. BCryptEncryptionModule.java (47)

 @Override public String getHash(String content, String salt) { salt = BCrypt.gensalt(); return BCrypt.hashpw(content, salt); } 

Dalam kriptografi, garam adalah serangkaian data yang diteruskan ke fungsi hash bersama dengan kata sandi. Ini terutama digunakan untuk perlindungan terhadap pencarian dan serangan kamus menggunakan tabel pelangi, serta menyembunyikan kata sandi yang sama. Baca lebih lanjut: Garam (kriptografi) .

Dalam fungsi ini, garis digosok segera setelah memasuki fungsi. Mungkin mengabaikan nilai yang diteruskan merupakan kerentanan potensial.

Peringatan 2

Untuk fungsi yang dipertimbangkan, penganalisa segera memberikan dua peringatan:

  • V6023 Parameter 'offsetWidth' selalu ditulis ulang dalam tubuh metode sebelum digunakan. CubaSuggestionFieldWidget.java (433)
  • V6023 Parameter 'offsetHeight' selalu ditulis ulang dalam tubuh metode sebelum digunakan. CubaSuggestionFieldWidget.java (433)


 @Override public void setPosition(int offsetWidth, int offsetHeight) { offsetHeight = getOffsetHeight(); .... if (offsetHeight + getPopupTop() > ....)) { .... } .... offsetWidth = containerFirstChild.getOffsetWidth(); if (offsetWidth + getPopupLeft() > ....)) { .... } else { left = getPopupLeft(); } setPopupPosition(left, top); } 

Kode lucu. Fungsi hanya mengambil dua variabel: offsetWidth dan offsetHeight , keduanya ditimpa sebelum digunakan.

Peringatan 3

V6022 'Pintasan' Parameter tidak digunakan di dalam badan konstruktor. DeclarativeTrackingAction.java (47)

 public DeclarativeTrackingAction(String id, String caption, String description, String icon, String enable, String visible, String methodName, @Nullable String shortcut, ActionsHolder holder) { super(id); this.caption = caption; this.description = description; this.icon = icon; setEnabled(enable == null || Boolean.parseBoolean(enable)); setVisible(visible == null || Boolean.parseBoolean(visible)); this.methodName = methodName; checkActionsHolder(holder); } 

Nilai parameter pintasan tidak digunakan dalam fungsi. Antarmuka fungsi mungkin kedaluwarsa atau peringatan ini bukan kesalahan.

Beberapa tempat serupa:

  • V6022 'Jenis' Parameter tidak digunakan di dalam tubuh konstruktor. QueryNode.java (36)
  • V6022 Parameter 'text2' tidak digunakan di dalam tubuh konstruktor. MarkerAddition.java (22)
  • V6022 'Pemilihan' Parameter tidak digunakan di dalam tubuh konstruktor. AceEditor.java (114)
  • V6022 'Opsi' Parameter tidak digunakan di dalam tubuh konstruktor. EntitySerialization.java (379)

Fungsi berbeda dengan kode yang sama


Peringatan 1

V6032 Aneh bahwa tubuh metode 'firstItemId' sepenuhnya setara dengan tubuh metode lain 'lastItemId'. ContainerTableItems.java (213), ContainerTableItems.java (219)

 @Override public Object firstItemId() { List<E> items = container.getItems(); return items.isEmpty() ? null : items.get(0).getId(); } @Override public Object lastItemId() { List<E> items = container.getItems(); return items.isEmpty() ? null : items.get(0).getId(); } 

Fungsi firstItemId dan lastItemId memiliki implementasi yang sama. Kemungkinan besar, dalam yang terakhir itu perlu untuk mendapatkan elemen bukan dengan indeks 0 , tetapi untuk menghitung indeks elemen terakhir.

Peringatan 2

V6032 Aneh bahwa tubuh metode sepenuhnya setara dengan tubuh metode lain. SearchComboBoxPainter.java (495), SearchComboBoxPainter.java (501)

 private void paintBackgroundDisabledAndEditable(Graphics2D g) { rect = decodeRect1(); g.setPaint(color53); g.fill(rect); } private void paintBackgroundEnabledAndEditable(Graphics2D g) { rect = decodeRect1(); g.setPaint(color53); g.fill(rect); } 

Dua fungsi lagi dengan implementasi yang mencurigakan identik. Saya berani menyarankan bahwa di salah satu dari mereka perlu menggunakan warna yang berbeda dari color53 .

Referensi kosong


Peringatan 1

V6060 Referensi 'descriptionPopup' digunakan sebelum diverifikasi terhadap nol. SuggestPopup.java (252), SuggestPopup.java (251)

 protected void updateDescriptionPopupPosition() { int x = getAbsoluteLeft() + WIDTH; int y = getAbsoluteTop(); descriptionPopup.setPopupPosition(x, y); if (descriptionPopup!=null) { descriptionPopup.setPopupPosition(x, y); } } 

Hanya dalam dua baris, penulis berhasil menulis kode yang sangat mencurigakan. Pertama, metode setPopupPosition dipanggil pada objek descriptionPopup , dan kemudian objek tersebut dibandingkan dengan nol . Kemungkinan besar, panggilan pertama ke fungsi setPopupPosition berlebihan dan berbahaya. Sepertinya konsekuensi dari kegagalan refactoring.

Peringatan 2

V6060 Referensi 'tableModel' digunakan sebelum diverifikasi terhadap nol. DesktopAbstractTable.java (1580), DesktopAbstractTable.java (1564)

 protected Column addRuntimeGeneratedColumn(String columnId) { // store old cell editors / renderers TableCellEditor[] cellEditors = new TableCellEditor[tableModel.getColumnCount() + 1]; // <= TableCellRenderer[] cellRenderers = new TableCellRenderer[tableModel.getColumnCount() + 1]; // <= for (int i = 0; i < tableModel.getColumnCount(); i++) { // <= Column tableModelColumn = tableModel.getColumn(i); if (tableModel.isGeneratedColumn(tableModelColumn)) { // <= TableColumn tableColumn = getColumn(tableModelColumn); cellEditors[i] = tableColumn.getCellEditor(); cellRenderers[i] = tableColumn.getCellRenderer(); } } Column col = new Column(columnId, columnId); col.setEditable(false); columns.put(col.getId(), col); if (tableModel != null) { // <= tableModel.addColumn(col); } .... } 

Situasi serupa ada dalam fungsi ini. Setelah banyak panggilan ke objek tableModel , pemeriksaan dilakukan apakah itu nol atau tidak.

Contoh lain:

  • V6060 Referensi 'tableModel' digunakan sebelum diverifikasi terhadap nol. DesktopAbstractTable.java (596), DesktopAbstractTable.java (579)

Mungkin kesalahan logis


V6026 Nilai ini sudah ditetapkan ke variabel 'sortAscending'. CubaScrollTableWidget.java (488)

 @Override protected void sortColumn() { .... if (sortAscending) { if (sortClickCounter < 2) { // special case for initial revert sorting instead of reset sort order if (sortClickCounter == 0) { client.updateVariable(paintableId, "sortascending", false, false); } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; // <= client.updateVariable(paintableId, "resetsortorder", "", true); } } else { client.updateVariable(paintableId, "sortascending", false, false); } } else { if (sortClickCounter < 2) { // special case for initial revert sorting instead of reset sort order if (sortClickCounter == 0) { client.updateVariable(paintableId, "sortascending", true, false); } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; client.updateVariable(paintableId, "resetsortorder", "", true); } } else { reloadDataFromServer = false; sortClickCounter = 0; sortColumn = null; sortAscending = true; client.updateVariable(paintableId, "resetsortorder", "", true); } } .... } 

Dalam kondisi pertama, variabel sortAscending sudah benar , tetapi masih diberi nilai yang sama. Mungkin ini adalah kesalahan dan ingin menugaskan salah .

Contoh serupa dari file lain:

  • V6026 Nilai ini sudah ditetapkan ke variabel 'sortAscending'. CubaTreeTableWidget.java (444)

Nilai pengembalian fungsi aneh


Peringatan 1

V6037 ' Pengembalian ' tanpa syarat dalam satu lingkaran. QueryCacheManager.java (128)

 public <T> T getSingleResultFromCache(QueryKey queryKey, List<View> views) { .... for (Object id : queryResult.getResult()) { return (T) em.find(metaClass.getJavaClass(), id, views.toArray(....)); } .... } 

Penganalisis mendeteksi panggilan tanpa syarat ke pernyataan kembali pada iterasi pertama dari for loop. Mungkin ini kesalahan, atau Anda perlu menulis ulang kode untuk menggunakan pernyataan if .

Peringatan 2

V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. DefaultExceptionHandler.java (40)

 @Override public boolean handle(ErrorEvent event, App app) { Throwable t = event.getThrowable(); if (t instanceof SocketException || ExceptionUtils.getRootCause(t) instanceof SocketException) { return true; } if (ExceptionUtils.getThrowableList(t).stream() .anyMatch(o -> o.getClass().getName().equals("...."))) { return true; } if (StringUtils.contains(ExceptionUtils.getMessage(t), "....")) { return true; } AppUI ui = AppUI.getCurrent(); if (ui == null) { return true; } if (t != null) { if (app.getConnection().getSession() != null) { showDialog(app, t); } else { showNotification(app, t); } } return true; } 

Fungsi ini dalam semua kasus mengembalikan true . Tapi di sini, di baris terakhir meminta kembalinya yang salah . Mungkin ada kesalahan.

Seluruh daftar fungsi mencurigakan dengan kode yang serupa:

  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. ErrorNodesFinder.java (31)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. FileDownloadController.java (69)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. IdVarSelector.java (73)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. IdVarSelector.java (48)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. IdVarSelector.java (67)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. IdVarSelector.java (46)
  • V6014 Aneh bahwa metode ini selalu mengembalikan satu dan nilai yang sama. JoinVariableNode.java (57)

Peringatan 3

Ekspresi V6007 'needReload' selalu salah. WebAbstractTable.java (2702)

 protected boolean handleSpecificVariables(Map<String, Object> variables) { boolean needReload = false; if (isUsePresentations() && presentations != null) { Presentations p = getPresentations(); if (p.getCurrent() != null && p.isAutoSave(p.getCurrent()) && needUpdatePresentation(variables)) { Element e = p.getSettings(p.getCurrent()); saveSettings(e); p.setSettings(p.getCurrent(), e); } } return needReload; } 

Fungsi mengembalikan variabel needReload , yang nilainya selalu salah . Kemungkinan besar, di salah satu kondisi mereka lupa menambahkan kode untuk mengubah nilai variabel.

Peringatan 4

V6062 Kemungkinan rekursi tak terbatas di dalam metode 'isFocused'. GwtAceEditor.java (189), GwtAceEditor.java (190)

 public final native void focus() /*-{ this.focus(); }-*/; public final boolean isFocused() { return this.isFocused(); } 

Penganalisa mendeteksi suatu fungsi yang disebut rekursif tanpa syarat untuk menghentikan rekursi. File ini memiliki banyak fungsi yang ditandai dengan kata kunci asli dan berisi kode komentar. Kemungkinan besar, file saat ini sedang ditimpa dan segera pengembang akan memperhatikan fungsi isFocused .

Peringatan lain-lain


Peringatan 1

V6002 Pernyataan beralih tidak mencakup semua nilai dari 'Operasi' enum: ADD. DesktopAbstractTable.java (665)

 /** * Operation which caused the datasource change. */ enum Operation { REFRESH, CLEAR, ADD, REMOVE, UPDATE } @Override public void setDatasource(final CollectionDatasource datasource) { .... collectionChangeListener = e -> { switch (e.getOperation()) { case CLEAR: case REFRESH: fieldDatasources.clear(); break; case UPDATE: case REMOVE: for (Object entity : e.getItems()) { fieldDatasources.remove(entity); } break; } }; .... } 

Pernyataan beralih tidak membahas nilai ADD . Ini adalah satu-satunya yang belum ditinjau, jadi ada baiknya memeriksa apakah itu kesalahan atau tidak.

Peringatan 2

V6021 'Sumber' variabel tidak digunakan. DefaultHorizontalLayoutDropHandler.java (177)

 @Override protected void handleHTML5Drop(DragAndDropEvent event) { LayoutBoundTransferable transferable = (LayoutBoundTransferable) event .getTransferable(); HorizontalLayoutTargetDetails details = (HorizontalLayoutTargetDetails) event .getTargetDetails(); AbstractOrderedLayout layout = (AbstractOrderedLayout) details .getTarget(); Component source = event.getTransferable().getSourceComponent(); // <= int idx = (details).getOverIndex(); HorizontalDropLocation loc = (details).getDropLocation(); if (loc == HorizontalDropLocation.CENTER || loc == HorizontalDropLocation.RIGHT) { idx++; } Component comp = resolveComponentFromHTML5Drop(event); if (idx >= 0) { layout.addComponent(comp, idx); } else { layout.addComponent(comp); } if (dropAlignment != null) { layout.setComponentAlignment(comp, dropAlignment); } } 

Variabel sumber dideklarasikan dan tidak digunakan dalam kode. Mungkin, seperti variabel comp lain dari jenis yang sama, mereka lupa untuk menambahkan sumber ke tata letak .

Lebih banyak fungsi dengan variabel yang tidak digunakan:

  • V6021 'Sumber' variabel tidak digunakan. DefaultHorizontalLayoutDropHandler.java (175)
  • V6021 Nilai ini diberikan ke variabel 'r' tetapi tidak digunakan. ExcelExporter.java (262)
  • V6021 Variabel 'over' tidak digunakan. DefaultCssLayoutDropHandler.java (49)
  • V6021 Variabel 'dapat ditransfer' tidak digunakan. DefaultHorizontalLayoutDropHandler.java (171)
  • V6021 Variabel 'dapat ditransfer' tidak digunakan. DefaultHorizontalLayoutDropHandler.java (169)
  • V6021 'beanLocator' Variabel tidak digunakan. ScreenEventMixin.java (28)

Peringatan 3

Kelas V6054 tidak boleh dibandingkan dengan namanya. MessageTools.java (283)

 public boolean hasPropertyCaption(MetaProperty property) { Class<?> declaringClass = property.getDeclaringClass(); if (declaringClass == null) return false; String caption = getPropertyCaption(property); int i = caption.indexOf('.'); if (i > 0 && declaringClass.getSimpleName().equals(caption.substring(0, i))) return false; else return true; } 

Penganalisa mendeteksi suatu situasi ketika membandingkan kelas dilakukan dengan nama. Perbandingan semacam itu tidak benar, karena, sesuai dengan spesifikasi, kelas JVM memiliki nama unik hanya di dalam paket. Ini dapat menyebabkan perbandingan yang salah dan eksekusi kode yang salah yang telah direncanakan.

Umpan Balik Pengembang Platform CUBA


Tentu saja, dalam setiap proyek besar ada bug. Itulah sebabnya kami dengan senang hati menyetujui proposal tim PVS-Studio untuk memeriksa proyek kami. Repositori CUBA termasuk fork dari beberapa perpustakaan OSS pihak ketiga di bawah lisensi Apache 2, dan tampaknya kita perlu lebih memperhatikan kode ini, penganalisa menemukan beberapa masalah dalam sumber-sumber ini. Sekarang kami menggunakan SpotBugs sebagai analis utama, dan tidak menemukan beberapa masalah signifikan yang ditemukan oleh PVS-Studio. Sudah waktunya untuk pergi dan menulis cek tambahan sendiri. Banyak terima kasih kepada tim PVS-Studio untuk pekerjaan yang dilakukan.

Pengembang juga mencatat bahwa peringatan V6013 dan V6054 salah. Kode itu ditulis dengan sengaja. Analis statis dirancang untuk mendeteksi fragmen kode yang mencurigakan dan kemungkinan menemukan kesalahan berbeda untuk semua inspeksi. Namun demikian, mudah untuk bekerja dengan peringatan semacam itu menggunakan mekanisme yang nyaman untuk penindasan massal terhadap penganalisa tanpa memodifikasi file kode sumber.

Tim PVS-Studio lain tidak dapat mengabaikan frasa “saatnya untuk pergi dan menulis cek tambahan sendiri” dan tidak meninggalkan gambar ini :)

Gambar 1

Kesimpulan


PVS-Studio akan menjadi tambahan yang bagus untuk proyek Anda saat ini untuk meningkatkan alat kualitas kode. Apalagi jika ada puluhan, ratusan dan ribuan karyawan. PVS-Studio dirancang tidak hanya untuk menemukan kesalahan, tetapi juga untuk memperbaikinya. Selain itu, kami tidak berbicara tentang pengeditan kode otomatis, tetapi tentang kontrol kualitas kode yang andal. Dalam sebuah perusahaan besar, tidak mungkin untuk membayangkan situasi di mana benar-benar semua pengembang akan secara independen memverifikasi kode mereka dengan berbagai alat, jadi alat seperti PVS-Studio lebih cocok untuk perusahaan seperti itu, di mana kontrol kualitas kode disediakan pada semua tahap pengembangan, tidak hanya untuk programmer biasa.



Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Svyatoslav Razmyslov. Menganalisis Kode Platform CUBA dengan PVS-Studio

Source: https://habr.com/ru/post/id449022/


All Articles