diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..e14f31a93c --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,60 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,llvm-include-order,llvm-namespace-comment,readability-braces-around-statements,readability-container-size-empty,readability-else-after-return,readability-redundant*,readability-inconsistent-declaration-parameter-name,hicpp-explicit-conversions,hicpp-use-emplace,hicpp-use-equals-default,hicpp-use-equals-delete,performance-*,-performance-move-constructor-init' +WarningsAsErrors: '*' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +FormatStyle: none +User: bstaletic +CheckOptions: + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: hicpp-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: hicpp-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: hicpp-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: hicpp-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: hicpp-use-equals-default.IgnoreMacros + value: '1' + - key: llvm-namespace-comment.ShortNamespaceLines + value: '1' + - key: llvm-namespace-comment.SpacesBeforeComments + value: '1' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: performance-faster-string-find.StringLikeClasses + value: 'std::basic_string' + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '0' + - key: performance-inefficient-string-concatenation.StrictMode + value: '0' + - key: performance-inefficient-vector-operation.VectorLikeClasses + value: '::std::vector' + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: performance-type-promotion-in-math-fn.IncludeStyle + value: llvm + - key: performance-unnecessary-value-param.IncludeStyle + value: llvm + - key: readability-braces-around-statements.ShortStatementLines + value: '0' +... + diff --git a/.travis.yml b/.travis.yml index 08e0f203a4..372593366b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ env: - YCMD_PYTHON_VERSION=3.4 - YCMD_PYTHON_VERSION=3.4 YCM_COMPILER=clang - YCMD_PYTHON_VERSION=3.4 YCM_BENCHMARK=true COVERAGE=false + - YCMD_PYTHON_VERSION=3.4 YCM_CLANG_TIDY=true COVERAGE=false YCM_CORES=1 addons: # If this doesn't make much sense to you, see the travis docs: # https://docs.travis-ci.com/user/migrating-from-legacy/ @@ -39,6 +40,7 @@ addons: - g++-4.8 # Install Clang 3.4 and its standard library. - clang + - clang-tidy-3.9 - libc++-dev # Required to build the OmniSharp server. - mono-devel diff --git a/build.py b/build.py index e98417397e..5656bb9649 100755 --- a/build.py +++ b/build.py @@ -363,6 +363,9 @@ def ParseArguments(): parser.add_argument( '--no-regex', action = 'store_true', help = "Don't build the regex module" ) + parser.add_argument( '--clang-tidy', + action = 'store_true', + help = "Run clang-tidy static analysis" ) # These options are deprecated. @@ -382,6 +385,9 @@ def ParseArguments(): # We always want a debug build when running with coverage enabled args.enable_debug = True + if not args.clang_tidy and os.environ.get( 'YCM_CLANG_TIDY' ): + args.clang_tidy = True + if ( args.system_libclang and not args.clang_completer and not args.all_completers ): @@ -405,6 +411,9 @@ def GetCmakeArgs( parsed_args ): if parsed_args.clang_completer or parsed_args.all_completers: cmake_args.append( '-DUSE_CLANG_COMPLETER=ON' ) + if parsed_args.clang_tidy: + cmake_args.append( '-DUSE_CLANG_TIDY=ON' ) + if parsed_args.system_libclang: cmake_args.append( '-DUSE_SYSTEM_LIBCLANG=ON' ) diff --git a/ci/travis/travis_install.sh b/ci/travis/travis_install.sh index 360a6b0a2b..4f05d8593a 100755 --- a/ci/travis/travis_install.sh +++ b/ci/travis/travis_install.sh @@ -27,6 +27,9 @@ else ln -s /usr/bin/gcc-4.9 ${HOME}/bin/cc fi ln -s /usr/bin/gcov-4.9 ${HOME}/bin/gcov +if [ -n "${YCM_CLANG_TIDY}" ]; then + ln -s /usr/bin/clang-tidy-3.9 ${HOME}/bin/clang-tidy +fi export PATH=${HOME}/bin:${PATH} diff --git a/ci/travis/travis_script.sh b/ci/travis/travis_script.sh index 768a927957..65e45d648d 100755 --- a/ci/travis/travis_script.sh +++ b/ci/travis/travis_script.sh @@ -1,5 +1,7 @@ if [ "${YCM_BENCHMARK}" == "true" ]; then ./benchmark.py +elif [ "${YCM_CLANG_TIDY}" == "true" ]; then + ./build.py --clang-completer --clang-tidy --quiet --no-regex else ./run_tests.py fi diff --git a/cpp/ycm/CMakeLists.txt b/cpp/ycm/CMakeLists.txt index 1bbb628f17..047b118dc1 100644 --- a/cpp/ycm/CMakeLists.txt +++ b/cpp/ycm/CMakeLists.txt @@ -466,3 +466,27 @@ endif() if ( DEFINED ENV{YCM_BENCHMARK} ) add_subdirectory( benchmarks ) endif() + +############################################################################### + +if( USE_CLANG_TIDY ) + if( NOT APPLE ) + find_program( CLANG_TIDY NAMES clang-tidy ) + else() + execute_process( COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_ROOT ) + string( STRIP ${LLVM_ROOT} LLVM_ROOT ) + message( STATUS "${LLVM_ROOT}/bin" ) + find_program( CLANG_TIDY NAMES clang-tidy PATHS "${LLVM_ROOT}/bin" ) + endif() + + if ( CLANG_TIDY ) + message( STATUS "clang-tidy executable found: ${CLANG_TIDY}" ) + set( CLANG_TIDY_ARGS "${CLANG_TIDY}") + set_target_properties( ycm_core PROPERTIES + CXX_CLANG_TIDY "${CLANG_TIDY_ARGS}" ) + else() + message( STATUS "clang-tidy not found" ) + endif() +else() + message( STATUS "NOT using clang-tidy for static analysis." ) +endif() diff --git a/cpp/ycm/ClangCompleter/ClangHelpers.cpp b/cpp/ycm/ClangCompleter/ClangHelpers.cpp index 8cf1501de3..1da76b9545 100644 --- a/cpp/ycm/ClangCompleter/ClangHelpers.cpp +++ b/cpp/ycm/ClangCompleter/ClangHelpers.cpp @@ -18,8 +18,8 @@ #include "ClangHelpers.h" #include "ClangUtils.h" #include "Location.h" -#include "Range.h" #include "PythonSupport.h" +#include "Range.h" #include "UnsavedFile.h" #include "Utils.h" diff --git a/cpp/ycm/ClangCompleter/CompilationDatabase.cpp b/cpp/ycm/ClangCompleter/CompilationDatabase.cpp index a31eacb468..835871dc56 100644 --- a/cpp/ycm/ClangCompleter/CompilationDatabase.cpp +++ b/cpp/ycm/ClangCompleter/CompilationDatabase.cpp @@ -35,7 +35,7 @@ using CompileCommandsWrap = CompilationDatabase::CompilationDatabase( - pybind11::object path_to_directory ) + const pybind11::object &path_to_directory ) : is_loaded_( false ), path_to_directory_( GetUtf8String( path_to_directory ) ) { CXCompilationDatabase_Error status; @@ -63,7 +63,7 @@ bool CompilationDatabase::AlreadyGettingFlags() { CompilationInfoForFile CompilationDatabase::GetCompilationInfoForFile( - pybind11::object path_to_file ) { + const pybind11::object &path_to_file ) { CompilationInfoForFile info; if ( !is_loaded_ ) { diff --git a/cpp/ycm/ClangCompleter/CompilationDatabase.h b/cpp/ycm/ClangCompleter/CompilationDatabase.h index f6e3045820..e6d4031596 100644 --- a/cpp/ycm/ClangCompleter/CompilationDatabase.h +++ b/cpp/ycm/ClangCompleter/CompilationDatabase.h @@ -36,7 +36,7 @@ struct CompilationInfoForFile { class CompilationDatabase { public: // |path_to_directory| should be a string-like object. - CompilationDatabase( pybind11::object path_to_directory ); + CompilationDatabase( const pybind11::object &path_to_directory ); CompilationDatabase( const CompilationDatabase& ) = delete; CompilationDatabase& operator=( const CompilationDatabase& ) = delete; ~CompilationDatabase(); @@ -51,7 +51,7 @@ class CompilationDatabase { // serialized since Clang internals are not thread-safe. // |path_to_file| should be a string-like object. CompilationInfoForFile GetCompilationInfoForFile( - pybind11::object path_to_file ); + const pybind11::object &path_to_file ); std::string GetDatabaseDirectory() { return path_to_directory_; diff --git a/cpp/ycm/PythonSupport.cpp b/cpp/ycm/PythonSupport.cpp index d7994545d4..2b041a44af 100644 --- a/cpp/ycm/PythonSupport.cpp +++ b/cpp/ycm/PythonSupport.cpp @@ -102,7 +102,7 @@ pylist FilterAndSortCandidates( } -std::string GetUtf8String( object value ) { +std::string GetUtf8String( const object &value ) { // If already a unicode or string (or something derived from it) // pybind will already convert to utf8 when converting to std::string. // For `bytes` the contents are left untouched: diff --git a/cpp/ycm/PythonSupport.h b/cpp/ycm/PythonSupport.h index 5c05611ca2..5df1cd28e6 100644 --- a/cpp/ycm/PythonSupport.h +++ b/cpp/ycm/PythonSupport.h @@ -37,7 +37,7 @@ YCM_EXPORT pybind11::list FilterAndSortCandidates( /// Given a Python object that's supposed to be "string-like", returns a UTF-8 /// encoded std::string. Raises an exception if the object can't be converted to /// a string. Supports newstr and newbytes from python-future on Python 2. -std::string GetUtf8String( pybind11::object value ); +std::string GetUtf8String( const pybind11::object &value ); } // namespace YouCompleteMe