Ignorar los encabezados del sistema en clang-tidy

8 minutos de lectura

tldr;> ¿Cómo oculto las advertencias de los encabezados del sistema en clang-tidy?

Tengo el siguiente archivo fuente de ejemplo mínimo, que activa una advertencia de aviso en los encabezados del sistema:

#include <future>

int main() {
  std::promise<int> p;
  p.set_value(3);
}

Llamándolo con libstdc++ 7.0.1 usando clang-tidy 4.0.0 en Ubuntu 17.04:

$ clang-tidy main.cpp -extra-arg=-std=c++14

rendimientos

Running without flags.
1 warning generated.
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/mutex:693:5: warning: Address of stack memory associated with local variable '__callable' is still referred to by the global variable '__once_callable' upon returning to the caller.  This will be a dangling reference [clang-analyzer-core.StackAddressEscape]
    }
    ^
/home/user/main.cpp:5:3: note: Calling 'promise::set_value'
  p.set_value(3);
  ^
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/future:1094:9: note: Calling '_State_baseV2::_M_set_result'
      { _M_future->_M_set_result(_State::__setter(this, std::move(__r))); }
        ^
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/future:401:2: note: Calling 'call_once'
        call_once(_M_once, &_State_baseV2::_M_do_set, this,
        ^
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/mutex:691:11: note: Assuming '__e' is 0
      if (__e)
          ^
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/mutex:691:7: note: Taking false branch
      if (__e)
      ^
/usr/lib/gcc/x86_64-linux-gnu/7.0.1/../../../../include/c++/7.0.1/mutex:693:5: note: Address of stack memory associated with local variable '__callable' is still referred to by the global variable '__once_callable' upon returning to the caller.  This will be a dangling reference
    }

Quiero ocultar las advertencias en los encabezados del sistema. Intenté lo siguiente:

$ clang-tidy -extra-arg=-std=c++14 main.cpp -header-filter=$(realpath .) -system-headers=0

pero la advertencia todavía se muestra.

  • Aparte: Esa advertencia fue suprimida en GCC 7.3 (su PR 82481 error), pero las versiones recientes de clang-tidy no parecen dar esa advertencia de todos modos, incluso con -system-headers.

    –Jonathan Wakely

    13 de enero de 2021 a las 10:53


  • Esto no funciona de forma genérica, pero puede usar la definición __clang_analyzer__ para evitar el análisis. Si se trata de un código generado por una máquina como qt moc, a menudo algunas declaraciones simples pueden evitar procesar el archivo generado por la máquina con clang-tidy. También puede funcionar para algunos archivos de encabezado. No funcionará para este ejemplo con plantillas… pero para otras situaciones podría ser útil.

    – ruido sin arte

    16 de noviembre de 2021 a las 20:47

avatar de usuario
jason creighton

También me encontré con este problema y pasé un tiempo tratando de resolverlo, pero no pude ver una manera de desactivar este tipo de advertencia en clang-tidy.

de la lectura esta discusión sobre el rastreador de problemas de LLVM con respecto a un problema similarme da la impresión de que el problema es que desde la perspectiva de clang-tidy, la advertencia en realidad se encuentra en main.cppporque la llamada a set_value es de ahi

Mi solución ha sido deshabilitar las comprobaciones de análisis estático en clang-tidy y usar el utilidad de escaneo y construcción para ejecutar el análisis estático de clang, que parece evitar estos problemas. Por ejemplo, usando su main.cpp:

$ scan-build-3.9 clang++ -std=c++14 main.cpp 
scan-build: Using '/usr/lib/llvm-3.9/bin/clang' for static analysis
In file included from main.cpp:1:
In file included from /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/future:39:
/usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/mutex:621:11: warning: Address of stack memory associated with local variable '__callable' is still referred to by the global variable '__once_callable' upon returning to the caller.  This will be a dangling reference
      if (__e)
          ^~~
1 warning generated.
scan-build: Removing directory '/tmp/scan-build-2017-12-02-112018-13035-1' because it contains no reports.
scan-build: No bugs found.

El analizador encuentra el mismo error en un encabezado del sistema, pero es lo suficientemente inteligente como para no incluirlo en el informe final. (“No se encontraron errores”)

Aún necesitará ejecutar clang-tidy por separado si está interesado en las advertencias de tipo de guía de estilo, como modernize-* o readability-*.

  • Como lo hizo disabled the static analysis checks in clang-tidy?

    –Livne Rosenblum

    27 de diciembre de 2020 a las 10:39

  • scan-build seguirá informando el error si intenta excluir un encabezado que no sea del sistema pasándolo como -isystem.

    – Martín

    19 de febrero de 2021 a las 17:28

avatar de usuario
pete baughman

Inicialmente llegué a la conclusión de que esto no era posible, pero tengo un truco que se acerca bastante.

Cuando compilo, uso CMAKE_EXPORT_COMPILE_COMMANDS=ON, que genera un archivo compile_commands.json que muestra qué comandos se pasaron al compilador para cada archivo cpp compilado. cuando corro clang-tidy Le doy la opción -p para apuntar al directorio que contiene este archivo.

Una entrada típica en este archivo se parece a esto:

{
  "directory": "/project/build/package1",
  "command": "/usr/bin/clang++-9 -I/opt/thirdparty/include -isystem /usr/include . . . /project/src/package1/src/foo.cpp",
  "file": "/project/src/package1/src/foo.cpp"
},

Si vuelvo a escribir este archivo para que -I/opt/thirdparty/include se convierte -isystem /opt/thirdparty/include los encabezados previamente problemáticos en /opt/third-party/include se ignoran porque clang-tidy los verá como encabezados del sistema.

yo suelo sed para reescribir el archivo

