Compilers static code analyzers

This is just a small note about the options of the different C++ compilers to do a static code analysis. This are different from the standard compiler warnings and are in principle similar to Coverity, PVS-Studio and CodeQL scanners that we have already been running in the past. Since this are part of the standard compilers I do not plan to make regular reports with them, as with the other tools, but it can be good if developers run this for themselves from time to time…

msvc /analyze

Code analysis for C/C++ overview
https://docs.microsoft.com/en-us/cpp/code-quality/code-analysis-for-c-cpp-overview?view=msvc-160

/analyze (Code analysis)
https://docs.microsoft.com/en-us/cpp/build/reference/analyze-code-analysis?view=msvc-160


clang scan-build

Clang Static Analyzer
https://clang-analyzer.llvm.org/


gcc -c -fanalyzer

Static analysis in GCC 10
https://developers.redhat.com/blog/2020/03/26/static-analysis-in-gcc-10/


_A general post about the security and code quality tools https://forum.freecadweb.org/viewtopic.php?f=10&t=32602#p274069_

In my not-up-to-date kdevelop (5.2.1), there is a plugin called cppcheck, which does static code analysis on the go. I find it a very nice aid.

I have read that they have support for other static code analysis tools (clang-tidy). I have not tried that any other, so I do not know how they would compare…

All of the above mentioned tools require to run a build (compilation) of the code, because they analyze the trace of the build process and are in this way able to do a deeper and more advanced analysis of the code execution, even across different functions and files, compared to the more simple “linter” tools that mostly do direct string pattern searches on the source code… But yes, those are also good, different tools can help on different levels and with different problems.

These link might be useful to use clang-tidy with CMake projects:
https://ortogonal.github.io/cmake-clang-tidy/
https://www.kdab.com/clang-tidy-part-1-modernize-source-code-using-c11c14/
https://www.kdab.com/clang-tidy-part-2-integrate-qmake-and-other-build-systems-using-bear/
https://stackoverflow.com/questions/57082124/how-to-integrate-clang-tidy-to-cmake-and-gcc

https://www.kdab.com/cant-the-compiler-do-that/
https://www.reddit.com/r/cpp/comments/b2jl18/how_do_you_work_around_clangtidy_not_being_able/
https://bcain-llvm.readthedocs.io/projects/clang-tools-extra/en/latest/clang-tidy/checks/modernize-use-transparent-functors/

Two methods to use clang-tidy with CMake:

CMAKE_CXX_CLANG_TIDY=“clang-tidy;-checks=-*,modernize-redundant-void-arg;-fix”


