Skip to content

Update for filtering #314

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

Merged
merged 3 commits into from
May 17, 2018
Merged
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
8 changes: 8 additions & 0 deletions lib/cc/engine/analyzers/analyzer_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ def filters
engine_config.filters_for(language) | default_filters
end

def post_filters
engine_config.post_filters_for(language) | default_post_filters
end

def language
self.class::LANGUAGE
end
Expand Down Expand Up @@ -108,6 +112,10 @@ def default_filters
[]
end

def default_post_filters
[]
end

def points_per_overage
self.class::POINTS_PER_OVERAGE
end
Expand Down
6 changes: 6 additions & 0 deletions lib/cc/engine/analyzers/engine_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ def filters_for(language)
end
end

def post_filters_for(language)
fetch_language(language).fetch("post_filters", []).map do |filter|
Sexp::Matcher.parse filter
end
end

def minimum_mass_threshold_for(language)
[
mass_threshold_for(language, IDENTICAL_CODE_CHECK),
Expand Down
22 changes: 22 additions & 0 deletions lib/cc/engine/analyzers/javascript/main.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,34 @@ class Main < CC::Engine::Analyzers::Base
LANGUAGE = "javascript"
DEFAULT_MASS_THRESHOLD = 45
DEFAULT_FILTERS = [
"(directives (Directive (value (DirectiveLiteral ___))))",
"(ImportDeclaration ___)".freeze,
"(VariableDeclarator _ (init (CallExpression (_ (Identifier require)) ___)))".freeze,
].freeze
DEFAULT_POST_FILTERS = [
"(NUKE ___)",
"(Program _ ___)",
].freeze
POINTS_PER_OVERAGE = 30_000
REQUEST_PATH = "/javascript".freeze

def use_sexp_lines?
false
end

##
# Transform sexp as such:
#
# s(:Program, :module, s(:body, ... ))
# => s(:NUKE, s(:Program, :module, s(:NUKE, ... )))

def transform_sexp(sexp)
sexp.body.sexp_type = :NUKE # negate top level body
sexp = s(:NUKE, sexp) # wrap with extra node to force full process

sexp
end

private

def process_file(file)
Expand All @@ -33,6 +51,10 @@ def process_file(file)
def default_filters
DEFAULT_FILTERS.map { |filter| Sexp::Matcher.parse filter }
end

def default_post_filters
DEFAULT_POST_FILTERS.map { |filter| Sexp::Matcher.parse filter }
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/cc/engine/analyzers/reporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def flay_options
changes = {
mass: language_strategy.mass_threshold,
filters: language_strategy.filters,
post_filters: language_strategy.post_filters,
}

CCFlay.default_options.merge changes
Expand Down
19 changes: 19 additions & 0 deletions lib/ccflay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ def initialize(option = nil)
self.identical = Concurrent::Hash.new
self.masses = Concurrent::Hash.new
end

def post_filter *patterns
return if patterns.empty?

self.hashes.delete_if { |_, sexps|
sexps.any? { |sexp|
patterns.any? { |pattern|
# pattern =~ sexp
pattern.satisfy? sexp
}
}
}
end

def prune
post_filter(*option[:post_filters])

super
end
end

class Sexp
Expand Down
88 changes: 88 additions & 0 deletions spec/cc/engine/analyzers/javascript/main_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,94 @@
expect(issues).to be_empty
end

it "ignores imports and reports proper line number boundaries" do
create_source_file("foo.js", <<~EOJS)
'use strict';

import React from 'react';

import Translator from '../../../i18n/translator-tag.jsx';
import { gettingSeniorID } from '../../../helpers/data/senior';
import { choosingReducedFee } from '../../../helpers/data/reduced-fee';
import { correctID } from '../../../helpers/data/card-type';


const Senior = (props) => {
if (!gettingSeniorID(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.correctingSeniorID' />
};

const Reduced = (props) => {
if (!choosingReducedFee(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.correctingReducedFeeID' />
};

const Regular = (props) => {
if (gettingSeniorID(props.IDApp) || choosingReducedFee(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.correctingID' />
};


const CorrectingIDInfo = (props) => {
if(!correctID(props)) { return null; }
return (
<div className='correcting-id-info'>
<Senior IDApp = {props.IDApp }/>
<Reduced IDApp = {props.IDApp }/>
<Regular IDApp = { props.IDApp}/>
</div>
);
};

export default CorrectingIDInfo;
EOJS

create_source_file("bar.js", <<~EOJS)
'use strict';

import React from 'react';
import { updateID } from '../../../helpers/data/card-type';
import { gettingSeniorID } from '../../../helpers/data/senior';
import { choosingReducedFee } from '../../../helpers/data/reduced-fee';
import Translator from '../../../i18n/translator-tag.jsx';

const Senior = (props) => {
if (!gettingSeniorID(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.updatingSeniorID' />
};

const Reduced = (props) => {
if (!choosingReducedFee(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.updatingReducedFeeID' />
};

const Regular = (props) => {
if (gettingSeniorID(props.IDApp) || choosingReducedFee(props.IDApp)) { return null; }
return <Translator tag='p' translationPath = 'intro.getStartedPage.whatYouAreDoing.updatingID' />
};

const UpdatingIDInfo = (props) => {
if (!updateID(props)) { return null; }
return (
<div className='updating-id-info'>
<Senior IDApp = {props.IDApp } />
<Reduced IDApp = {props.IDApp } />
<Regular IDApp = { props.IDApp} />
</div>
);
};

export default UpdatingIDInfo;
EOJS

issues = run_engine(engine_conf).strip.split("\0")
issues = issues.map { |issue| JSON.parse issue }

infected = issues.any? { |i| i.dig("location", "lines", "begin") == 1 }

expect(infected).to be false
end

it "outputs the correct line numbers for ASTs missing line details (codeclimate/app#6227)" do
create_source_file("foo.js", <<~EOJS)
`/movie?${getQueryString({ movie_id: movieId })}`
Expand Down