Проверка линтера на удаление ссылок в автотипе

Я хотел знать, есть ли какая-либо опция компилятора или аккуратные проверки для этой ситуации:

#include<iostream>
#include <ostream>

int glob = 12;

int& test(int d){
    std::cout << &glob << std::endl;
    return glob;
}


int main() {

    auto a = test(10);
    std::cout << &a << std::endl;
    return 0;
}

Если я вдруг забуду поставить & после auto, я увижу в выводе разные адреса, и это ожидаемо, но есть ли какой-нибудь флаг компилятора или флаг clang-tidy, который предупреждает меня об этом?

Как проверить что-то совершенно безопасное и легальное? С таким же успехом вы можете попросить линтер проверить, не ошиблись ли вы когда-нибудь с + на -.

Passer By 11.08.2024 15:38

@PasserBy Многие предупреждения компилятора касаются вещей, которые совершенно безопасны и легальны, но тем не менее они проверяются. Например, предупреждение о назначении в состоянии if.

Yksisarvinen 11.08.2024 16:17

@Yksisarvinen Я не очень хорошо выразился. Задание в if вряд ли будет правильным. Здесь нет такого различия. То, что я хочу сказать, не следует называть «безопасным», но лучшее слово у меня ускользает.

Passer By 11.08.2024 16:25

@PasserBy if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0), этот код правильный, но в результате появляется предупреждение линтера: «Назначение в условии 'if' подвержено ошибкам: C/C++: bugprone-assignment-in-if-condition», я знаю, что это происходит из int& to int — это всего лишь копия и она безопасна, но я просто спросил, есть ли что-нибудь, что может сказать мне, что вы создаете новый экземпляр своего объекта, и вы, вероятно, не хотели этого делать.

Ahmad Mansoori 12.08.2024 07:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
182
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Мне не известно о существующем предупреждении или проверке, которая бы делала это, но есть одно можно использовать clang-запрос чтобы проверить шаблон объявления переменной с использованием типа auto (отличается от auto&) и инициализируем его вызовом функция, возвращающая ссылку.

Следующий сценарий оболочки вызывает clang-query с таким сопоставьте выражение:

#!/bin/sh

PATH=$HOME/opt/clang+llvm-16.0.0-x86_64-linux-gnu-ubuntu-18.04/bin:$PATH

# In the following, the comments are seen and ignored by clang-query
# (not the shell).  But beware that clang-query has odd rules for where
# comments can go, and poor error reporting if the rules are violated.
query='m

  varDecl(                         # Report any variable declaration
    hasType(                       # whose declared type
      autoType()                   # is `auto`,
    ),
    hasInitializer(                # and that has an initializer
      implicitCastExpr(            # that is an implicit conversion
        hasSourceExpression(       # from
          callExpr(                # a function call expression
            callee(                # where the callee
              functionDecl(        # is a directly named function
                returns(           # whose return type
                  referenceType()  # is a reference.
                )
              )
            )
          )
        )
      )
    )
  ).bind("decl")

'

if [ "x$1" = "x" ]; then
  echo "usage: $0 filename.cc -- <compile options like -I, etc.>"
  exit 2
fi

# Run the query.  Setting 'bind-root' to false means clang-query will
# not also print a redundant "root" binding.
clang-query \
  -c = "set bind-root false" \
  -c = "$query" \
  "$@"

# EOF

На следующем входе:

// test.cc
// Cases for `auto` declaring non-ref initialized from ref.

int &getref();

int getnonref();

void g(int &refparam)
{
  // ref -> ref
  auto &r2r = getref();       // not reported: no conversion

  // ref -> nonref
  auto r2nr = getref();       // reported

  // nonref -> nonref
  auto nr2nr = getnonref();   // not reported: no conversion

  // nonref -> ref: Syntax error.
  //auto &nr2r = getnonref();

  auto rp2nr = refparam;      // not reported: not a call
}

// EOF

он производит вывод:

$ ./cmd.sh test.cc --

Match #1:

$PWD/test.cc:14:3: note: "decl" binds here
  auto r2nr = getref();       // reported
  ^~~~~~~~~~~~~~~~~~~~
1 match.

В выражении соответствия я ограничиваю отчеты инициализаторами, которые вызовы функций. Однако, в зависимости от того, что вам нужно, вы можете захотеть чтобы удалить весь сопоставитель hasSourceExpression (так что За implicitCastExpr просто следует ()), таким образом сообщая о любых auto объявление, инициализированное с использованием неявного преобразования, поскольку, возможно, любое такой случай является «удивительным» и, возможно, непреднамеренным.

Я не проводил масштабного тестирования или настройки этого сопоставителя, поэтому может потребоваться дополнительная корректировка для использования в производстве.

Процедура интеграции clang-query в сборку или тест рабочий процесс в основном такой же, как и для clang-tidy, при условии, что последнее делается прямым вызовом.

Ответ: нет, не стоит этого делать. Даже если вы можете создать для этого собственные правила линтера, ответ все равно будет отрицательным. Причина в том, что какие бы правила линтера вы для этого ни создавали, они всегда будут иметь множество ложных срабатываний.

Например, в операторе a = b = c; возвращаемое значение подвыражения b = c является неконстантной ссылкой на b, значение которой затем присваивается a. Это обычный случай. Ваш пример, когда это не является намерением, является редким случаем. Когда другие люди читают ваш код, они с гораздо большей вероятностью поверят, что auto a = test(1); — правильная форма, чем форма со ссылками, особенно когда возвращаемое значение — просто целое число. Если вы хотите, чтобы что-то так сильно противоречило сути, вам нужно приложить гораздо больше усилий, чем правило линтера.

Вы можете сделать одно из следующих действий:

А. Оберните объект, который вы не хотите копировать, в структуру и удалите его конструктор копирования.

Б. Передавайте указатель вместо ссылки, чтобы операции с памятью были более очевидными.

Другие вопросы по теме