Search in sources :

Example 11 with SuggestedFix

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);
}
Also used : Type(com.sun.tools.javac.code.Type) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) VariableTree(com.sun.source.tree.VariableTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) IdentifierTree(com.sun.source.tree.IdentifierTree) Tree(com.sun.source.tree.Tree)

Example 12 with SuggestedFix

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);
}
Also used : ClassType(com.sun.tools.javac.code.Type.ClassType) Type(com.sun.tools.javac.code.Type) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ClassType(com.sun.tools.javac.code.Type.ClassType)

Example 13 with SuggestedFix

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()));
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher) MethodTree(com.sun.source.tree.MethodTree) Collection(java.util.Collection) CUSTOM(com.google.errorprone.BugPattern.LinkType.CUSTOM) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) Streams(com.google.common.collect.Streams) Objects(java.util.Objects) VisitorState(com.google.errorprone.VisitorState) List(java.util.List) Stream(java.util.stream.Stream) Multimaps.toMultimap(com.google.common.collect.Multimaps.toMultimap) Description(com.google.errorprone.matchers.Description) AutoValue(com.google.auto.value.AutoValue) BugPattern(com.google.errorprone.BugPattern) SUGGESTION(com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) JDK(com.google.errorprone.BugPattern.Category.JDK) Tree(com.sun.source.tree.Tree) LinkedHashMultimap(com.google.common.collect.LinkedHashMultimap) ASTHelpers(com.google.errorprone.util.ASTHelpers) ClassTree(com.sun.source.tree.ClassTree) Name(javax.lang.model.element.Name) SuggestedFix(com.google.errorprone.fixes.SuggestedFix)

Example 14 with SuggestedFix

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);
}
Also used : Context(com.sun.tools.javac.util.Context) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) StringWriter(java.io.StringWriter) IOException(java.io.IOException)

Example 15 with SuggestedFix

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;
}
Also used : TemporalUnit(java.time.temporal.TemporalUnit) Duration(java.time.Duration) LiteralTree(com.sun.source.tree.LiteralTree) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) Converter(com.google.common.base.Converter) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ChronoUnit(java.time.temporal.ChronoUnit)

Aggregations

SuggestedFix (com.google.errorprone.fixes.SuggestedFix)16 ExpressionTree (com.sun.source.tree.ExpressionTree)5 Tree (com.sun.source.tree.Tree)5 AnnotationTree (com.sun.source.tree.AnnotationTree)4 Symbol (com.sun.tools.javac.code.Symbol)4 MethodSymbol (com.sun.tools.javac.code.Symbol.MethodSymbol)4 Description (com.google.errorprone.matchers.Description)3 Type (com.sun.tools.javac.code.Type)3 JCTree (com.sun.tools.javac.tree.JCTree)3 ArrayList (java.util.ArrayList)3 Streams (com.google.common.collect.Streams)2 BugPattern (com.google.errorprone.BugPattern)2 JDK (com.google.errorprone.BugPattern.Category.JDK)2 VisitorState (com.google.errorprone.VisitorState)2 ClassTreeMatcher (com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher)2 Builder (com.google.errorprone.fixes.SuggestedFix.Builder)2 ASTHelpers (com.google.errorprone.util.ASTHelpers)2 ClassTree (com.sun.source.tree.ClassTree)2 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)2 MethodTree (com.sun.source.tree.MethodTree)2