# Trick clang-tidy into thinking anything in /opt/thirdparty/include is a system header
sed -i 's|-I/opt/thirdparty/include|-isystem /opt/thirdparty/include|g' build/compile_commands.json
# Run clang-tidy using the run-clang-tidy python wrapper
run-clang-tidy.py -p build -header-filter .* $(find src -iname "*.cpp")

  • Si está usando CMake, usando el SYSTEM palabra clave en su target_include_directories llamar a sus directorios de inclusión de terceros personalizados debe hacer lo que quiera sin tener que editar los comandos de compilación. cmake.org/cmake/help/v3.16/command/… y cmake.org/cmake/help/v3.16/manual/…

    – Kymiko Loco

    21 de febrero de 2020 a las 19:58

  • Desafortunadamente, estaba lidiando con una compilación que contenía muchos proyectos de CMake, algunos de terceros que no se podían cambiar fácilmente.

    –Pete Baughman

    21 de febrero de 2020 a las 21:02

  • Acabo de probar esto en un proyecto de prueba usando clang-tidy de LLVM 6.0.0; no funciona. Todavía veo que se generan las advertencias, aunque intenté usar -isystem y --system-header-prefix.

    – Martín

    18 de febrero de 2021 a las 0:19

  • Lo siento, es un fastidio, funcionó para mí, pero actualmente no estoy haciendo ningún trabajo para la empresa que necesitaba esto, así que no puedo volver atrás y jugar con él para tratar de averiguar qué podría estar mal cuando lo pruebes. Ni siquiera recuerdo la versión clang-tidy que estaban usando.

    –Pete Baughman

    3 de mayo de 2021 a las 3:37

avatar de usuario
cristian

Mi solución a este problema es ejecutar clang-tidy desde un script y luego filtre todos los problemas según la ubicación del archivo porque los problemas del código de usuario se encuentran en, por ejemplo, C:\Repos\myLibmientras que los problemas de los encabezados del sistema se encuentran en C:\Program Files (x86) o similar.

El guion es un powershell guión, tal vez puedas hacer algo similar con bash:

# clang-filter-user-code.ps1
Param(
    [parameter(Mandatory=$true)]
    [string]$CLANG_TIDY,
    [parameter(Mandatory=$true)]
    [string[]]$SOURCE_FILES,
    [parameter(Mandatory=$true)]
    [string]$SOURCE_DIR,
    [parameter(Mandatory=$true)]
    [string]$TARGET_DIR
)

$TMP = $TARGET_DIR + "/tmp-clang-output.txt"
$PATTERN = "(?s)(" + $SOURCE_DIR.Replace("/", "\\") + "[^\^]*\^)"

# Reading the content as Raw text, where everything is stored within one line, is only possible with specifying a path to a file.
# Therefore we store the clang-tidy output in a temporary file, that is deleted afterwards.
&($CLANG_TIDY) $SOURCE_FILES > $TMP
Get-Content -Raw -Path $TMP | Select-String -Pattern $PATTERN -AllMatches | Select-Object -ExpandProperty Matches | % {$_.Groups[1].Value }
Remove-Item $TMP

Debe pasar la ruta a clang-tidy, sus archivos de origen, la ruta de su directorio de origen y la ruta de su directorio de destino al script.

Usando CMAKEpuede integrar esto en su compilación:

# clang-dev-tools.cmake
function(PREPARE_SOURCE_FILE_LIST SOURCE_FILES OUTPUT)
    # Put each entry between single quotes
    foreach(SOURCE_FILE ${SOURCE_FILES})
        list(APPEND SOURCE_FILES_LIST '${SOURCE_FILE}')
    endforeach()

    # Join all entries using comma as delimiter - based on https://stackoverflow.com/questions/7172670/best-shortest-way-to-join-a-list-in-cmake
    string(REGEX REPLACE "([^\\]|^);" "\\1," TMP_STR "${SOURCE_FILES_LIST}")
    string(REGEX REPLACE "[\\](.)" "\\1" TMP_STR "${TMP_STR}") #fixes escaping
    set(${OUTPUT} "${TMP_STR}" PARENT_SCOPE)
endfunction()

# Detect all source files
file(GLOB_RECURSE
        SOURCE_FILES
        ${CMAKE_SOURCE_DIR}/Src/Libs/*/Src/*.cpp
        ${CMAKE_SOURCE_DIR}/Src/Libs/*/Src/*.h)

find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-6.0)
if (CLANG_TIDY)
    PREPARE_SOURCE_FILE_LIST("${SOURCE_FILES}" SOURCE_FILES_LIST)
    set(SCRIPT_ARGUMENTS "-CLANG_TIDY" '${CLANG_TIDY}' "-SOURCE_FILES" ("${SOURCE_FILES_LIST}") "-SOURCE_DIR" '${CMAKE_SOURCE_DIR}' "-TARGET_DIR" '${CMAKE_BINARY_DIR}')
    
    # Because clang-tidy also detects warnings/errors in non-user code, we need to filter its output via this script.
    add_custom_command(
        OUTPUT clang-output
        COMMAND PowerShell (${CMAKE_CURRENT_SOURCE_DIR}/cmake/clang-filter-user-code.ps1 ${SCRIPT_ARGUMENTS})
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )
    add_custom_target(
        FilterClang ALL 
        DEPENDS clang-output
    )
endif ()

no estoy tan familiarizado con ambos CMAKE y powershellasí que tengan paciencia conmigo si no encuentro la solución más elegante.

También hay un abra relaciones públicas a una solución aún mejor en LLVMpero dado que ya está abierto desde hace casi 4 años, no sabemos si llegará ni cuándo.

¿Ha sido útil esta solución?