Skip to content

Commit

Permalink
add support for detekt (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
nidi3 committed Oct 13, 2017
1 parent 2567f44 commit fc6d7f0
Show file tree
Hide file tree
Showing 28 changed files with 891 additions and 108 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ It also integrates several static code analysis tools.

## Kotlin checks
- [ktlint](#user-content-ktlint)
- [detekt](#user-content-detekt)

## Other
- [Configuration reuse](#user-content-configuration-reuse)
Expand Down Expand Up @@ -138,7 +139,7 @@ public class FindBugsTest {
BugCollector collector = new BugCollector().maxRank(17).minPriority(Priorities.NORMAL_PRIORITY)
.just(In.everywhere().ignore("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"))
.because("It's checked and OK like this",
In.classes(DependencyRules.class, Ruleset.class).ignore("DP_DO_INSIDE_DO_PRIVILEGED"),
In.classes(DependencyRules.class, PmdRuleset.class).ignore("DP_DO_INSIDE_DO_PRIVILEGED"),
In.locs("ClassFileParser#parse", "*Test", "Rulesets").ignore("URF_UNREAD_FIELD"));

FindBugsResult result = new FindBugsAnalyzer(config, collector).analyze();
Expand Down Expand Up @@ -248,6 +249,29 @@ public class KtlintTest {
```
[//]: # (end)

### detekt

Runs [detekt](https://github.com/arturbosch/detekt), a static code analysis tool for kotlin.

[//]: # (detekt)
```java
public class DetektTest {
@Test
public void analyze() {
// Analyze all sources in src/main/kotlin
AnalyzerConfig config = AnalyzerConfig.maven(KOTLIN).main();

DetektCollector collector = new DetektCollector()
.just(In.loc("Linker").ignore("MaxLineLength"));

DetektResult result = new DetektAnalyzer(config, collector).analyze();

assertThat(result, hasNoDetektIssues());
}
}
```
[//]: # (end)

### Configuration reuse

Collector configurations can be defined separately and thus reused.
Expand Down
51 changes: 39 additions & 12 deletions code-assert/pom.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand All @@ -13,14 +14,19 @@

<properties>
<slf4j.version>1.7.25</slf4j.version>
<checkstyle.version>6.19</checkstyle.version>
<findbugs.version>3.0.1</findbugs.version>
<pmd.version>5.4.1</pmd.version>
<detekt.version>1.0.0.RC4</detekt.version>
<ktlint.version>0.9.2</ktlint.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>guru.nidi</groupId>
<artifactId>code-assert-maven-plugin</artifactId>
<version>0.8.2</version>
<version>0.8.5</version>
<executions>
<execution>
<goals>
Expand Down Expand Up @@ -86,7 +92,7 @@
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs</artifactId>
<version>3.0.1</version>
<version>${findbugs.version}</version>
</dependency>
<dependency>
<groupId>com.h3xstream.findsecbugs</groupId>
Expand All @@ -96,12 +102,12 @@
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>5.4.1</version>
<version>${pmd.version}</version>
</dependency>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>6.19</version>
<version>${checkstyle.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
Expand All @@ -110,21 +116,26 @@
</exclusions>
</dependency>

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

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

<dependency>
Expand Down Expand Up @@ -161,4 +172,20 @@
</dependency>
</dependencies>

<repositories>
<repository>
<id>arturbosch-code-analysis</id>
<name>arturbosch-code-analysis (for detekt)</name>
<url>https://dl.bintray.com/arturbosch/code-analysis/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public CheckstyleResult analyze() {
try {
final LoggingAuditListener listener = new LoggingAuditListener();
checker.addListener(listener);
checker.setModuleClassLoader(CheckstyleAnalyzer.class.getClassLoader());
checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
checker.configure(ConfigurationLoader.loadConfiguration(checks.location, createPropertyResolver()));
checker.process(config.getSources());
return createResult(listener.events);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,28 @@ public String getPack() {
return pack;
}

public Path commonBase(Path path) {
final String[] thisParts = getPath().split("/");
final String[] otherParts = path.getPath().split("/");
int i = 0;
final StringBuilder res = new StringBuilder();
while (i < Math.min(thisParts.length, otherParts.length) && thisParts[i].equals(otherParts[i])) {
res.append(thisParts[i]).append('/');
i++;
}
return res.length() < base.length()
? new Path(res.substring(0, res.length() - 1), "")
: new Path(base, pack.substring(0, res.length() - base.length() - 2));
}

public static Path commonBase(Iterable<Path> paths) {
Path base = null;
for (final Path path : paths) {
base = base == null ? path : base.commonBase(path);
}
return base;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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.detekt;

import guru.nidi.codeassert.Analyzer;
import guru.nidi.codeassert.config.AnalyzerConfig;
import guru.nidi.codeassert.config.UsageCounter;
import io.gitlab.arturbosch.detekt.api.*;
import io.gitlab.arturbosch.detekt.core.*;

import java.io.File;
import java.net.URL;
import java.util.*;

import static guru.nidi.codeassert.config.Language.KOTLIN;
import static io.gitlab.arturbosch.detekt.api.Severity.*;
import static java.lang.Boolean.FALSE;

public class DetektAnalyzer implements Analyzer<List<TypedDetektFinding>> {
private final AnalyzerConfig config;
private final DetektCollector collector;

public DetektAnalyzer(AnalyzerConfig config, DetektCollector collector) {
this.config = config;
this.collector = collector;
}

public DetektResult analyze() {
final URL defaultConfig = DetektAnalyzer.class.getResource("default-detekt-config.yml");
final Config detektConfig = new NoFormat(YamlConfig.Companion.loadResource(defaultConfig));
final File baseDir = new File(AnalyzerConfig.Path.commonBase(config.getSourcePaths(KOTLIN)).getPath());
final ProcessingSettings settings = new ProcessingSettings(baseDir.toPath(),
detektConfig, Collections.emptyList(), false, false, Collections.emptyList());
final KtTreeCompiler compiler = KtTreeCompiler.Companion.instance(settings);
final Detektion detektion = DetektFacade.INSTANCE.instance(settings).run(compiler);
return createResult(baseDir, detektion);
}

private DetektResult createResult(File baseDir, Detektion detektion) {
final List<TypedDetektFinding> filtered = new ArrayList<>();
final UsageCounter counter = new UsageCounter();
for (final Map.Entry<String, List<Finding>> entry : detektion.getFindings().entrySet()) {
for (final Finding finding : entry.getValue()) {
final TypedDetektFinding typed = new TypedDetektFinding(baseDir, finding.getEntity(), entry.getKey(),
finding.getId(), finding.getIssue().getSeverity(), finding.getIssue().getDescription());
if (counter.accept(collector.accept(typed))) {
filtered.add(typed);
}
}
}
collector.printUnusedWarning(counter);
Collections.sort(filtered, TypedDetektFindingComparator.INSTANCE);
return new DetektResult(this, filtered, collector.unusedActions(counter));
}

private static class NoFormat implements Config {
private final Config delegate;

NoFormat(Config delegate) {
this.delegate = delegate;
}

@Override
public Config subConfig(String s) {
return delegate.subConfig(s);
}

@Override
public <T> T valueOrDefault(String s, T t) {
return "autoCorrect".equals(s) ? (T) FALSE : delegate.valueOrDefault(s, t);
}
}

private static class SeverityComparator implements Comparator<Severity> {
static final SeverityComparator INSTANCE = new SeverityComparator();

private static final List<Severity> SEVERITIES = Arrays.asList(
Style, CodeSmell, Minor, Performance, Maintainability, Warning, Security, Defect);

public int compare(Severity s1, Severity s2) {
return SEVERITIES.indexOf(s2) - SEVERITIES.indexOf(s1);
}
}

private static class TypedDetektFindingComparator implements Comparator<TypedDetektFinding> {
static final TypedDetektFindingComparator INSTANCE = new TypedDetektFindingComparator();

public int compare(TypedDetektFinding f1, TypedDetektFinding f2) {
int res = SeverityComparator.INSTANCE.compare(f1.severity, f2.severity);
if (res != 0) {
return res;
}
res = f1.type.compareTo(f2.type);
if (res != 0) {
return res;
}
return f1.name.compareTo(f2.name);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.detekt;

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

import java.io.File;
import java.util.List;

import static guru.nidi.codeassert.config.Language.KOTLIN;

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

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

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

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

@Override
protected ActionResult doAccept(TypedDetektFinding issue, Ignore action) {
final File file = new File(issue.basedir, issue.entity.getLocation().getFile());
final String className = guessClassFromFile(file.getAbsolutePath(), KOTLIN);
return action.accept(new NamedLocation(issue.name, KOTLIN, className, null, true));
}

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

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

}
Loading

0 comments on commit fc6d7f0

Please sign in to comment.