Skip to content

Commit

Permalink
add support for ktlint (#27), MISSING: readme, KotlinCodeAssertTest, …
Browse files Browse the repository at this point in the history
…configurable ruleset
  • Loading branch information
nidi3 committed Oct 8, 2017
1 parent 210e7e1 commit b30ae3e
Show file tree
Hide file tree
Showing 11 changed files with 425 additions and 9 deletions.
17 changes: 17 additions & 0 deletions code-assert/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@
</exclusions>
</dependency>

<!--<dependency>-->
<!--<groupId>io.gitlab.arturbosch.detekt</groupId>-->
<!--<artifactId>detekt-core</artifactId>-->
<!--<version>1.0.0.RC4</version>-->
<!--</dependency>-->

<dependency>
<groupId>com.github.shyiko.ktlint</groupId>
<artifactId>ktlint-core</artifactId>
<version>0.9.2</version>
</dependency>
<dependency>
<groupId>com.github.shyiko.ktlint</groupId>
<artifactId>ktlint-ruleset-standard</artifactId>
<version>0.9.2</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,7 @@ public ActionResult accept(AuditEvent issue) {

@Override
protected ActionResult doAccept(AuditEvent issue, Ignore action) {
final String file = issue.getFileName().replace('\\', '/');
//TODO can this heuristic be improved?
final int slash = file.lastIndexOf('/');
final int dot = file.lastIndexOf('.');
final int src = file.indexOf("/src/") + 4;
final int java = file.indexOf("/java/") + 5;
final int later = Math.max(src, java);
final int start = later >= 5 ? later + 1 : slash + 1;
final String className = file.substring(start, dot).replace('/', '.');
final String className = guessClassFromFile(issue.getFileName(), Language.JAVA);
final String name = issue.getLocalizedMessage().getKey();
return action.accept(new NamedLocation(name, className, "", false));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,15 @@ protected List<A> unusedNullAction(UsageCounter counter, boolean hasDefaultConfi
: Collections.<A>emptyList();
}

protected String guessClassFromFile(String filename, Language language) {
final String file = filename.replace('\\', '/');
//TODO can this heuristic be improved?
final int slash = file.lastIndexOf('/');
final int dot = file.lastIndexOf('.');
final int src = file.indexOf("/src/") + 4;
final int lang = file.indexOf("/" + language.path + "/") + language.path.length() + 1;
final int later = Math.max(src, lang);
final int start = later >= 5 ? later + 1 : slash + 1;
return file.substring(start, dot).replace('/', '.');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.junit.kotlin;

import guru.nidi.codeassert.ktlint.KtlintMatcher;
import guru.nidi.codeassert.ktlint.KtlintResult;
import org.hamcrest.Matcher;

public final class KotlinCodeAssertMatchers {
private KotlinCodeAssertMatchers() {
}

public static Matcher<KtlintResult> hasNoKtlintIssues() {
return new KtlintMatcher();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.ktlint;

import com.github.shyiko.ktlint.core.KtLint;
import com.github.shyiko.ktlint.core.LintError;
import com.github.shyiko.ktlint.ruleset.standard.StandardRuleSetProvider;
import guru.nidi.codeassert.Analyzer;
import guru.nidi.codeassert.config.AnalyzerConfig;
import guru.nidi.codeassert.config.UsageCounter;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

import static guru.nidi.codeassert.config.Language.KOTLIN;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonList;

public class KtlintAnalyzer implements Analyzer<List<LocatedLintError>> {
private static final Logger LOG = LoggerFactory.getLogger(KtlintAnalyzer.class);

private final AnalyzerConfig config;
private final KtlintCollector collector;

public KtlintAnalyzer(AnalyzerConfig config, KtlintCollector collector) {
this.config = config;
this.collector = collector;
}

public KtlintResult analyze() {
final ErrorListener listener = new ErrorListener();
for (final File src : config.getSources(KOTLIN)) {
try {
listener.currentFile = src;
KtLint.INSTANCE.lint(readFile(src), singletonList(new StandardRuleSetProvider().get()), listener);
} catch (IOException e) {
LOG.error("Could not read file {}", src, e);
}
}
return createResult(listener);
}

private String readFile(File f) throws IOException {
final StringBuilder sb = new StringBuilder();
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f), UTF_8))) {
String line;
while ((line = in.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString();
}

private KtlintResult createResult(ErrorListener listener) {
final List<LocatedLintError> filtered = new ArrayList<>();
final UsageCounter counter = new UsageCounter();
for (final LocatedLintError error : listener.errors) {
if (counter.accept(collector.accept(error))) {
filtered.add(error);
}
}
collector.printUnusedWarning(counter);
return new KtlintResult(this, filtered, collector.unusedActions(counter));
}

private static class ErrorListener implements Function1<LintError, Unit> {
private final List<LocatedLintError> errors = new ArrayList<>();
private File currentFile;

@Override
public Unit invoke(LintError e) {
errors.add(new LocatedLintError(currentFile, e.getLine(), e.getCol(), e.getRuleId(), e.getDetail()));
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.ktlint;

import guru.nidi.codeassert.config.*;
import guru.nidi.codeassert.util.ListUtils;

import java.util.List;

public class KtlintCollector extends BaseCollector<LocatedLintError, Ignore, KtlintCollector> {
@Override
public KtlintCollector config(final CollectorConfig<Ignore>... configs) {
return new KtlintCollector() {
@Override
public ActionResult accept(LocatedLintError issue) {
return accept(issue, KtlintCollector.this, configs);
}

public List<Ignore> unused(UsageCounter counter) {
return unused(counter, KtlintCollector.this, configs);
}

@Override
public String toString() {
return KtlintCollector.this.toString() + "\n" + ListUtils.join("\n", configs);
}
};
}

@Override
public ActionResult accept(LocatedLintError issue) {
return ActionResult.accept(null, 1);
}

@Override
protected ActionResult doAccept(LocatedLintError issue, Ignore action) {
final String className = guessClassFromFile(issue.file.getAbsolutePath(), Language.KOTLIN);
return action.accept(new NamedLocation(issue.ruleId, className, null, true));
}

@Override
public List<Ignore> unused(UsageCounter counter) {
return unusedNullAction(counter, true);
}

@Override
public String toString() {
return "";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.ktlint;

import guru.nidi.codeassert.util.ResultMatcher;
import org.hamcrest.Description;

public class KtlintMatcher extends ResultMatcher<KtlintResult, LocatedLintError> {
public void describeTo(Description description) {
description.appendText("Has no ktlint issues");
}

@Override
protected void describeMismatchSafely(KtlintResult item, Description description) {
for (final LocatedLintError error : item.findings()) {
description.appendText("\n").appendText(printError(error));
}
}

private String printError(LocatedLintError error) {
return String.format("%-35s %s:%d %s",
error.ruleId, error.file.getAbsolutePath(), error.line, error.detail);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.ktlint;

import guru.nidi.codeassert.Analyzer;
import guru.nidi.codeassert.AnalyzerResult;

import java.util.List;

public class KtlintResult extends AnalyzerResult<List<LocatedLintError>> {
public KtlintResult(Analyzer<List<LocatedLintError>> analyzer,
List<LocatedLintError> findings, List<String> unusedActions) {
super(analyzer, findings, unusedActions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.ktlint;

import java.io.File;

class LocatedLintError {
final File file;
final int line;
final int col;
final String ruleId;
final String detail;

LocatedLintError(File file, int line, int col, String ruleId, String detail) {
this.file = file;
this.line = line;
this.col = col;
this.ruleId = ruleId;
this.detail = detail;
}
}
Loading

0 comments on commit b30ae3e

Please sign in to comment.