PVS-Studio لجافا

PVS-Studio لجافا

في الإصدار السابع من محلل ثابت PVS-Studio ، أضفنا دعم لغة جافا. حان الوقت لقصة مختصرة عن كيفية البدء في دعم لغة جافا ، وإلى أي مدى وصلنا ، وما هو في خططنا الإضافية. بالطبع ، سوف تسرد هذه المقالة تجارب المحلل الأولى على مشاريع مفتوحة المصدر.

PVS-Studio


فيما يلي وصف موجز لبرنامج PVS-Studio لمطوري Java الذين لم يسمعوا به من قبل.

تم تصميم هذه الأداة للكشف عن الأخطاء ونقاط الضعف المحتملة في التعليمات البرمجية المصدر للبرامج ، المكتوبة بلغات C و C ++ و C # و Java. يعمل في بيئة Windows و Linux و macOS.

يقوم برنامج PVS-Studio بتحليل الشفرة الثابتة ويقوم بإنشاء تقرير يساعد المطور في العثور على العيوب والقضاء عليها. بالنسبة لأولئك المهتمين بكيفية البحث الدقيق عن PVS-Studio عن الأخطاء ، أقترح إلقاء نظرة على المقال " التقنيات المستخدمة في محلل كود PVS-Studio للعثور على الأخطاء ونقاط الضعف المحتملة ".

بداية


كان بإمكاني التوصل إلى قصة ذكية عن كيفية تكهناتنا بشأن اللغة التالية التي سيتم دعمها في PVS-Studio. حول اختيار معقول لجافا ، والتي تستند إلى شعبية عالية لهذه اللغة ، وهلم جرا.

ومع ذلك ، كما يحدث في الحياة ، لم يتم الاختيار عن طريق التحليل العميق ، ولكن عن طريق التجربة :). نعم ، فكرنا في اتجاه تطوير محلل PVS-Studio. نظرنا في لغات مثل: Java و PHP و Python و JavaScript و IBM RPG. كنا نميل إلى لغة جافا ولكن لم يتم اتخاذ القرار النهائي. بالنسبة لأولئك الذين استندت نظرتهم إلى IBM RPG غير المألوف ، أود توجيهك إلى هذه الملاحظة ، والتي سيصبح كل شيء واضحًا منها.

في نهاية عام 2017 ، قام زميلي إيغور بريديكين بمراجعة المكتبات الجاهزة لرموز التحليل اللغوي (بمعنى آخر - المحللون) للتعرف على اتجاهات تطوير جديدة ومثيرة للاهتمام بالنسبة لنا. في النهاية ، صادف عدة مشاريع لتحليل كود جافا. تمكن من إنشاء نموذج أولي سريع للمحلل باستخدام تشخيصين يعتمدان على الملعقة . علاوة على ذلك ، أصبح من الواضح أننا سنكون قادرين على استخدام بعض آليات محلل C ++ باستخدام SWIG في محلل Java. نظرنا إلى ما حصلنا عليه وأدركنا أن محللنا التالي سيكون لجافا.

نود أن نشكر إيجور على تعهده وعمله الشاق الذي قام به على محلل جافا. وقد وصف عملية التطوير نفسها في مقاله " تطوير محلل ثابت جديد: PVS-Studio Java ."

ماذا عن المنافسين؟


هناك العديد من برامج تحليل الشفرات الثابتة المجانية والتجارية لجافا في جميع أنحاء العالم. ليس هناك نقطة لإدراجها جميعًا في المقالة. سأترك الرابط " قائمة أدوات لتحليل الشفرة الثابتة " (انظر قسم Java و Multi-language).

ومع ذلك ، أعرف أنه أولاً وقبل كل شيء سوف يتم سؤالك عن IntelliJ IDEA و FindBugs و SonarQube (SonarJava).

IntelliJ IDEA

بنيت محلل قوي ثابت جدا رمز في IntelliJ IDEA. ما هو أكثر من ذلك ، محلل يتطور ، مؤلفيه متابعة عن كثب أنشطتنا. لذلك ، IntelliJ IDEA هو ملف تعريف ارتباط قوي بالنسبة لنا. لن نتمكن من تجاوز IntelliJ IDEA في قدرات التشخيص ، على الأقل حتى الآن. لذلك ، سوف نركز على مزايانا الأخرى.

