From 770175c51a40f96a149f1740ee9fcb683ccd6d2d Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Mon, 14 Jun 2021 15:55:45 -0400 Subject: [PATCH] Ban the var keyword via error-prone `VarUsage` (#1788) Ban the var keyword via error-prone `VarUsage` --- .../baseline/errorprone/VarUsage.java | 68 ++++++++++++++++++ .../baseline/errorprone/VarUsageTest.java | 72 +++++++++++++++++++ changelog/@unreleased/pr-1788.v2.yml | 5 ++ .../BaselineErrorProneExtension.java | 1 + 4 files changed, 146 insertions(+) create mode 100644 baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/VarUsage.java create mode 100644 baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/VarUsageTest.java create mode 100644 changelog/@unreleased/pr-1788.v2.yml diff --git a/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/VarUsage.java b/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/VarUsage.java new file mode 100644 index 000000000..d7025763f --- /dev/null +++ b/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/VarUsage.java @@ -0,0 +1,68 @@ +/* + * (c) Copyright 2020 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.LinkType; +import com.google.errorprone.BugPattern.SeverityLevel; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.fixes.SuggestedFix; +import com.google.errorprone.fixes.SuggestedFixes; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.util.ASTHelpers; +import com.google.errorprone.util.ErrorProneToken; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import com.sun.tools.javac.parser.Tokens.TokenKind; + +@AutoService(BugChecker.class) +@BugPattern( + name = "VarUsage", + link = "https://github.com/palantir/gradle-baseline#baseline-error-prone-checks", + linkType = LinkType.CUSTOM, + severity = SeverityLevel.ERROR, + summary = "The `var` keyword results in illegible code in most cases and should not be used.") +public final class VarUsage extends BugChecker implements BugChecker.VariableTreeMatcher { + + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + Tree typeTree = tree.getType(); + // The AST doesn't differentiate between 'var' and a concrete type, so we check the source + // prior to tokenizing the variable tree. + String sourceType = state.getSourceForNode(typeTree); + if (sourceType != null) { + return Description.NO_MATCH; + } + for (ErrorProneToken token : state.getOffsetTokensForNode(tree)) { + if (token.kind() == TokenKind.IDENTIFIER + && token.hasName() + && token.name().contentEquals("var")) { + SuggestedFix.Builder fix = SuggestedFix.builder(); + return buildDescription(typeTree) + .addFix(fix.replace( + token.pos(), + token.endPos(), + SuggestedFixes.prettyType(state, fix, ASTHelpers.getType(typeTree))) + .build()) + .build(); + } + } + return Description.NO_MATCH; + } +} diff --git a/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/VarUsageTest.java b/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/VarUsageTest.java new file mode 100644 index 000000000..529d1d0e3 --- /dev/null +++ b/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/VarUsageTest.java @@ -0,0 +1,72 @@ +/* + * (c) Copyright 2021 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 org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +class VarUsageTest { + + @Test + @EnabledForJreRange(min = JRE.JAVA_10) + void testSimple() { + fix().addInputLines( + "Test.java", + // format + "class Test {", + " void function() {", + " var x = 3;", + " }", + "}") + .addOutputLines( + "Test.java", + // format + "class Test {", + " void function() {", + " int x = 3;", + " }", + "}") + .doTest(); + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_10) + void testWithFinalModifier() { + fix().addInputLines( + "Test.java", + // format + "class Test {", + " void function() {", + " final var x = 3;", + " }", + "}") + .addOutputLines( + "Test.java", + // format + "class Test {", + " void function() {", + " final int x = 3;", + " }", + "}") + .doTest(); + } + + private RefactoringValidator fix() { + return RefactoringValidator.of(VarUsage.class, getClass()); + } +} diff --git a/changelog/@unreleased/pr-1788.v2.yml b/changelog/@unreleased/pr-1788.v2.yml new file mode 100644 index 000000000..00d0c8ae1 --- /dev/null +++ b/changelog/@unreleased/pr-1788.v2.yml @@ -0,0 +1,5 @@ +type: improvement +improvement: + description: Ban the var keyword via error-prone `VarUsage` + links: + - https://github.com/palantir/gradle-baseline/pull/1788 diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/extensions/BaselineErrorProneExtension.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/extensions/BaselineErrorProneExtension.java index b6bda7a4c..f3bbdce0d 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/extensions/BaselineErrorProneExtension.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/extensions/BaselineErrorProneExtension.java @@ -71,6 +71,7 @@ public class BaselineErrorProneExtension { // TODO(ckozak): re-enable pending scala check // "ThrowSpecificity", "UnsafeGaugeRegistration", + "VarUsage", // Built-in checks "ArrayEquals",