diff --git a/src/linting/extended_checks.jl b/src/linting/extended_checks.jl index f7f3294..bbea557 100644 --- a/src/linting/extended_checks.jl +++ b/src/linting/extended_checks.jl @@ -58,6 +58,11 @@ struct Sleep_Extension <: ExtendedRule end struct Mmap_Extension <: ExtendedRule end struct Future_Extension <: ExtendedRule end struct Wait_Extension <: ExtendedRule end +struct Fetch_Extension <: ExtendedRule end +struct Inbounds_Extension <: ExtendedRule end +struct Atomic_Extension <: ExtendedRule end +struct Ptr_Extension <: ExtendedRule end + const all_extended_rule_types = Ref{Any}(InteractiveUtils.subtypes(ExtendedRule)) @@ -80,11 +85,17 @@ function get_oracle_ast(template_code::String) end does_match(x::EXPR, template_code::String) = comp(x, get_oracle_ast(template_code)) -function generic_check(x::EXPR, template_code::String, error_code) - error_code isa String && get!(error_msgs, template_code, error_code) - does_match(x, template_code) && seterror!(x, error_code) +function generic_check(x::EXPR, template_code::String, error_msg) + error_msg isa String && get!(error_msgs, template_code, error_msg) + does_match(x, template_code) && seterror!(x, error_msg) +end + +function generic_check(x::EXPR, template_code::String) + keyword = first(split(template_code, ['(', '{', ' '])) + return generic_check(x, template_code, "`$(keyword)` should be used with extreme caution.") end + # Useful for rules that do not need markers check(t::Any, x::EXPR, markers::Dict{Symbol,Symbol}) = check(t, x) @@ -133,18 +144,29 @@ function check(::Lock_Extension, x::EXPR) generic_check(x, "Base.@lock hole_variable hole_variable", msg) end -check(::Unlock_Extension, x::EXPR) = generic_check(x, "unlock(hole_variable)", "`unlock` should be used with extreme caution.") -check(::Yield_Extension, x::EXPR) = generic_check(x, "yield()", "`yield` should be used with extreme caution.") -check(::Sleep_Extension, x::EXPR) = generic_check(x, "sleep(hole_variable)", "`sleep` should be used with extreme caution.") +check(::Unlock_Extension, x::EXPR) = generic_check(x, "unlock(hole_variable)") +check(::Yield_Extension, x::EXPR) = generic_check(x, "yield()") +check(::Sleep_Extension, x::EXPR) = generic_check(x, "sleep(hole_variable)") function check(::Mmap_Extension, x::EXPR) - generic_check(x, "mmap(hole_variable_star)", "`mmap` should be used with extreme caution.") + generic_check(x, "mmap(hole_variable_star)") generic_check(x, "Mmap.mmap(hole_variable_star)", "`mmap` should be used with extreme caution.") end -function check(::Future_Extension, x::EXPR) - generic_check(x, "Future{hole_variable}(hole_variable_star)", "`Future` should be used with extreme caution.") - generic_check(x, "Future(hole_variable_star)", "`Future` should be used with extreme caution.") +check(::Fetch_Extension, x::EXPR) = generic_check(x, "fetch(hole_variable)") +check(::Inbounds_Extension, x::EXPR) = generic_check(x, "@inbounds hole_variable") + +function check(::Atomic_Extension, x::EXPR) + msg = "`Atomic` should be used with extreme caution." + generic_check(x, "Atomic(hole_variable_star)", msg) + generic_check(x, "Atomic{hole_variable}(hole_variable_star)", msg) + generic_check(x, "Threads.Atomic(hole_variable_star)", msg) + generic_check(x, "Threads.Atomic{hole_variable}(hole_variable_star)", msg) end -check(::Wait_Extension, x::EXPR) = generic_check(x, "wait(hole_variable)", "`wait` should be used with extreme caution.") +function check(::Future_Extension, x::EXPR) + generic_check(x, "Future{hole_variable}(hole_variable_star)") + generic_check(x, "Future(hole_variable_star)") +end +check(::Wait_Extension, x::EXPR) = generic_check(x, "wait(hole_variable)") +check(::Ptr_Extension, x::EXPR) = generic_check(x, "Ptr{hole_variable}(hole_variable)") \ No newline at end of file diff --git a/test/rai_rules_tests.jl b/test/rai_rules_tests.jl index eee99e0..585cfbe 100644 --- a/test/rai_rules_tests.jl +++ b/test/rai_rules_tests.jl @@ -404,6 +404,8 @@ end @test lint_test(source, "Line 12, column 10: `mmap` should be used with extreme caution.") @test lint_test(source, + "Line 13, column 10: `mmap` should be used with extreme caution.") + @test lint_test(source, "Line 14, column 12: `Future` should be used with extreme caution.") @test lint_test(source, "Line 15, column 12: `Future` should be used with extreme caution.") @@ -411,9 +413,44 @@ end "Line 16, column 12: `Future` should be used with extreme caution.") @test lint_test(source, "Line 18, column 5: `wait` should be used with extreme caution.") - end + end + + @testset "fetch, @inbounds, Atomic, Ptr" begin + source = """ + function f() + fut = Future{Any}() + r1 = fetch(fut) + + @inbounds begin + at_end(iter) && return 0 + i = 1 + set_from_tuple!(columns_tuple, 1, iter_tuple(iter)) + while next!(iter) && i < cap + i += 1 + set_from_tuple!(columns_tuple, i, iter_tuple(iter)) + end + return i + end + num_created1 = Threads.Atomic{Int}(0); + num_created2 = Atomic{Int}(0); + num_created3 = Atomic(0); + + pointer(page) == Ptr{Nothing}(0) && return + end + """ + + @test lint_test(source, "Line 3, column 10: `fetch` should be used with extreme caution.") + @test lint_test(source, "Line 5, column 5: `@inbounds` should be used with extreme caution.") + + @test lint_test(source, "Line 15, column 20: `Atomic` should be used with extreme caution.") + @test lint_test(source, "Line 16, column 20: `Atomic` should be used with extreme caution.") + @test lint_test(source, "Line 17, column 20: `Atomic` should be used with extreme caution.") + + @test lint_test(source, "Line 19, column 22: `Ptr` should be used with extreme caution.") + end end + @testset "Comparison" begin t(s1, s2) = comp(CSTParser.parse(s1), CSTParser.parse(s2)) @test t("Threads.nthreads()", "Threads.nthreads()")