يعد التحليل الثابت في IntelliJ IDEA أحد ميزات البيئة ، والذي يفرض قيودًا معينة عليه. بالنسبة لنا ، لدينا الحرية فيما يمكننا القيام به مع محللنا. على سبيل المثال ، يمكننا تكييفها بسرعة مع احتياجات العملاء المحددة. الدعم السريع والعميق هو ميزتنا التنافسية. يتواصل عملاؤنا مباشرة مع المطورين ، ويعملون على جزء أو آخر من PVS-Studio.

في PVS-Studio ، هناك العديد من الفرص لدمجها في دورة تطوير المشاريع القديمة الكبيرة. على سبيل المثال ، إنه تكاملنا مع SonarQube . كما يتضمن أيضًا قمعًا جماعيًا لتحذيرات المحلل ، والذي يسمح لك بالبدء على الفور في استخدام الأداة في مشروع كبير لتتبع الأخطاء فقط في الكود الجديد أو المعدل. يمكن بناء PVS-Studio في عملية تكامل مستمرة. أعتقد أن هذه الميزات وغيرها ستساعد محللنا في العثور على مكان تحت الشمس في عالم جافا.

Findbugs

تم التخلي عن مشروع FindBugs. ومع ذلك ، ينبغي أن نذكرها بسبب حقيقة أنه ، ربما ، أشهر محلل ثابت مجاني لرمز Java.

قد يسمى SpotBugs خليفة FindBugs. ومع ذلك ، فهي أقل شعبية ، وليس من الواضح بعد ماذا سيحدث معها.

بشكل عام ، نعتقد أنه على الرغم من أن FindBugs كان ولا يزال يتمتع بشعبية كبيرة ، بالإضافة إلى أنه محلل مجاني ، يجب ألا نتناوله. سوف يصبح هذا المشروع مجرد تاريخ بهدوء.

PS بالمناسبة ، الآن يمكن أيضًا استخدام PVS-Studio مجانًا عند العمل مع المشاريع المفتوحة.

SonarQube (SonarJava)

نعتقد أننا لا نتنافس مع SonarQube ، لكننا نكمله. يدمج PVS-Studio في SonarQube ، والذي يسمح للمطورين بالعثور على المزيد من الأخطاء ونقاط الضعف الأمنية المحتملة في مشاريعهم. نحن نعلم بانتظام كيفية دمج أداة PVS-Studio وغيرها من أجهزة التحليل في SonarQube في الفصول الرئيسية التي نعقدها من حيث المؤتمرات المختلفة.

كيفية تشغيل PVS-Studio لجافا


لقد أتاحنا أكثر الطرق شيوعًا لتكامل المحلل في نظام الإنشاء للمستخدمين:

  • البرنامج المساعد ل Maven.
  • البرنامج المساعد ل Gradle.
  • البرنامج المساعد ل IntelliJ IDEA

خلال مرحلة الاختبار ، التقينا بالكثير من المستخدمين الذين لديهم أنظمة بناء مكتوبة ذاتيًا ، لا سيما في مجال تطوير الأجهزة المحمولة. لقد استمتعوا بفرصة تشغيل المحلل مباشرةً ، مع سرد المصادر و classpath.

يمكنك العثور على معلومات مفصلة حول جميع الطرق لتشغيل المحلل في صفحة الوثائق " كيفية تشغيل PVS-Studio Java ".

لم نتمكن من الابتعاد عن منصة SonarQube الخاصة بمراقبة جودة الكود ، والتي تحظى بشعبية كبيرة بين مطوري Java ، لذلك أضفنا دعمًا بلغة Java في المكون الإضافي لبرنامج SonarQube .

خطط أخرى


لدينا الكثير من الأفكار التي قد تتطلب مزيدًا من البحث ، ولكن بعض الخطط المحددة ، المتأصلة في أي من المحللين لدينا ، هي كما يلي:

  • إنشاء تشخيصات جديدة وتحسين التشخيصات الحالية ؛
  • تحسين تحليل تدفق البيانات ؛
  • زيادة الموثوقية وسهولة الاستخدام.

ربما ، سنجد وقتًا لتكييف البرنامج المساعد IntelliJ IDEA لـ CLion. مرحبًا إلى مطوري C ++ الذين قرأوا عن محلل Java :-)

أمثلة على الأخطاء الموجودة في مشاريع مفتوحة المصدر


ارتجف من أخشابي إذا لم أعرض في المقالة بعض الأخطاء التي عثر عليها مع المحلل الجديد! حسنًا ، كان بإمكاننا اتخاذ مشروع Java مفتوح المصدر كبيرًا وكتابة مقال كلاسيكي لمراجعة الأخطاء ، كما نفعل عادةً .

