qconnectlint is a Clang tool for statically verifying the consistency of signal and slot connections made with Qt's QObject::connect
. It can detect the following problems:
- Signals or slots not existing with the expected signature
- Incompatible signal and slot signatures due to types or argument count
- Slots being used as signals
A recent compiler toolchain supporting C++11 is required. GCC 4.7 or Clang 3.1 should be sufficient.
- Download the source for LLVM and Clang 3.2
- Check out qconnectlint as
tools/clang/tools/qconnectlint
- Run
./configure --enable-cxx11
in the root LLVM directory
--enable-libcpp
is required on Mac OS X due to the distributed libstdc++ not supporting C++11--disable-assertions --enable-optimized
is recommended for performance reasons. These flags are typically used when building a distribution's version of Clang.--prefix
can be used to install qconnectlint's copy of LLVM and Clang to a non-default location.
- Run the following from LLVM's root directory
$ make install && cd tools/clang/tools/qconnectlint && make install
If a Clang compilation database exists for the project qconnectlint
can be invoked with a list of source files to lint.
If no database is present the list of source files must be followed with a delimiting --
and a list of compiler flags exactly as they would be passed to Clang. For example, the following would check the files test1.cpp
and test2.cpp
with some typical compiler flags:
$ qconnectlint test1.cpp test2.cpp -- -std=c++11 -Wall -I/usr/include/qt4
qconnectlint's output mimics Clang's format. This means tools intended to parse the output of Clang should easily handle lint reports. An example Vim compiler plugin is included in the vim
directory.
qconnectlint is limited to static analysis using information available at compile time. This has a number of consequences:
- Signals and slots must be referenced using inline
SIGNAL()
andSLOT()
macros when callingconnect()
. For example, passing a signal/slot to a function that indirectly callsconnect()
itself won't be checked - Passing a derived class pointer upcast to a base class (typically QObject*) will falsely trigger warnings if the base class doesn't define the referenced signal/slot.
- Signal and slot annotations are lost at the preprocessor stage. As a result qconnectlint can't determine if a given class member has been defined as a signal or slot; it simply checks for the existence of a member with a matching signature.