Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule #17

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Rule #17

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
oclint
build
.oclint
compile_commands.json
148 changes: 148 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.13.4)
PROJECT(OCLINT_EXTENSIONS)

SET(LLVM_ROOT ${CMAKE_SOURCE_DIR}/oclint/build/llvm-install)

SET(CMAKE_DISABLE_SOURCE_CHANGES ON)
SET(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_MACOSX_RPATH ON)
SET(CMAKE_BUILD_TYPE None)

IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
SET(CMAKE_CXX_FLAGS "-fcolor-diagnostics")
ENDIF()
SET(CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_LINKER_FLAGS} -fno-rtti -fPIC ${CMAKE_CXX_FLAGS}")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINKER_FLAGS} -fno-rtti")

IF(OCLINT_BUILD_TYPE STREQUAL "Release")
SET(CMAKE_CXX_FLAGS "-O3 -DNDEBUG ${CMAKE_CXX_FLAGS}")
SET(CMAKE_SHARED_LINKER_FLAGS "-s ${CMAKE_SHARED_LINKER_FLAGS}")
ELSE()
SET(CMAKE_CXX_FLAGS "-O0 -g ${CMAKE_CXX_FLAGS}")
SET(CMAKE_SHARED_LINKER_FLAGS "-g ${CMAKE_SHARED_LINKER_FLAGS}")
ENDIF()

SET(OCLINT_VERSION_RELEASE "22.02")

IF(NOT EXISTS ${LLVM_ROOT}/include/llvm)
MESSAGE(FATAL_ERROR "LLVM_ROOT (${LLVM_ROOT}) is not a valid LLVM install. Could not find ${LLVM_ROOT}/include/llvm")
ENDIF()
MESSAGE("LLVM_ROOT: ${LLVM_ROOT}")
IF(EXISTS ${LLVM_ROOT}/lib/cmake/llvm)
SET(LLVM_DIR ${LLVM_ROOT}/lib/cmake/llvm)
ELSE()
SET(LLVM_DIR ${LLVM_ROOT}/share/llvm/cmake)
ENDIF()
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LLVM_DIR}")
INCLUDE(LLVMConfig)

INCLUDE_DIRECTORIES( ${LLVM_INCLUDE_DIRS} )
LINK_DIRECTORIES( ${LLVM_LIBRARY_DIRS} )
ADD_DEFINITIONS( ${LLVM_DEFINITIONS} )

STRING(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLVM_VERSION_RELEASE ${LLVM_PACKAGE_VERSION})