ومع ذلك ، أتوقع على الفور أسئلة حول ما يمكننا العثور عليه في مشاريع مثل IntelliJ IDEA و FindBugs وما إلى ذلك. لذلك ليس لدي مخرج ، بخلاف البدء بهذه المشاريع. لذلك ، قررت أن أقوم بفحص وكتابة العديد من الأمثلة المثيرة للاهتمام للأخطاء من المشاريع التالية:

  • IntelliJ IDEA Community Edition . أعتقد أنه لا توجد حاجة لشرح سبب اختيار هذا المشروع :).
  • SpotBugs كما كتبت في وقت سابق ، فإن مشروع FindBugs لا يتقدم. لذلك دعونا ننظر داخل مشروع SpotBugs ، وهو خليفة FindBugs. SpotBugs هو محلل ثابت الكلاسيكية لرمز جافا.
  • شيء من مشاريع شركة SonarSource ، التي تطور البرمجيات للمراقبة المستمرة لجودة الشفرة. الآن دعونا ننظر داخل SonarQube و SonarJava .

الكتابة عن الأخطاء في هذه المشاريع هو التحدي. حقيقة الأمر هي أن هذه المشاريع عالية الجودة. في الواقع ، ليس من المستغرب. تشير ملاحظاتنا إلى أنه يتم دائمًا اختبار أدوات تحليل الشفرات الثابتة والتحقق منها جيدًا باستخدام أدوات أخرى.

على الرغم من كل هذا ، يجب أن أبدأ مع هذه المشاريع بالضبط. لن تكون لدي الفرصة الثانية لأكتب عنها. أنا متأكد من أنه بعد إصدار PVS-Studio for Java ، سيتولى مطورو المشاريع المدرجة وضع PVS-Studio على متنها ويبدأون في استخدامها لفحصها بشكل منتظم أو على الأقل في بعض الأحيان. على سبيل المثال ، أعرف أن Tagir Valeev ( lany ) ، أحد مطوري JetBrains ، الذي يعمل على محلل الكود الثابت IntelliJ IDEA ، في الوقت الحالي ، عندما أكتب المقال يتم تشغيله بالفعل باستخدام إصدار Beta من PVS-Studio . لقد كتب لنا حوالي 15 رسالة بريد إلكتروني مع تقارير الأخطاء والتوصيات. شكرا يا تاجير!

لحسن الحظ ، لست بحاجة إلى العثور على أكبر عدد من الأخطاء في مشروع واحد معين. تتمثل مهمتي في الوقت الحالي في إظهار أن محلل PVS-Studio لجافا لم يظهر هباء ، وسيكون قادرًا على ملء سطر من الأدوات الأخرى المصممة لتحسين جودة الشفرة. نظرت للتو من خلال تقارير المحلل وسردت بعض الأخطاء التي بدت مثيرة للاهتمام. إذا كان ذلك ممكنًا ، فقد حاولت الاستشهاد بأنواع مختلفة من الأخطاء. دعونا نرى كيف اتضح.

IntelliJ IDEA ، شعبة عدد صحيح


