Skip to content
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

Add BugCheckerAutoService #2028

Merged
merged 4 commits into from
Jan 7, 2022
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ Safe Logging can be found at [github.com/palantir/safe-logging](https://github.c
- `PreferImmutableStreamExCollections`: It's common to use toMap/toSet/toList() as the terminal operation on a stream, but would be extremely surprising to rely on the mutability of these collections. Prefer `toImmutableMap`, `toImmutableSet` and `toImmutableList`. (If the performance overhead of a stream is already acceptable, then the `UnmodifiableFoo` wrapper is likely tolerable).
- `DangerousIdentityKey`: Key type does not override equals() and hashCode, so comparisons will be done on reference equality only.
- `ConsistentOverrides`: Ensure values are bound to the correct variables when overriding methods
- `FilterOutputStreamSlowMultibyteWrite`:Subclasses of FilterOutputStream should provide a more efficient implementation of `write(byte[], int, int)` to avoid slow writes.
- `FilterOutputStreamSlowMultibyteWrite`: Subclasses of FilterOutputStream should provide a more efficient implementation of `write(byte[], int, int)` to avoid slow writes.
- `BugCheckerAutoService`: Concrete BugChecker implementations should be annotated `@AutoService(BugChecker.class)` for auto registration with error-prone.

### Programmatic Application

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* (c) Copyright 2022 Palantir Technologies Inc. All rights reserved.
*
* 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 com.palantir.baseline.errorprone;

import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import java.util.List;
import javax.lang.model.element.ElementKind;

@AutoService(BugChecker.class)
@BugPattern(
name = "BugCheckerAutoService",
link = "https://github.com/palantir/gradle-baseline#baseline-error-prone-checks",
linkType = BugPattern.LinkType.CUSTOM,
summary = "Concrete BugChecker implementations should be annotated "
+ "`@AutoService(BugChecker.class)` for auto registration with error-prone.",
severity = SeverityLevel.ERROR,
tags = StandardTags.LIKELY_ERROR)
public final class BugCheckerAutoService extends BugChecker implements ClassTreeMatcher {

private static final String AUTO_SERVICE = "com.google.auto.service.AutoService";
private static final Matcher<ClassTree> isBugChecker =
Matchers.allOf(Matchers.isSubtypeOf(BugChecker.class), Matchers.hasAnnotation(BugPattern.class));

private static final Matcher<AnnotationTree> autoServiceBugChecker = Matchers.allOf(
Matchers.isType(AUTO_SERVICE),
Matchers.hasArgumentWithValue("value", Matchers.classLiteral(Matchers.isSameType(BugChecker.class))));

@Override
public Description matchClass(ClassTree classTree, VisitorState state) {
if (!isBugChecker.matches(classTree, state)) {
return Description.NO_MATCH;
}

TypeSymbol thisClassSymbol = ASTHelpers.getSymbol(classTree);
if (thisClassSymbol.getKind() != ElementKind.CLASS) {
return Description.NO_MATCH;
}

List<? extends AnnotationTree> annotations = ASTHelpers.getAnnotations(classTree);
boolean hasAutoServiceBugChecker =
annotations.stream().anyMatch(annotationTree -> autoServiceBugChecker.matches(annotationTree, state));
if (hasAutoServiceBugChecker) {
return Description.NO_MATCH;
}

SuggestedFix.Builder fix = SuggestedFix.builder();
String autoService = SuggestedFixes.qualifyType(state, fix, AUTO_SERVICE);
String bugChecker = SuggestedFixes.qualifyType(state, fix, BugChecker.class.getName());
return buildDescription(classTree)
.addFix(fix.prefixWith(classTree, "@" + autoService + "(" + bugChecker + ".class)\n")
.build())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* (c) Copyright 2022 Palantir Technologies Inc. All rights reserved.
*
* 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 com.palantir.baseline.errorprone;

import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;

class BugCheckerAutoServiceTest {

private CompilationTestHelper compilationHelper() {
return CompilationTestHelper.newInstance(BugCheckerAutoService.class, getClass());
}

private RefactoringValidator fix() {
return RefactoringValidator.of(BugCheckerAutoService.class, getClass());
}

@Test
public void doingItRight() {
compilationHelper()
.addSourceLines(
"TestChecker.java",
"import com.google.auto.service.AutoService;",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"@AutoService(BugChecker.class)",
"@BugPattern(name=\"Test\", summary=\"a\", severity=SeverityLevel.ERROR)",
"public class TestChecker extends BugChecker {",
"}")
.doTest();
}

@Test
public void nonCheckerAutoService() {
compilationHelper()
.addSourceLines(
"Test.java",
"import com.google.auto.service.AutoService;",
"@AutoService(Runnable.class)",
"public class Test implements Runnable {",
" public void run() {}",
"}")
.doTest();
}

@Test
public void fixBugChecker() {
fix().addInputLines(
"TestChecker.java",
"import com.google.auto.service.AutoService;",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"@BugPattern(name=\"Test\", summary=\"a\", severity=SeverityLevel.ERROR)",
"public class TestChecker extends BugChecker {",
"}")
.addOutputLines(
"TestChecker.java",
"import com.google.auto.service.AutoService;",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"@AutoService(BugChecker.class)",
"@BugPattern(name=\"Test\", summary=\"a\", severity=SeverityLevel.ERROR)",
"public class TestChecker extends BugChecker {",
"}")
.doTest();
}
}
9 changes: 9 additions & 0 deletions changelog/@unreleased/pr-2028.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type: improvement
improvement:
description: |-
Add BugCheckerAutoService

Concrete BugChecker implementations should be annotated
`@AutoService(BugChecker.class)` for auto registration with error-prone.
links:
- https://github.com/palantir/gradle-baseline/pull/2028
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class BaselineErrorProneExtension {
// Baseline checks
"AssertNoArgs",
"AvoidNewHashMapInt",
"BugCheckerAutoService",
"CatchBlockLogException",
// TODO(ckozak): re-enable pending scala check
// "CatchSpecificity",
Expand Down