com.google.errorprone.bugpatterns.threadsafety.ImmutableRefactoring Maven / Gradle / Ivy
/*
* Copyright 2018 The Error Prone Authors.
*
* 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.google.errorprone.bugpatterns.threadsafety;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.code.Symbol;
import java.util.Optional;
/** A {@link BugChecker}; see the associated {@link BugPattern} annotation for details. */
@BugPattern(
name = "ImmutableRefactoring",
summary = "Refactors uses of the JSR 305 @Immutable to Error Prone's annotation",
severity = SUGGESTION)
public class ImmutableRefactoring extends BugChecker implements CompilationUnitTreeMatcher {
@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
ImmutableChecker immutableChecker =
new ImmutableChecker(
ImmutableSet.of(
javax.annotation.concurrent.Immutable.class.getName(),
com.google.errorprone.annotations.Immutable.class.getName()));
Optional immutableImport =
tree.getImports().stream()
.filter(
i -> {
Symbol s = ASTHelpers.getSymbol(i.getQualifiedIdentifier());
return s != null
&& s.getQualifiedName()
.contentEquals(javax.annotation.concurrent.Immutable.class.getName());
})
.findFirst();
if (!immutableImport.isPresent()) {
return Description.NO_MATCH;
}
boolean[] ok = {true};
new TreePathScanner() {
@Override
public Void visitClass(ClassTree node, Void unused) {
if (immutableChecker.matchClass(node, createVisitorState().withPath(getCurrentPath()))
!= Description.NO_MATCH) {
ok[0] = false;
}
return super.visitClass(node, null);
}
@Override
public Void visitNewClass(NewClassTree node, Void unused) {
if (immutableChecker.matchNewClass(node, createVisitorState().withPath(getCurrentPath()))
!= Description.NO_MATCH) {
ok[0] = false;
}
return super.visitNewClass(node, null);
}
private VisitorState createVisitorState() {
return VisitorState.createConfiguredForCompilation(
state.context,
description -> ok[0] = false,
ImmutableMap.of(),
state.errorProneOptions());
}
}.scan(state.getPath(), null);
if (!ok[0]) {
// TODO(cushon): replace non-compliant @Immutable annotations with javadoc
return Description.NO_MATCH;
}
return describeMatch(
immutableImport.get(),
SuggestedFix.builder()
.removeImport(javax.annotation.concurrent.Immutable.class.getName())
.addImport(com.google.errorprone.annotations.Immutable.class.getName())
.build());
}
}