MESSAGE(STATUS "Found LLVM LLVM_PACKAGE_VERSION: ${LLVM_PACKAGE_VERSION} - LLVM_VERSION_RELEASE: ${LLVM_VERSION_RELEASE}")
MESSAGE(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
LLVM_MAP_COMPONENTS_TO_LIBNAMES(REQ_LLVM_LIBRARIES asmparser bitreader instrumentation mcparser option support frontendopenmp)

SET(CLANG_LIBRARIES
clangToolingCore
clangTooling
clangFrontend
clangDriver
clangSerialization
clangParse
clangSema
clangAnalysis
clangEdit
clangASTMatchers
clangAST
clangLex
clangBasic)

IF(TEST_BUILD)
ENABLE_TESTING()
IF(NOT APPLE)
ADD_DEFINITIONS(
--coverage
)
ENDIF()

INCLUDE_DIRECTORIES(
${GOOGLETEST_SRC}/googlemock/include
${GOOGLETEST_SRC}/googletest/include
)
LINK_DIRECTORIES(
${GOOGLETEST_BUILD}
${GOOGLETEST_BUILD}/lib
)
SET(GTEST_LIBS gmock gtest)

# Find CUDA
FIND_PROGRAM(NVIDIA_NVCC_BIN "nvcc")
IF (NVIDIA_NVCC_BIN)
MESSAGE(STATUS "Enable tests for CUDA rules.")
SET(TEST_CUDA TRUE)
ELSE()
SET(TEST_CUDA FALSE)
ENDIF()

# Setup the path for profile_rt library
STRING(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_SYSTEM_NAME)
LINK_DIRECTORIES(${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_RELEASE}/lib/${COMPILER_RT_SYSTEM_NAME})
IF(APPLE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
ELSEIF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
SET(PROFILE_RT_LIBS clang_rt.profile-aarch64 --coverage)
ELSE()
SET(PROFILE_RT_LIBS clang_rt.profile-x86_64 --coverage)
ENDIF()
ENDIF()

IF(DOC_GEN_BUILD)
SET(CMAKE_CXX_FLAGS "-DDOCGEN ${CMAKE_CXX_FLAGS}")
ENDIF()




INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/oclint/oclint-core/include
${CMAKE_SOURCE_DIR}/oclint/oclint-metrics/include
${CMAKE_SOURCE_DIR}/oclint/oclint-rules/include
${CMAKE_SOURCE_DIR}/oclint/oclint-rules
)
LINK_DIRECTORIES(
${CMAKE_SOURCE_DIR}/oclint/build/oclint-core/lib
${CMAKE_SOURCE_DIR}/oclint/build/oclint-metrics/lib
${CMAKE_SOURCE_DIR}/oclint/build/oclint-rules/lib/helper
${CMAKE_SOURCE_DIR}/oclint/build/oclint-rules/lib/util
${CMAKE_SOURCE_DIR}/oclint/build/oclint-rules/lib
)

MACRO(build_dynamic_rule name)
ADD_LIBRARY(${name}Rule SHARED ${CMAKE_SOURCE_DIR}/rules/${name}Rule.cpp)

#SET_TARGET_PROPERTIES(${name}Rule
# PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build
# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build
# )

TARGET_LINK_LIBRARIES(${name}Rule OCLintAbstractRule)

TARGET_LINK_LIBRARIES(${name}Rule
clangASTMatchers
)

TARGET_LINK_LIBRARIES(${name}Rule
OCLintMetric
OCLintHelper
OCLintUtil
OCLintCore
)
install(TARGETS ${name}Rule DESTINATION lib/oclint/rules)
ENDMACRO(build_dynamic_rule)

BUILD_DYNAMIC_RULE(TooLongIfSequence)
BUILD_DYNAMIC_RULE(TooComplexCondition)
59 changes: 19 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,30 @@
# oclint_extensions
# OCLint extensions

## Что это?
## Как собрать и установить?

Кастомные правила для oclint. Список реализованных правил:
* слишком много последовательных конструкций if (TooManyConsecutiveIfStatementsRule)

## Установка, сборка и использование

### Создание заготовок для новых правил внутри репозитория oclint

Для начала склонируйте куда-нибудь [репозиторий oclint](https://github.com/oclint/oclint).

Далее необходимо добавить "заготовки" для новых правил. Другими словами, необходимо создать исходники для новых правил и внести их в CMakeLists oclint'а. Новые правила относятся к группе "etu". Для этого выполните следующее:

```bash
cd oclint-scripts
./scaffoldRule -t ASTVisitor -c etu -n"too many consecutive if statements" -p 2 TooManyConsecutiveIfStatementsRule
В одну строку:
```

### Копирование исходников с новыми правилами в репозиторий oclint

Из репозитория oclint_extensions выполните:

```bash
cp -r ./oclint-rules YOUR_OCLINT_DIRECTORY_GOES_HERE
sudo ./install-deps.sh && ./build-oclint.sh && ./install-oclint.sh && mkdir build && cd build && cmake ../ && cmake --build . && sudo cmake --install . && cd ..
```

### Сборка и установка

Вернитесь в репозиторий oclint. Выполните следующее:
То же самое, только в человекочитаемом виде:
```bash
cd oclint-scripts
./make -release # этот скрипт начнет скачивание oclint-json-compilation-database размером в 514 МБ. имейте в виду
sudo ./install-deps.sh

cd ..
cd build/oclint-release
sudo cp ./bin/oclint* /usr/local/bin/
sudo cp -rp ./lib/* /usr/local/lib/
```

### Использование
./build-oclint.sh
./install-oclint.sh

```
oclint --rule=TooManyConsecutiveIfStatements examples/ex*.c
mkdir build
cd build
cmake ../
cmake --build .
sudo cmake --install .
```

## P.S.
Больше информации в [Wiki](https://github.com/moevm/oclint_extensions/wiki/Сборка-и-установка)

Очень странный способ установки всего этого. В теории можно сделать форк oclint'а, ноооооо сомнительно. Должен же быть какой-то более простой способ.
Критикуйте, предлагайте.
Папка `examples` содержит примеры "проектов" с плохим кодом, а также скрипты `test-gcc.sh` и
`test-makefile.sh`. В качестве первого аргумента они принимают путь до папки с исходным кодом,
а последующие аргументы передаются в OCLint, позволяя изменять его поведение. Первый скрипт
предназначем для проектов, состоящих из одного файла с исходным кодом, а второй скрипт - для
проектов с использованием Makefile.
13 changes: 13 additions & 0 deletions build-oclint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

OCLINT_22_02_COMMIT=d776db51c8574df406b2b0dc1b43b0b9b2d86d34

if [ ! -d oclint ]; then
git clone https://github.com/oclint/oclint.git oclint
cd oclint
git reset --hard $OCLINT_22_02_COMMIT
cd ..
fi

cd oclint/oclint-scripts
./make
18 changes: 18 additions & 0 deletions do-everything.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/bash

OLD_PATH=$(pwd)
SCRIPT_PATH=$(dirname "$0")

cd $SCRIPT_PATH

sudo ./install-deps.sh
./build-oclint.sh
./install-oclint.sh
mkdir build
cd build
cmake ../
cmake --build .
sudo cmake --install .
cd ..

cd $OLD_PATH
16 changes: 16 additions & 0 deletions do-rules.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/bash

OLD_PATH=$(pwd)
SCRIPT_PATH=$(dirname "$0")

cd $SCRIPT_PATH

[[ -d build ]] || (mkdir build && cd build && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ../ && cd ..)

cd build
cmake --build .
sudo cmake --install .
cp compile_commands.json ../
cd ..

cd $OLD_PATH
16 changes: 16 additions & 0 deletions examples/ex-condition/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <stdio.h>

int main()
{
int a, b, c, d, e, f;
scanf("%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f);

if ((((a*d == b || b == c*f) && (d == e || (e - a) == f)) || !(d/(e*e + 1) == c)) && b != e) {
puts("Congrats! You found the secret code.");
}
else {
puts("Better luck next time.");
}

return 0;
}
14 changes: 14 additions & 0 deletions examples/ex-goto/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <iostream>
using namespace std;

int main()
{
int x;
cin >> x;

if (x != 2) goto failed;
cout << "Congrats! You typed 2!" << endl;

failed:
return 0;
}
81 changes: 81 additions & 0 deletions examples/ex-if/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <stdio.h>

void simple_ifs()
{
int option = 0;
scanf("%d", &option);

if (option == 0) {
puts("Zero");
}
if (option == 1) {
puts("One");
}
if (option == 2) {
puts("Two");
}
if (option == 3) {
puts("Three");
}
if (option == 4) {
puts("Four");
}
if (option == 5) {
puts("Five");
}
if (option == 6) {
puts("Six");
}
if (option == 7) {
puts("Seven");
}
if (option == 8) {
puts("Eight");
}
if (option == 9) {
puts("Nine");
}
else {
puts("Something else");
}
}

void complex_ifs()
{
int x = 0;
int param1 = 0;
float param2 = 0.0;
float param3 = 0.0;
float param4 = 0.0;
int opt = 0;
int value = -1;
scanf("%d %d %f %f %f %d %d", &x, &param1, &param2, &param3, &param4, &opt, &value);

if (x == 0) {
puts("Zero");
}
else if (param1 > 100){
puts("Too large");
}
else if (param2 < 0.0){
puts("Negative");
}
else if( param3 * param2 > 1e+5){
puts("Invalid");
}
else if (param4 / 2 < param1){
puts("Unique case");
}
else if (opt < 0 || opt > 6){
puts("Invalid option");
}
else if (value == -1){
puts("By default");
}
}

int main()
{
simple_ifs();
complex_ifs();
}
Loading