By running _make_ the changes are performed on-the-fly
2. ```text
CMAKE_EXPORT_COMPILE_COMMANDS=ON

Running make creates the file compile_commands.json. By running the Python script run-clang-tidy.py the changes are performed at the end of the build process

run-clang-tidy.py -clang-apply-replacements-binary=/usr/bin/clang-apply-replacements-6.0 -header-filter='.*' -checks='-*,modernize-redundant-void-arg' -fix

Just a simple example of cppcheck, which came by today while coding. Underlined, hover it, problem description:
Screenshot_20201229_110951.png

That’s a good example that proves that you shouldn’t re-invent the wheel. It’s not only about the warnings but it’s that your algorithm simply doesn’t work reliably.

Assuming you have a list of groups with these sizes [6, 5, 3, 1, 8, 7, 2, 4] your algorithm will sort the list to be [5, 3, 1, 6, 7, 2, 4, 8] which is not the expected result. What you need is an outer loop to repeat the inner loop until no swapping is performed any more. This algorithm is known as bubble sort that shouldn’t be used in practice as its complexity is O(n**2)

You better use the algorithm offered by the standard library: std::sort

std::sort(groups.begin(), groups.end(), [](const std::set<double*>& a, const std::set<double*>& b) {
    return a.size() < b.size();
});

Here is a demo to show the difference between the broken sort and std::sort:

#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector < std::vector < int > > tmp;
    tmp.push_back({0,1,2,3,4,5});
    tmp.push_back({0,1,2,3,4});
    tmp.push_back({0,1,2});
    tmp.push_back({0});
    tmp.push_back({0,1,2,3,4,5,6,7});
    tmp.push_back({0,1,2,3,4,5,6});
    tmp.push_back({0,1});
    tmp.push_back({0,1,2,3});

    std::vector < std::vector < int > > groups = tmp;
    for (const auto& it : groups) {
        std::cout << it.size() << ", ";
    }
    std::cout << '\n';

    for (int i=0; i<groups.size()-1; i++) {
        if (groups[i].size() > groups[i+1].size()) {
            std::swap(groups[i], groups[i+1]);
        }
    }
    for (const auto& it : groups) {
        std::cout << it.size() << ", ";
    }
    std::cout << '\n';

    groups = tmp;
    std::sort(groups.begin(), groups.end(), [](const std::vector < int >& a, const std::vector < int >& b){
        return a.size() < b.size();
    });
    for (const auto& it : groups) {
        std::cout << it.size() << ", ";
    }
    std::cout << '\n';
}

To the latter: it is true. I had fixed it in the meanwhile. Not that a static code analyzer could detect that one…

Thanks! Not to reinvent the wheel one needs to know an existing proven wheel. It is unfortunately not my case in many aspects of STL.

Thanks! Not to reinvent the wheel one needs to know an existing proven wheel. It is unfortunately not my case in many aspects of STL.

Yes, it’s pretty hard to find and know all that goodies provided by the STL and with C++11 a ton of new handy things have been added. However, std::sort was already part of C++98 and I have thought that every C++ developer knows about it.

The probably most complete resource is https://en.cppreference.com/w/cpp and especially https://en.cppreference.com/w/cpp/header/algorithm is interesting to see what useful functions are available.

Oh! That last link is very handy.

I am not a professional c++ developer. I am a hobbyist who likes writing software and who writes code exclusively for FreeCAD (safe for some diy Arduinos and the like).

I have read many of the excellent Scott Meyers’ books (a pity he retired. He well deserved it. But my library misses him as much as he missed Darla, his black labrador retriever). I haven’t read the STL one though. I did not buy it because I presume it is very outdated.

I am aware I lack a background in many software engineering concepts. For example, in the algorithm I am writing, in one of the multiple iterations, I though of using a tree. I read wikipedia, stackoverflow and boost documentation for adjacent lists. I read about the multiple algorithms and ways to traverse a tree. I realised how much I do not know about graphs, adjacent lists and trees and related algorithms, and how these are important to solve more complex problems. These are most probably university level basic software engineering concepts that, if I want to improve, I need to learn.

Probably, my next personal development step will be to improve my STL and boost skills. If anybody knows about a good book, feel free to post a link.

Awesome, I didn’t know that GCC had this feature. Do you have some hints on how to make use of this on linux. What editor/ide to use, do they support some kind of language server that can give you the feedback as you code, or do you have to to a trial compilation to get the analysis?

I am also only a hobbyist developer, but I used this type of functionality when working on a java project using the IntelliJ IDEA ide on windows (and Visual studio, and android studio also).

The second link shows a nice feature: You can apply fix-it to a modernize checker. The override example is nice one because it is painless automated work. Should we consider running (some of) these modernize checks on FreeCAD?

According to a comment. Cppcheck GUI (not cppcheck) integrates clang-tidy (to which extent I have not investigated yet).

There is a list of supported IDEs here:
https://clang.llvm.org/extra/clang-tidy/Integrations.html

I downloaded the latest kdevelop appimage (5.6.1). It integrates both clangtidy and cppcheck.

I will play with it for a while. I do not like the lack of theme integration of the appimage though.

Yes, we can do that but I suggest to start with it with the v0.20 development. As a test I once played a bit with it where the old C headers have been replaced with their modern C++ counterparts: https://github.com/wwmayer/FreeCAD/commit/82293680981fed874fea2118f89f342ba1293377

That is cool. For sure, v0.20 is fine.

Just my two cents, cppchecker 2.3 has embedded support for cmake projects, described very well in the pdf documentation. It took some minor effort to run, but it reports about 1300 unused functions, with some false positives due to poor template handling. There are some concerning ones in there :laughing: :

FreeCAD/src/Base/Parameter.cpp:1768:0: style: The function ‘handleError’ is never used. [unusedFunction]
FreeCAD/src/Mod/Mesh/App/Core/MeshIO.cpp:1770:0: style: The function ‘SetSTLHeaderData’ is never used. [unusedFunction]
FreeCAD/src/Base/Builder3D.cpp:421:0: style: The function ‘addMaterialBinding’ is never used. [unusedFunction]
FreeCAD/src/App/PropertyGeo.cpp:935:0: style: The function ‘getPlacementObject’ is never used. [unusedFunction]

:laughing: :laughing: :laughing:

For those using Vscode , and have clang available, there is this wonderful guide:
https://github.com/fbaeuerlein/cpp-vscode-guide/blob/master/doc/StaticAnalysis.md
EDIT: here is a USEFUL configuration set for VsCode + Clang-tidy that does not generate 1000+ warnings per file:

 "clang-tidy.checks": [

        
        "bugprone-",
        "cert-",
        "clang-analyzer-",
        "cppcoreguidelines-",
        "-cppcoreguidelines-pro-type-vararg",
        "-cppcoreguidelines-pro-bounds-array-to-pointer-decay",
        "llvm-",
        "-llvm-include-order",
        "misc-",
        "modernize-",
        "-modernize-use-trailing-return-type",
        "-modernize-concat-nested-namespaces",
        "performance-",
        "readability-*",
        "-readability-braces-around-statements",
        "-readability-implicit-bool-conversion"
        ],
    "clang-tidy.compilerArgs" : [ "-std=c++11" ], 
    "clang-tidy.buildPath" : "build/", 
    "clang-tidy.executable": "clang-tidy",