use of com.google.errorprone.fixes.SuggestedFix in project error-prone by google.
the class MutableConstantField method matchVariable.
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
if (!isConstantField(ASTHelpers.getSymbol(tree))) {
return Description.NO_MATCH;
}
Tree rhsTree = tree.getInitializer();
Type rhsType = ASTHelpers.getType(rhsTree);
if (rhsType == null || !ImmutableCollections.isImmutableType(rhsType)) {
return Description.NO_MATCH;
}
Tree lhsTree = tree.getType();
Type lhsType = ASTHelpers.getType(lhsTree);
if (lhsType == null || ImmutableCollections.isImmutableType(lhsType)) {
return Description.NO_MATCH;
}
String lhsTypeQualifiedName = getTypeQualifiedName(lhsType);
String newLhsTypeQualifiedName = ImmutableCollections.mutableToImmutable(lhsTypeQualifiedName).orElse(getTypeQualifiedName(rhsType));
Type newLhsType = state.getTypeFromString(newLhsTypeQualifiedName);
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
fixBuilder.replace(getTypeTree(lhsTree), SuggestedFixes.qualifyType(state, fixBuilder, newLhsType.asElement()));
SuggestedFix fix = fixBuilder.build();
return describeMatch(lhsTree, fix);
}
use of com.google.errorprone.fixes.SuggestedFix in project error-prone by google.
the class MutableMethodReturnType method matchMethod.
@Override
public Description matchMethod(MethodTree methodTree, VisitorState state) {
MethodSymbol methodSymbol = ASTHelpers.getSymbol(methodTree);
if (methodSymbol.isConstructor()) {
return Description.NO_MATCH;
}
if (isMethodCanBeOverridden(methodSymbol, state)) {
return Description.NO_MATCH;
}
if (ANNOTATED_WITH_PRODUCES_OR_PROVIDES.matches(methodTree, state)) {
return Description.NO_MATCH;
}
Type returnType = methodSymbol.getReturnType();
if (ImmutableCollections.isImmutableType(returnType)) {
return Description.NO_MATCH;
}
ImmutableSet<ClassType> returnStatementsTypes = getMethodReturnTypes(methodTree);
if (returnStatementsTypes.isEmpty()) {
return Description.NO_MATCH;
}
boolean alwaysReturnsImmutableType = returnStatementsTypes.stream().allMatch(ImmutableCollections::isImmutableType);
if (!alwaysReturnsImmutableType) {
return Description.NO_MATCH;
}
Optional<String> immutableReturnType = ImmutableCollections.mutableToImmutable(getTypeQualifiedName(returnType));
if (!immutableReturnType.isPresent()) {
immutableReturnType = getCommonImmutableTypeForAllReturnStatementsTypes(returnStatementsTypes);
}
if (!immutableReturnType.isPresent()) {
return Description.NO_MATCH;
}
Type newReturnType = state.getTypeFromString(immutableReturnType.get());
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
fixBuilder.replace(getTypeTree(methodTree.getReturnType()), SuggestedFixes.qualifyType(state, fixBuilder, newReturnType.asElement()));
SuggestedFix fix = fixBuilder.build();
return describeMatch(methodTree.getReturnType(), fix);
}
use of com.google.errorprone.fixes.SuggestedFix in project error-prone by google.
the class UngroupedOverloads method checkOverloads.
private void checkOverloads(VisitorState state, List<? extends Tree> members, Name name, Collection<MemberWithIndex> overloads) {
if (overloads.size() <= 1) {
return;
}
// check if the indices of the overloads in the member list are sequential
MemberWithIndex first = overloads.iterator().next();
boolean grouped = Streams.zip(Stream.iterate(first.index(), i -> i + 1), overloads.stream().map(m -> m.index()), (a, b) -> Objects.equals(a, b)).allMatch(x -> x);
if (grouped) {
return;
}
if (overloads.stream().anyMatch(m -> isSuppressed(m.tree()))) {
return;
}
// build a fix that deletes all but the first overload, and adds them back immediately after
// the first overload
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
StringBuilder sb = new StringBuilder("\n");
overloads.stream().filter(o -> o != first).forEach(o -> {
int start = state.getEndPosition(members.get(o.index() - 1));
int end = state.getEndPosition(o.tree());
sb.append(state.getSourceCode(), start, end).append('\n');
fixBuilder.replace(start, end, "");
});
fixBuilder.postfixWith(first.tree(), sb.toString());
SuggestedFix fix = fixBuilder.build();
String message = String.format("Overloads of '%s' are not grouped together.", name);
// emit findings for each overload
overloads.stream().forEach(o -> state.reportMatch(buildDescription(o.tree()).addFix(fix).setMessage(message).build()));
}
use of com.google.errorprone.fixes.SuggestedFix in project error-prone by google.
the class ExpressionTemplate method replace.
/**
* Generates a {@link SuggestedFix} replacing the specified match (usually of another template)
* with this template.
*/
@Override
public Fix replace(ExpressionTemplateMatch match) {
Inliner inliner = match.createInliner();
Context context = inliner.getContext();
if (annotations().containsKey(UseImportPolicy.class)) {
ImportPolicy.bind(context, annotations().getInstance(UseImportPolicy.class).value());
} else {
ImportPolicy.bind(context, ImportPolicy.IMPORT_TOP_LEVEL);
}
int prec = getPrecedence(match.getLocation(), context);
SuggestedFix.Builder fix = SuggestedFix.builder();
try {
StringWriter writer = new StringWriter();
pretty(inliner.getContext(), writer).printExpr(expression().inline(inliner), prec);
fix.replace(match.getLocation(), writer.toString());
} catch (CouldNotResolveImportException e) {
logger.log(SEVERE, "Failure to resolve in replacement", e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return addImports(inliner, fix);
}
use of com.google.errorprone.fixes.SuggestedFix in project error-prone by google.
the class CanonicalDuration method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Api api;
if (JAVA_TIME_MATCHER.matches(tree, state)) {
api = Api.JAVA;
} else if (JODA_MATCHER.matches(tree, state)) {
api = Api.JODA;
} else {
return NO_MATCH;
}
if (tree.getArguments().size() != 1) {
// TODO(cushon): ofSeconds w/ nano adjustment?
return NO_MATCH;
}
Tree arg = getOnlyElement(tree.getArguments());
if (!(arg instanceof LiteralTree)) {
// don't inline constants
return NO_MATCH;
}
Number value = constValue(arg, Number.class);
if (value == null) {
return NO_MATCH;
}
if (value.intValue() == 0) {
switch(api) {
case JODA:
ExpressionTree receiver = getReceiver(tree);
SuggestedFix fix;
if (receiver == null) {
// static import of the method
fix = SuggestedFix.builder().addImport(api.getDurationFullyQualifiedName()).replace(tree, "Duration.ZERO").build();
} else {
fix = SuggestedFix.replace(state.getEndPosition(getReceiver(tree)), state.getEndPosition(tree), ".ZERO");
}
return buildDescription(tree).setMessage("Duration can be expressed more clearly without units, as Duration.ZERO").addFix(fix).build();
case JAVA:
// don't rewrite e.g. `ofMillis(0)` to `ofDays(0)`
return NO_MATCH;
}
throw new AssertionError(api);
}
MethodSymbol sym = getSymbol(tree);
if (!METHOD_NAME_TO_UNIT.containsKey(sym.getSimpleName().toString())) {
return NO_MATCH;
}
TemporalUnit unit = METHOD_NAME_TO_UNIT.get(sym.getSimpleName().toString());
if (Objects.equals(BLACKLIST.get(unit), value.longValue())) {
return NO_MATCH;
}
Duration duration = Duration.of(value.longValue(), unit);
// largest unit that can be used to exactly express the duration.
for (Map.Entry<ChronoUnit, Converter<Duration, Long>> entry : CONVERTERS.entrySet()) {
ChronoUnit nextUnit = entry.getKey();
if (unit.equals(nextUnit)) {
// We reached the original unit, no simplification is possible.
break;
}
Converter<Duration, Long> converter = entry.getValue();
long nextValue = converter.convert(duration);
if (converter.reverse().convert(nextValue).equals(duration)) {
// We reached a larger than original unit that precisely expresses the duration, rewrite to
// use it instead.
String name = FACTORIES.get(api, nextUnit);
String replacement = String.format("%s(%d%s)", name, nextValue, nextValue == ((int) nextValue) ? "" : "L");
ExpressionTree receiver = getReceiver(tree);
if (receiver == null) {
// static import of the method
SuggestedFix fix = SuggestedFix.builder().addStaticImport(api.getDurationFullyQualifiedName() + "." + name).replace(tree, replacement).build();
return describeMatch(tree, fix);
} else {
return describeMatch(tree, SuggestedFix.replace(state.getEndPosition(receiver), state.getEndPosition(tree), "." + replacement));
}
}
}
return NO_MATCH;
}
Aggregations