diff --git a/04-static-analysis/clang-format/.clang-format b/04-static-analysis/clang-format/.clang-format new file mode 100644 index 00000000..2ee84f8d --- /dev/null +++ b/04-static-analysis/clang-format/.clang-format @@ -0,0 +1,61 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 3 +NamespaceIndentation: All +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/04-static-analysis/clang-format/CMakeLists.txt b/04-static-analysis/clang-format/CMakeLists.txt new file mode 100644 index 00000000..0f848be3 --- /dev/null +++ b/04-static-analysis/clang-format/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required (VERSION 3.0) + +project(cppcheck_analysis) + +# Add a custom CMake Modules directory +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules + ${CMAKE_MODULE_PATH}) + +# Add sub directories +add_subdirectory(subproject1) +add_subdirectory(subproject2) + +set(CLANG_FORMAT_BIN_NAME clang-format-3.6) +find_package(ClangFormat) diff --git a/04-static-analysis/clang-format/README.adoc b/04-static-analysis/clang-format/README.adoc new file mode 100644 index 00000000..71614923 --- /dev/null +++ b/04-static-analysis/clang-format/README.adoc @@ -0,0 +1,142 @@ += clang-format +:toc: +:toc-placement!: + +toc::[] + +# Introduction + +This example shows how to call the +https://clang.llvm.org/docs/ClangFormat.html[Clang Format] to check if your source code +matches against your code style guidelines. + +The files included in this example are: + +``` +$ tree +. +├── .clang-format +├── CMakeLists.txt +├── cmake +│   ├── modules +│   │   ├── clang-format.cmake +│   │   └── FindClangFormat.cmake +│   └── scripts +│   └── clang-format-check-changed +├── subproject1 +│   ├── CMakeLists.txt +│   └── main1.cpp +└── subproject2 + ├── CMakeLists.txt + └── main2.cpp +``` + + * link:CMakeLists.txt[] - Top level CMakeLists.txt + * link:.clang-format - The file describing the stype guide + * link:cmake/modules/FindClangFormat.cmake - Script to find the clang-format binary + * link:cmake/modules/clang-format.cmake - Script to setup the format targets + * link:cmake/scripts/clang-format-check-changed - A helper script to check against changed files in git + * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1 + * link:subproject1/main.cpp[] - source for a subproject with no errors + * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2 + * link:subproject2/main2.cpp[] - source for a subproject that includes errors + +# Requirements + +To run this example you must have clang format tool installed. This can be installed on Ubuntu using the following command. + +[source,bash] +---- +$ sudo apt-get install clang-format +---- + +It will result in the tool being available as: + +[source,bash] +---- +$ clang-format +---- + +# Concepts + +## clang-format + ++clang-format+ can scan a source file then find and optionally format it to match your +companys style guidelines. There are default styles build in but you can also setup a style guide using a custom file called +.clang-format+, for example a snipped from this +repositories +.clang-format+ is below: + +[source] +---- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +---- + +By default this will run the standard compiler for your platform, i.e. `gcc` on linux. However, if you want to override this you can change the command to: + +[source,bash] +---- +$ scan-build-3.6 --use-cc=clang-3.6 --use-c++=clang++-3.6 -o ./scanbuildout/ make +---- + +## format style + +As mentioned, the style in this example is based on the +.clang-format+ file. This can be changed by editing link:cmake/modules/clang-format.cmake[clang-format.cmake] and changing +the `-style=file` to the required style; + +# Targets + +This example will setup 3 targets: + + * format + * format-check + * format-check-changed + +## format + +The format target will find any C++ source files and in place modify them to match the ++.clang-format+ style. The source files are found using the following cmake code + +[source,cmake] +---- +file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.cxx *.hxx *.hpp *.cc) + +# Don't include some common build folders +set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "build/" "/CMakeFiles/") + +# get all project files file +foreach (SOURCE_FILE ${ALL_SOURCE_FILES}) + foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS}) + string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND) + if (NOT ${EXCLUDE_FOUND} EQUAL -1) + list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE}) + endif () + endforeach () +endforeach () +---- + +This will find files matching the common C++ suffixes and then remove any that match some +common CMake build directories. + +## format-check + +This target will work as above but instead of formatting the files it will cause a failure +if any files don't match the clang-format style + +## format-check-changed + +This target will check the output of `git status` and scan the files to check if they match the style. This can be used by developers to make sure their changed files match the correct style. + +In this example the actual check is done with a helper script +clang-format-check-changed+. This calls the following command to check files: + +[source,bash] +---- +git status --porcelain \ + | egrep '*\.cpp|*\.h|*\.cxx|*\.hxx|*\.hpp|*\.cc' \ + | awk -F " " '{print $NF}' \ + | xargs -r clang-format -style=file -output-replacements-xml \ + | grep "replacement offset" 2>&1 > /dev/null +---- diff --git a/04-static-analysis/clang-format/cmake/modules/FindClangFormat.cmake b/04-static-analysis/clang-format/cmake/modules/FindClangFormat.cmake new file mode 100644 index 00000000..4dcd02a6 --- /dev/null +++ b/04-static-analysis/clang-format/cmake/modules/FindClangFormat.cmake @@ -0,0 +1,34 @@ +# Find Clang format +# +# +if(NOT CLANG_FORMAT_BIN_NAME) + set(CLANG_FORMAT_BIN_NAME clang-format) +endif() + +# if custom path check there first +if(CPPCHECK_ROOT_DIR) + find_program(CLANG_FORMAT_BIN + NAMES + ${CLANG_FORMAT_BIN_NAME} + PATHS + "${CLANG_FORMAT_ROOT_DIR}" + NO_DEFAULT_PATH) +endif() + +find_program(CLANG_FORMAT_BIN NAMES ${CLANG_FORMAT_BIN_NAME}) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + CLANG_FORMAT + DEFAULT_MSG + CLANG_FORMAT_BIN) + +mark_as_advanced( + CLANG_FORMAT_BIN) + +if(CLANG_FORMAT_FOUND) + # A CMake script to find all source files and setup clang-format targets for them + include(clang-format) +else() + message("clang-format not found. Not setting up format targets") +endif() diff --git a/04-static-analysis/clang-format/cmake/modules/clang-format.cmake b/04-static-analysis/clang-format/cmake/modules/clang-format.cmake new file mode 100644 index 00000000..06f5195b --- /dev/null +++ b/04-static-analysis/clang-format/cmake/modules/clang-format.cmake @@ -0,0 +1,46 @@ +# A CMake script to find all source files and setup clang-format targets for them + +# Find all source files +file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h *.cxx *.hxx *.hpp *.cc) + +# Don't include some common build folders +set(CLANG_FORMAT_EXCLUDE_PATTERNS ${CLANG_FORMAT_EXCLUDE_PATTERNS} "main2.cpp" "build/" "/CMakeFiles/") + +# get all project files file +foreach (SOURCE_FILE ${ALL_SOURCE_FILES}) + foreach (EXCLUDE_PATTERN ${CLANG_FORMAT_EXCLUDE_PATTERNS}) + string(FIND ${SOURCE_FILE} ${EXCLUDE_PATTERN} EXCLUDE_FOUND) + if (NOT ${EXCLUDE_FOUND} EQUAL -1) + list(REMOVE_ITEM ALL_SOURCE_FILES ${SOURCE_FILE}) + endif () + endforeach () +endforeach () + +add_custom_target(format + COMMENT "Running clang-format to change files" + COMMAND ${CLANG_FORMAT_BIN} + -style=file + -i + ${ALL_SOURCE_FILES} +) + +add_custom_target(format-check + COMMENT "Checking clang-format changes" + COMMAND ${CLANG_FORMAT_BIN} + -style=file + -output-replacements-xml + ${ALL_SOURCE_FILES} + | grep "replacement offset" 2>&1 > /dev/null +) + +# This is a hack because our CMake root dir isn't the same as our git root dir + +# Get the path to this file +get_filename_component(_clangcheckpath ${CMAKE_CURRENT_LIST_FILE} PATH) +# call the script to chech changed files in git +add_custom_target(format-check-changed + COMMENT "Checking changed files in git" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${_clangcheckpath}/../scripts/clang-format-check-changed ${CLANG_FORMAT_BIN} +) + diff --git a/04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed b/04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed new file mode 100755 index 00000000..30da46ec --- /dev/null +++ b/04-static-analysis/clang-format/cmake/scripts/clang-format-check-changed @@ -0,0 +1,18 @@ +#!/bin/bash + +# Required because cmake root isn't git root in this example +CLANG_FORMAT_BIN=$1 +GIT_ROOT=`git rev-parse --show-toplevel` + +pushd ${GIT_ROOT} > /dev/null + +git status --porcelain \ + | egrep '*\.cpp|*\.h|*\.cxx|*\.hxx|*\.hpp|*\.cc' \ + | awk -F " " '{print $NF}' \ + | xargs -r ${CLANG_FORMAT_BIN} -style=file -output-replacements-xml \ + | grep "replacement offset" 2>&1 > /dev/null + +RET=$? +popd > /dev/null + +exit ${RET} diff --git a/04-static-analysis/clang-format/subproject1/CMakeLists.txt b/04-static-analysis/clang-format/subproject1/CMakeLists.txt new file mode 100644 index 00000000..25548534 --- /dev/null +++ b/04-static-analysis/clang-format/subproject1/CMakeLists.txt @@ -0,0 +1,10 @@ +# Set the project name +project (subproject1) + +# Create a sources variable with a link to all cpp files to compile +set(SOURCES + main1.cpp +) + +# Add an executable with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) diff --git a/04-static-analysis/clang-format/subproject1/main1.cpp b/04-static-analysis/clang-format/subproject1/main1.cpp new file mode 100644 index 00000000..daf763b6 --- /dev/null +++ b/04-static-analysis/clang-format/subproject1/main1.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char* argv[]) +{ + std::cout << "Hello Main1!" << std::endl; + return 0; +} \ No newline at end of file diff --git a/04-static-analysis/clang-format/subproject2/CMakeLists.txt b/04-static-analysis/clang-format/subproject2/CMakeLists.txt new file mode 100644 index 00000000..bb05ae36 --- /dev/null +++ b/04-static-analysis/clang-format/subproject2/CMakeLists.txt @@ -0,0 +1,10 @@ +# Set the project name +project (subproject2) + +# Create a sources variable with a link to all cpp files to compile +set(SOURCES + main2.cpp +) + +# Add an executable with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) diff --git a/04-static-analysis/clang-format/subproject2/main2.cpp b/04-static-analysis/clang-format/subproject2/main2.cpp new file mode 100644 index 00000000..4e90e90b --- /dev/null +++ b/04-static-analysis/clang-format/subproject2/main2.cpp @@ -0,0 +1,18 @@ +#include + +class TestClass { +public: + TestClass(); +}; + +TestClass::TestClass() { + +} + +int main(int argc, char* argv[]) +{ + std::cout << "Hello Main2!" << std::endl; + int* x = NULL; + std::cout << *x << std::endl; + return 0; +}