Pull to refresh
43
0

Разработчик

Send message
Вы точно про этот пример? Здесь перепутали && и ||.
String colOrScalar1 = tdesc[4];
....
if (colOrScalar1.equals("Col") &&
    colOrScalar1.equals("Column")) {
    ....
} else if (colOrScalar1.equals("Col") &&
           colOrScalar1.equals("Scalar")) {
    ....
} else if (colOrScalar1.equals("Scalar") &&
           colOrScalar1.equals("Column")) {
    ....
}

Такой паттерн это же явно баг.
Мы в таких отдельных случаях смотрим оригинальный код (spoon запоминает позиции для элементов).
Если еще проще, то мы взяли dataflow анализатор и еще некоторый функционал из C++ анализатора и прикрутили его к Java анализатору (почти как библиотеку).
Про C# я не знаю наверняка, но думаю что на тот момент и инфраструктура C++ анализатора тоже не позволила бы так просто перенести что-либо в C#.
Да такое мы различаем, благодаря тому, что dataflow взяли из C++. Там ведь возможна аналогичная ситуация:
  int *ptr1 = ....;
  int *ptr2 = ....;
  if (*ptr1 == *ptr2 && ptr1 != ptr2) { .... }

Если в двух словах, то виртуальные значения для ссылок в Java, это наши виртуальные значения для указателей из C++. А виртуальное значение для указателя может, в свою очередь, содержать «boxed» значение (например целого числа, строки, и т.п.).
Ну и соответственно, в одном случае сравниваются виртуальные значения строк, а в другом указателей ссылок.
Да, срабатываний мало, особенно относительно других проектов :)
На таком варианте тоже будет срабатывание. Мы используем эвристику для определения «похожести».
Сталкивались с подобным, когда разрабатывали maven-плагин:
@Parameter(defaultValue = "${reactorProjects}", readonly = true)
private List<MavenProject> reactorProjects;

Так что стараемся учитывать подобный код.
Или вот еще например:
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);
    }
  }

Что-то мне подсказывает, что здесь скопипастили и забыли во втором случае поменять definition на metadata.
К слову, пример вполне реальной ошибки, которую нашел наш анализатор в самом проекте SonarQube:

V6029 Possible incorrect order of arguments passed to method: 'parent', 'profile'. InheritanceActionTest.java 254:
  private void setParent(QProfileDto profile, QProfileDto parent) {
    ruleActivator.setParentAndCommit(dbSession, parent, profile);
  }


RuleActivator.java
 public List<ActiveRuleChange> setParentAndCommit(
   DbSession dbSession, 
   QProfileDto profile,
   @Nullable QProfileDto parent) {
    .... 
}
Да, здесь я сам накосячил, извините :)
Пример неудачный, заменил его другим.
Давайте взглянем на код вызываемых методов:

bool KoChangeTracker::displayChanges() const
{
    return d->displayChanges;
}


KoChangeTracker *KoTextDocumentLayout::changeTracker() const
{
    return d->changeTracker;
}

Как мы видим, changeTracker() просто возвращает указатель из приватного поля d, а displayChanges() просто возвращает bool из приватного поля d.
При этом, между вызовами эти значения не изменяются. Анализатор понимает это и выдает предупреждение.
Т.е. в данном случае анализатор производит анализ тел вызываемых методов и собирает информацию о модифицируемых переменных, а вовсе не ограничивается простым паттерн-матчингом вида x || !x.

Код условия целиком

Эта информация собирается визитором на стороне Java. А механизм Data-Flow просто не будет задействован в таком случае. Думаю, по возможности, мы как-нибудь расскажем обо всем поподробнее.
На самом деле, генерировать JNI обертки с помощью SWIG не так уж сложно.
Ну и очевидно, что Spoon мы юзаем, из-за того, что наш C++ парсер не очень подходит для разбора Java =).
А вот в механизме Data-Flow ничего специально мы не делали, чтобы поддержать такое в Java.

В ваших примерах варнинги не сохраняются, раз вы предоставляете публичный интерфейс для изменения содержимого массива.
Можно, конечно, упомянуть межмодульный анализ, однако вряд ли разработчики библиотеки станут без необходимости делать этот массив публичным.
Вот небольшая заметка на тему синтетических тестов.
SonarLint, например, молчит на втором примере из статьи:
if (idx1 > 0 && idx2 > 0 &&
    (idx3 < 0 || (idx2 < idx3 && idx3 > 0))) {
    ....
}

На мой взгляд, Data Flow анализ в нем слабый. Явно слабее того, что мы можем предоставить уже сейчас.

Кроме того, механизм аннотаций не развит. Не находятся ошибки такого типа:
int test1(int a, int b)
{
  int x = Math.max(a, a); // <=
  return x + b;
}

String test2(String a)
{
  return a.replace("aaa", "aaa"); // <=
}

Подобные ошибки часто допускают из-за опечаток и упускать их точно не стоит.

При этом, без предварительной настройки, SonarLint уж очень сильно «шумит».
Также, у нас есть ряд уникальных диагностик в C++ и C# анализаторах, которые будут перенесены в анализатор Java.
Короче говоря, конкурентные преимущества будут.
Для прототипа мы решили использовать дерево и семантическую модель из spoon, т.к это позволяет существенно ускорить разработку.
Поэтому и сами диагностические правила также пишутся на Java.
В общем случае такой подход не подойдет. Например для std::is_class или std::is_arithmetic.
На вход to_chars подаются тоже указатели. А вообще, to_chars была так спроектированна именно для максимально быстрого преобразования.
Так написать можно. Structured bindings, как было сказано в статье, умеют производить декомпозицию типов, содержащих только нестатические открытые члены.
1

Information

Rating
Does not participate
Registered
Activity