private static boolean checkSentenceCapitalization(@NotNull String value) { List<String> words = StringUtil.split(value, " "); .... int capitalized = 1; .... return capitalized / words.size() < 0.2; // allow reasonable amount of // capitalized words } 

تحذير PVS-Studio: V6011 [CWE-682] تتم مقارنة الحرف "0.2" من النوع "المزدوج" بقيمة من النوع "int". TitleCapitalizationInspection.java 169

كانت النقطة التي يجب أن ترجع الدالة صحيحة إذا كان أقل من 20٪ من الكلمات يبدأ بحرف كبير. في الواقع ، لا يعمل التحقق ، لأنه يحدث عدد صحيح. نتيجة للتقسيم ، يمكننا الحصول على قيمتين فقط: 0 أو 1.

سوف ترجع الدالة false ، فقط إذا كانت كل الكلمات تبدأ بحرف كبير. في جميع الحالات الأخرى ، ستؤدي عملية القسمة إلى 0 وستعود الوظيفة إلى حقيقة.

IntelliJ IDEA ، حلقة مشبوهة


 public int findPreviousIndex(int current) { int count = myPainter.getErrorStripeCount(); int foundIndex = -1; int foundLayer = 0; if (0 <= current && current < count) { current--; for (int index = count - 1; index >= 0; index++) { // <= int layer = getLayer(index); if (layer > foundLayer) { foundIndex = index; foundLayer = layer; } } .... } 

تحذير PVS-Studio: V6007 [CWE-571] تعبير 'index> = 0' صحيح دائمًا. Updater.java 184

أولاً ، انظر إلى الحالة (0 <= الحالية && <<العد) . يتم تنفيذها فقط في حالة ما إذا كانت قيمة المتغير العد أكبر من 0.

انظر الآن إلى الحلقة:

 for (int index = count - 1; index >= 0; index++) 

تتم تهيئة الفهرس المتغير بعدد تعبير - 1 . نظرًا لأن متغير العدد أكبر من 0 ، فستكون القيمة الأولية لمتغير الفهرس دائمًا أكبر من أو تساوي 0. اتضح أنه سيتم تنفيذ الحلقة حتى يحدث تدفق زائد لمتغير الفهرس .

على الأرجح ، إنه مجرد خطأ مطبعي ، ولا يجب تنفيذ زيادة في متغير:

 for (int index = count - 1; index >= 0; index--) 

IntelliJ IDEA ، نسخ ولصق


 @NonNls public static final String BEFORE_STR_OLD = "before:"; @NonNls public static final String AFTER_STR_OLD = "after:"; private static boolean isBeforeOrAfterKeyword(String str, boolean trimKeyword) { return (trimKeyword ? LoadingOrder.BEFORE_STR.trim() : LoadingOrder.BEFORE_STR).equalsIgnoreCase(str) || (trimKeyword ? LoadingOrder.AFTER_STR.trim() : LoadingOrder.AFTER_STR).equalsIgnoreCase(str) || LoadingOrder.BEFORE_STR_OLD.equalsIgnoreCase(str) || // <= LoadingOrder.BEFORE_STR_OLD.equalsIgnoreCase(str); // <= } 

تحذير PVS-Studio: V6001 [CWE-570] هناك تعبيرات فرعية متطابقة 'LoadingOrder.BEFORE_STR_OLD.equalsIgnoreCase (str)' إلى اليسار وإلى يمين "||" المشغل. خطوط التحقق: 127 ، 128. ExtensionOrderConverter.java 127

تأثير قديم جيد من السطر الأخير . قفز مطور البندقية وضرب خط الشفرة ، ونسي إصلاحه. نتيجة لذلك ، تتم مقارنة سلسلة str مع BEFORE_STR_OLD مرتين. على الأرجح ، يجب أن تكون إحدى المقارنات مع AFTER_STR_OLD .

IntelliJ IDEA، Typo


 public synchronized boolean isIdentifier(@NotNull String name, final Project project) { if (!StringUtil.startsWithChar(name,'\'') && !StringUtil.startsWithChar(name,'\"')) { name = "\"" + name; } if (!StringUtil.endsWithChar(name,'"') && !StringUtil.endsWithChar(name,'\"')) { name += "\""; } .... } 

تحذير PVS-Studio: V6001 [CWE-571] هناك تعبيرات فرعية متطابقة '! StringUtil.endsWithChar (الاسم ،' "')' إلى اليسار وإلى يمين المشغل '&&'. JsonNamesValidator.java 27

يتحقق جزء التعليمات البرمجية هذا من أن الاسم محاط بعلامات اقتباس مفردة أو مزدوجة. إذا لم يكن الأمر كذلك ، تتم إضافة علامات اقتباس مزدوجة تلقائيًا.

بسبب خطأ مطبعي ، يتم فحص نهاية الاسم فقط لوجود علامات اقتباس مزدوجة. نتيجة لذلك ، سيتم معالجة الاسم في علامات اقتباس مفردة بشكل غير صحيح.

الاسم

 'Abcd' 

بسبب إضافة علامات الاقتباس المزدوجة ستتحول إلى:

 'Abcd'" 

IntelliJ IDEA ، حماية غير صحيحة من تجاوز الصفيف


 static Context parse(....) { .... for (int i = offset; i < endOffset; i++) { char c = text.charAt(i); if (c == '<' && i < endOffset && text.charAt(i + 1) == '/' && startTag != null && CharArrayUtil.regionMatches(text, i + 2, endOffset, startTag)) { endTagStartOffset = i; break; } } .... } 

تحذير PVS-Studio: V6007 [CWE-571] التعبير 'i <endOffset' صحيح دائمًا. EnterAfterJavadocTagHandler.java 183

تعبير subpresspress i <endOffset في حالة إذا كان عامل التشغيل غير منطقي. المتغير i دائمًا أقل من endOffset في أي حال ، والذي يتبع من حالة تنفيذ الحلقة.

على الأرجح ، أراد مطور للحماية من تجاوز سلسلة عند استدعاء وظائف:

  • text.charAt (i + 1)
  • CharArrayUtil.regionMatches (النص ، i + 2 ، endOffset ، startTag)

في هذه الحالة ، يجب أن يكون التعبير الفرعي للتحقق من الفهرس: (i) <endOffset-2 .

IntelliJ IDEA ، التدقيق المتكرر


 public static String generateWarningMessage(....) { .... if (buffer.length() > 0) { if (buffer.length() > 0) { buffer.append(" ").append( IdeBundle.message("prompt.delete.and")).append(" "); } } .... } 

تحذير PVS-Studio: V6007 [CWE-571] تعبير 'buffer.length ()> 0' صحيح دائمًا. DeleteUtil.java 62

هذا يمكن أن يكون إما رمز زائدة ضارة أو خطأ فادح.

إذا ظهر فحص مكرر بطريق الخطأ ، على سبيل المثال أثناء إعادة التجهيز ، فلا حرج في ذلك. يمكنك ببساطة حذف الاختيار الثاني.

سيناريو آخر ممكن أيضا. يجب أن يكون الاختيار الثاني مختلفًا تمامًا ويتصرف الرمز كما هو غير مقصود. ثم إنه خطأ حقيقي.

ملاحظة بالمناسبة ، هناك الكثير من الشيكات الزائدة عن الحاجة. حسنًا ، غالبًا ما يكون واضحًا أنه ليس خطأ. ومع ذلك ، لا يمكننا اعتبار تحذيرات المحلل ايجابيات كاذبة. للحصول على توضيح ، أود ذكر مثال على ذلك ، مأخوذ أيضًا من IntelliJ IDEA:

 private static boolean isMultiline(PsiElement element) { String text = element.getText(); return text.contains("\n") || text.contains("\r") || text.contains("\r\n"); } 

يقول المحلل أن نص الدالة. يحتوى ("\ r \ n") دائمًا على خطأ. في الواقع ، إذا لم يتم العثور على الحرف "\ n" و "\ r" ، فلا فائدة من البحث عن "\ r \ n". إنه ليس خطأ ، والرمز سيء فقط لأنه يعمل بشكل أبطأ قليلاً ، ويقوم بإجراء بحث لا معنى له عن سلسلة فرعية.

كيفية التعامل مع هذا الرمز ، في كل حالة ، هي مسألة للمطورين. عند كتابة المقالات ، أنا عادة لا تولي اهتماما لمثل هذا الرمز.

فكرة IntelliJ ، هناك خطأ ما


 public boolean satisfiedBy(@NotNull PsiElement element) { .... @NonNls final String text = expression.getText().replaceAll("_", ""); if (text == null || text.length() < 2) { return false; } if ("0".equals(text) || "0L".equals(text) || "0l".equals(text)) { return false; } return text.charAt(0) == '0'; } 

تحذير PVS-Studio: V6007 [CWE-570] تعبير '"0". المساواة (النص)' غير صحيح دائمًا. ConvertIntegerToDecimalPredicate.java 46

يحتوي الكود على خطأ منطقي بالتأكيد. أجد صعوبة في تحديد ما يريده المبرمج بالتحديد وكيفية تصحيح الخلل. حتى هنا ، سأشير فقط إلى فحص لا معنى له.

في البداية يجب التحقق من أن السلسلة تحتوي على رمزين على الأقل. إذا لم يكن الأمر كذلك ، فستُرجع الدالة false .

التالي يأتي التحقق "0". المساواة (النص) . إنه لا معنى له ، لأنه لا يمكن أن تحتوي السلسلة على حرف واحد فقط.

لذلك ، هناك خطأ ما هنا ، ويجب إصلاح الكود.

SpotBugs (خليفة FindBugs) ، خطأ في تحديد عدد مرات التكرار


 public static String getXMLType(@WillNotClose InputStream in) throws IOException { .... String s; int count = 0; while (count < 4) { s = r.readLine(); if (s == null) { break; } Matcher m = tag.matcher(s); if (m.find()) { return m.group(1); } } throw new IOException("Didn't find xml tag"); .... } 

تحذير PVS-Studio: V6007 [CWE-571] تعبير 'العد <4' صحيح دائمًا. Util.java 394

من الناحية النظرية ، يجب إجراء البحث عن علامة xml فقط في الأسطر الأربعة الأولى من الملف. ولكن نظرًا لحقيقة نسيان زيادة متغير العدد ، سيتم قراءة الملف بالكامل.

أولاً ، قد تكون هذه عملية بطيئة للغاية ، وثانياً ، في مكان ما في منتصف الملف ، قد يتم العثور على شيء يمكن اعتباره علامة xml ، وليس كونه.

SpotBugs (خليفة FindBugs) ، تطهير قيمة


 private void reportBug() { int priority = LOW_PRIORITY; String pattern = "NS_NON_SHORT_CIRCUIT"; if (sawDangerOld) { if (sawNullTestVeryOld) { priority = HIGH_PRIORITY; // <= } if (sawMethodCallOld || sawNumericTestVeryOld && sawArrayDangerOld) { priority = HIGH_PRIORITY; // <= pattern = "NS_DANGEROUS_NON_SHORT_CIRCUIT"; } else { priority = NORMAL_PRIORITY; // <= } } bugAccumulator.accumulateBug( new BugInstance(this, pattern, priority).addClassAndMethod(this), this); } 

تحذير PVS-Studio: V6021 [CWE-563] تم تعيين القيمة للمتغير "الأولوية" ولكن لا يتم استخدامها. FindNonShortCircuit.java 197

يتم تعيين قيمة متغير الأولوية اعتمادًا على قيمة المتغير sawNullTestVeryOld . ومع ذلك ، لا يهم على الإطلاق. بعد ذلك ، سيتم تعيين متغير الأولوية قيمة أخرى في أي حال. خطأ واضح في منطق الوظيفة.

SonarQube ، نسخ لصق


 public class RuleDto { .... private final RuleDefinitionDto definition; private final RuleMetadataDto metadata; .... private void setUpdatedAtFromDefinition(@Nullable Long updatedAt) { if (updatedAt != null && updatedAt > definition.getUpdatedAt()) { setUpdatedAt(updatedAt); } } private void setUpdatedAtFromMetadata(@Nullable Long updatedAt) { if (updatedAt != null && updatedAt > definition.getUpdatedAt()) { setUpdatedAt(updatedAt); } } .... } 

PVS-Studio: V6032 من الغريب أن يكون نص الأسلوب "setUpdatedAtFromDefinition" مساوياً تمامًا لجسم طريقة أخرى "setUpdatedAtFromMetadata". خطوط التحقق: 396 ، 405. RuleDto.java 396

يتم استخدام مجال التعريف في طريقة setUpdatedAtFromMetadata . على الأرجح ، يجب استخدام حقل بيانات التعريف . هذا مشابه جدًا لآثار فشل نسخ اللصق.

SonarJava ، التكرارات عند تهيئة الخريطة


 private final Map<JavaPunctuator, Tree.Kind> assignmentOperators = Maps.newEnumMap(JavaPunctuator.class); public KindMaps() { .... assignmentOperators.put(JavaPunctuator.PLUSEQU, Tree.Kind.PLUS_ASSIGNMENT); .... assignmentOperators.put(JavaPunctuator.PLUSEQU, Tree.Kind.PLUS_ASSIGNMENT); .... } 

تحذير PVS-Studio: V6033 [CWE-462] تمت إضافة عنصر يحمل نفس المفتاح "JavaPunctuator.PLUSEQU". خطوط التحقق: 104 ، 100. KindMaps.java 104

يتم تعيين نفس زوج قيمة المفتاح في الخريطة مرتين. على الأرجح ، حدث ذلك عن غير قصد وفي الواقع لا يوجد خطأ حقيقي. ومع ذلك ، يجب التحقق من هذا الرمز في أي حال ، لأنه ربما ينسى أحدهم إضافة أي زوج آخر.

الخاتمة


لماذا تكتب الخاتمة عندما تكون واضحة؟ أقترح عليك جميعًا تنزيل PVS-Studio في الوقت الحالي ومحاولة التحقق من مشاريع عملك على لغة Java! تحميل PVS-Studio .

شكرا لكم جميعا على اهتمامكم. آمل أن نتمكن قريبًا من إرضاء قرائنا بمجموعة من المقالات حول التحقق من مختلف مشاريع Java مفتوحة المصدر.

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


All Articles