diff --git a/.ci/appveyor.yml b/.ci/appveyor.yml index c075afbe5a..51f2b187e2 100644 --- a/.ci/appveyor.yml +++ b/.ci/appveyor.yml @@ -4,6 +4,7 @@ environment: # /E:ON and /V:ON options are not enabled in the batch script intepreter # See: http://stackoverflow.com/a/13751649/163740 CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\.ci\\run_with_env.cmd" + RUST_TOOLCHAIN: "nightly-2017-07-20-x86_64-pc-windows-msvc" matrix: - PYTHON: "C:\\Python34" @@ -20,6 +21,13 @@ cache: - "C:\\Users\\appveyor\\AppData\\Local\\coala-bears\\coala-bears" - "C:\\Users\\appveyor\\AppData\\Roaming\\nltk_data" +# Workaround Appveyor bug: +# http://help.appveyor.com/discussions/problems/7115-curl-cant-download-files-through-ssl +init: + - ps: > + Disable-NetFirewallRule + -DisplayName 'Core Networking - Group Policy (LSASS-Out)' + branches: except: - /^sils\/.*/ @@ -49,6 +57,26 @@ install: - "npm config set loglevel warn" - "npm install" + - "curl -sSf -o rustup-init.exe https://win.rustup.rs/" + - "rustup-init.exe -y --default-toolchain=%RUST_TOOLCHAIN%" + # Normally, we shouldn't need the toolchain lib directory in our PATH + # https://github.com/rust-lang-nursery/rustup.rs/issues/876 + # This is actually the sole reason that we really + # need the RUST_TOOLCHAIN variable. + - "set PATH=%PATH%;C:\\Users\\appveyor\\.cargo\\bin" + # Start ignoring YAMLLintBear + # because of the line length; plitting up these paths would become unreadable + - "set PATH=%PATH%;C:\\Users\\appveyor\\.rustup\\toolchains\\%RUST_TOOLCHAIN%\\bin" + - "set PATH=%PATH%;C:\\Users\\appveyor\\.rustup\\toolchains\\%RUST_TOOLCHAIN%\\lib\\rustlib\\x86_64-pc-windows-msvc\\lib" + # Stop ignoring YAMLLintBear + - "cargo install clippy --vers 0.0.144" + + # Print rust and cargo parameters for quick debugging. + - where rustc cargo + - rustc -vV + - cargo -vV + - cargo clippy -V + build: false # Not a C# project, build stuff at the test step instead. test_script: diff --git a/.ci/deps.sh b/.ci/deps.sh index d3b544702b..df9ec5e08e 100644 --- a/.ci/deps.sh +++ b/.ci/deps.sh @@ -48,6 +48,24 @@ julia -e "Pkg.add(\"Lint\")" # Lua commands sudo luarocks install luacheck --deps-mode=none +# Rust commands +RUST_TOOLCHAIN=nightly-2017-07-20 +# Install Rustup +curl -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain=$RUST_TOOLCHAIN +# Make sure the specified nightly is the default. +# This bypasses cache if needed, which the `sh` line above doesn't +rustup default $RUST_TOOLCHAIN +# Workaround https://github.com/rust-lang/cargo/issues/2078 +# and https://github.com/rust-lang/cargo/issues/2429 (explanation) +# CircleCI gets its SSH agent activated, Travis doesn't need that. +CLIPPY_VERSION=0.0.144 +if [ -e /home/ubuntu/.ssh/id_circleci_github ]; then + eval `ssh-agent` + ssh-add /home/ubuntu/.ssh/id_circleci_github +fi +cargo install clippy --vers $CLIPPY_VERSION --force +cargo clippy -V + # PHPMD installation if [ ! -e ~/phpmd/phpmd ]; then mkdir -p ~/phpmd diff --git a/.gitignore b/.gitignore index 24d6ce89bf..0e44cd7b02 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ htmlcov *.egg-info .coverage.* src +!tests/rust/test_*/src site .zanata-cache *.exe diff --git a/.travis.yml b/.travis.yml index 58384cf9eb..2604a6e8f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -68,6 +68,8 @@ cache: - ~/dart-sdk/bin - ~/.local/tailor/ - ~/phpmd + - ~/.rustup/ + - ~/.cargo/ env: global: @@ -75,7 +77,7 @@ env: - USE_PPAS="marutter/rdev staticfloat/juliareleases ondrej/golang" - R_LIB_USER=~/R/Library - LINTR_COMMENT_BOT=false - - PATH="/opt/cabal/1.24/bin:$PATH:$TRAVIS_BUILD_DIR/node_modules/.bin:$TRAVIS_BUILD_DIR/vendor/bin:$HOME/dart-sdk/bin:$HOME/.cabal/bin:$HOME/infer-linux64-v0.7.0/infer/bin:$HOME/pmd-bin-5.4.1/bin:$HOME/bakalint-0.4.0:$HOME/elm-format-0.18:$HOME/.local/tailor/tailor-latest/bin:$HOME/phpmd" + - PATH="/opt/cabal/1.24/bin:$PATH:$TRAVIS_BUILD_DIR/node_modules/.bin:$TRAVIS_BUILD_DIR/vendor/bin:$HOME/dart-sdk/bin:$HOME/.cabal/bin:$HOME/infer-linux64-v0.7.0/infer/bin:$HOME/pmd-bin-5.4.1/bin:$HOME/bakalint-0.4.0:$HOME/elm-format-0.18:$HOME/.local/tailor/tailor-latest/bin:$HOME/phpmd:$HOME/.cargo/bin" before_install: - nvm install 6.10.2 diff --git a/README.rst b/README.rst index 384024acab..ed2bce090a 100644 --- a/README.rst +++ b/README.rst @@ -4,8 +4,8 @@ coala-bears ----------- coala-bears is a Python package containing all the bears that are officially -supported by coala. It features more than **78 bears** covering -**54 languages**. Here is a `generated list `_ +supported by coala. It features more than **79 bears** covering +**55 languages**. Here is a `generated list `_ that contains information about each bear, such as the languages it supports and what fixes it can apply to your code. @@ -69,35 +69,35 @@ To see what coala can do for your language, run: +----------------------------+----------------------------+----------------------------+ | Languages coala provides algorithms for | +============================+============================+============================+ -| C | Latex | SQL | +| C | Latex | sh & bash scripts | +----------------------------+----------------------------+----------------------------+ -| C++ | Lua | Stylus | +| C++ | Lua | SQL | +----------------------------+----------------------------+----------------------------+ -| C# | Markdown | Swift | +| C# | Markdown | Stylus | +----------------------------+----------------------------+----------------------------+ -| CMake | Matlab/Octave | TypeScript | +| CMake | Matlab/Octave | Swift | +----------------------------+----------------------------+----------------------------+ -| CoffeeScript | Natural Language (English) | Verilog | +| CoffeeScript | Natural Language (English) | Typescript | +----------------------------+----------------------------+----------------------------+ -| CSS | Perl | VHDL | +| CSS | Perl | Verilog | +----------------------------+----------------------------+----------------------------+ -| Dart | PHP | Vimscript | +| Dart | PHP | VHDL | +----------------------------+----------------------------+----------------------------+ -| Fortran | Python 2 | XML | +| Fortran | Python 2 | Vimscript | +----------------------------+----------------------------+----------------------------+ -| Go | Python 3 | YAML | +| Go | Python 3 | XML | +----------------------------+----------------------------+----------------------------+ -| Haskell | R | | +| Haskell | R | YAML | +----------------------------+----------------------------+----------------------------+ | HTML | reStructured Text | | +----------------------------+----------------------------+----------------------------+ | Java | Ruby | | +----------------------------+----------------------------+----------------------------+ -| JavaScript | Scala | | +| JavaScript | Rust | | +----------------------------+----------------------------+----------------------------+ -| JSP | SCSS | | +| JSP | Scala | | +----------------------------+----------------------------+----------------------------+ -| Julia | sh & bash scripts | | +| Julia | SCSS | | +----------------------------+----------------------------+----------------------------+ The number of bears grows every day! If you want to see any particular diff --git a/bears/rust/RustClippyLintBear.py b/bears/rust/RustClippyLintBear.py new file mode 100644 index 0000000000..6bbe3ccf09 --- /dev/null +++ b/bears/rust/RustClippyLintBear.py @@ -0,0 +1,67 @@ +import json +import os + +from coalib.bearlib.abstractions.Linter import linter +from coalib.results.Result import Result +from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY +from dependency_management.requirements.CargoRequirement import ( + CargoRequirement) + + +@linter(executable='cargo', + global_bear=True, + use_stdout=False, + use_stderr=True) +class RustClippyLintBear: + LANGUAGES = {'Rust'} + AUTHORS = {'The coala developers'} + AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} + LICENSE = 'AGPL-3.0' + CAN_DETECT = { + 'Formatting', + 'Unused Code', + 'Syntax', + 'Unreachable Code', + 'Smell', + 'Code Simplification', + } + EXECUTABLE = 'cargo.exe' if os.name == 'nt' else 'cargo' + REQUIREMENTS = { + CargoRequirement('clippy') + } + SEVERITY_MAP = { + 'warning': RESULT_SEVERITY.NORMAL, + 'error': RESULT_SEVERITY.MAJOR, + } + + @staticmethod + def create_arguments(config_file): + args = ('clippy', '--quiet', '--color', 'never', + '--', '-Z', 'unstable-options', + '--error-format', 'json', + '--test') + return args + + def process_output(self, output, filename, file): + # Rust outputs \n's, instead of the system default. + for line in output.split('\n'): + if not line: + continue + # cargo still outputs some text, even when in quiet mode, + # when a project does not build. We skip this, as the + # real reason will be reported on another line. + if line.startswith('To learn more, run the command again'): + continue + yield self.new_result(json.loads(line)) + + def new_result(self, issue): + span = issue['spans'][0] + return Result.from_values( + origin=self.__class__.__name__, + message=issue['message'], + file=span['file_name'], + line=span['line_start'], + end_line=span['line_end'], + column=span['column_start'], + end_column=span['column_end'], + severity=self.SEVERITY_MAP[issue['level']]) diff --git a/bears/rust/__init__.py b/bears/rust/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/circle.yml b/circle.yml index 23d37a01e9..e6d9ce8646 100644 --- a/circle.yml +++ b/circle.yml @@ -18,6 +18,8 @@ dependencies: - ~/bakalint-0.4.0 - ~/.julia - ~/.local/tailor/ + - ~/.cargo + - ~/.rustup pre: - sudo rm -rf /var/cache/apt/archives - sudo ln -s ~/.apt-cache /var/cache/apt/archives @@ -33,6 +35,7 @@ dependencies: - echo 'export PATH=$PATH:~/.local/tailor/tailor-latest/bin' >> ~/.circlerc - echo 'export PATH=$PATH:~/elm-format-0.18' >> ~/.circlerc - echo 'export PATH=$PATH:~/phpmd' >> ~/.circlerc + - echo 'export PATH=$PATH:~/.cargo/bin' >> ~/.circlerc - echo 'export R_LIB_USER=~/.RLibrary' >> ~/.circlerc - sed -i '/source \/home\/ubuntu\/virtualenvs\//d' ~/.circlerc - mkdir -p ~/.RLibrary @@ -48,6 +51,12 @@ dependencies: timeout: 900 # Allow 15 mins before timing out due to "no output" - bash .ci/deps.coala-bears.sh +checkout: + post: + # Workaround https://github.com/rust-lang/cargo/issues/2078 + # and https://github.com/rust-lang/cargo/issues/2429 (explanation) + - git config --global --unset url.ssh://git@github.com:.insteadof + machine: node: version: 6.10.2 diff --git a/tests/rust/.gitignore b/tests/rust/.gitignore new file mode 100644 index 0000000000..a9d37c560c --- /dev/null +++ b/tests/rust/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/tests/rust/RustClippyLintBearTest.py b/tests/rust/RustClippyLintBearTest.py new file mode 100644 index 0000000000..9e3b1ea689 --- /dev/null +++ b/tests/rust/RustClippyLintBearTest.py @@ -0,0 +1,49 @@ +import unittest +import os +from queue import Queue +from shutil import which +from unittest.case import skipIf + +from coalib.settings.Section import Section + +from bears.rust.RustClippyLintBear import RustClippyLintBear + + +@skipIf(which('cargo') is None, 'Cargo is not installed') +class RustClippyLintBearTest(unittest.TestCase): + + def setUp(self): + self.section = Section('name') + self.queue = Queue() + self.file_dict = {} + self.uut = RustClippyLintBear(self.file_dict, self.section, self.queue) + + def change_directory(self, directory_name): + test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + directory_name)) + os.chdir(test_path) + + def set_config_dir(self, directory): + # Work around https://github.com/coala/coala/issues/3867 + test_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), directory)) + self.uut.get_config_dir = lambda *args, **kwargs: test_path + + def test_ok_source(self): + self.set_config_dir('test_ok') + results = list(self.uut.run()) + self.assertTrue(len(results) == 0) + + def test_bad_source(self): + self.set_config_dir('test_bad') + results = list(self.uut.run()) + self.assertTrue(len(results) >= 3) + + def test_error_source(self): + self.set_config_dir('test_error') + results = list(self.uut.run()) + self.assertTrue(len(results) == 1) + + result = results[0] + print(result) + self.assertTrue(result.message == 'mismatched types') diff --git a/tests/rust/__init__.py b/tests/rust/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/rust/test_bad/Cargo.toml b/tests/rust/test_bad/Cargo.toml new file mode 100644 index 0000000000..ccaca8ccad --- /dev/null +++ b/tests/rust/test_bad/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "coala_test_files" +version = "0.1.0" + +[dependencies] diff --git a/tests/rust/test_bad/src/lib.rs b/tests/rust/test_bad/src/lib.rs new file mode 100644 index 0000000000..c767679a79 --- /dev/null +++ b/tests/rust/test_bad/src/lib.rs @@ -0,0 +1,24 @@ +// This function should trigger unused code (warning level) +fn testssss() { + // This comparison should trigger a `deny` level lint + let mut x: f64 = 0.0; + if x == std::f64::NAN { + } + x += 1.; // Triggers allow style lint + println!("{}", x); +} + + +// We test whether bad code is found in (unit) tests +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let x = Some(1u8); + // This match triggers a `warning` level lint + match x { + Some(y) => println!("{:?}", y), + _ => () + } + } +} diff --git a/tests/rust/test_error/Cargo.toml b/tests/rust/test_error/Cargo.toml new file mode 100644 index 0000000000..ccaca8ccad --- /dev/null +++ b/tests/rust/test_error/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "coala_test_files" +version = "0.1.0" + +[dependencies] diff --git a/tests/rust/test_error/src/lib.rs b/tests/rust/test_error/src/lib.rs new file mode 100644 index 0000000000..3baea9f592 --- /dev/null +++ b/tests/rust/test_error/src/lib.rs @@ -0,0 +1,4 @@ +fn main() { + // This does not compile. Message is 'mismatched types' + let a: i32 = ""; +} diff --git a/tests/rust/test_ok/Cargo.toml b/tests/rust/test_ok/Cargo.toml new file mode 100644 index 0000000000..ccaca8ccad --- /dev/null +++ b/tests/rust/test_ok/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "coala_test_files" +version = "0.1.0" + +[dependencies] diff --git a/tests/rust/test_ok/src/lib.rs b/tests/rust/test_ok/src/lib.rs new file mode 100644 index 0000000000..a93251b65d --- /dev/null +++ b/tests/rust/test_ok/src/lib.rs @@ -0,0 +1,3 @@ +#[test] +fn it_works() { +}