Signal-Android/lintchecks/src/main/java/org/signal/lint/AlertDialogBuilderDetector....

86 wiersze
3.9 KiB
Java

package org.signal.lint;
import com.android.tools.lint.client.api.JavaEvaluator;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.JavaContext;
import com.android.tools.lint.detector.api.LintFix;
import com.android.tools.lint.detector.api.Scope;
import com.android.tools.lint.detector.api.Severity;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.uast.UCallExpression;
import org.jetbrains.uast.UExpression;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@SuppressWarnings("UnstableApiUsage")
public final class AlertDialogBuilderDetector extends Detector implements Detector.UastScanner {
static final Issue ALERT_DIALOG_BUILDER_USAGE = Issue.create("AlertDialogBuilderUsage",
"Creating dialog with AlertDialog.Builder instead of MaterialAlertDialogBuilder",
"Signal utilizes MaterialAlertDialogBuilder for more consistent and pleasant AlertDialogs.",
Category.MESSAGES,
5,
Severity.WARNING,
new Implementation(AlertDialogBuilderDetector.class, Scope.JAVA_FILE_SCOPE));
@Override
public @Nullable List<String> getApplicableConstructorTypes() {
return Arrays.asList("android.app.AlertDialog.Builder", "androidx.appcompat.app.AlertDialog.Builder");
}
@Override
public void visitConstructor(JavaContext context, @NotNull UCallExpression call, @NotNull PsiMethod method) {
JavaEvaluator evaluator = context.getEvaluator();
if (evaluator.isMemberInClass(method, "android.app.AlertDialog.Builder")) {
LintFix fix = quickFixIssueAlertDialogBuilder(call);
context.report(ALERT_DIALOG_BUILDER_USAGE,
call,
context.getLocation(call),
"Using 'android.app.AlertDialog.Builder' instead of com.google.android.material.dialog.MaterialAlertDialogBuilder",
fix);
}
if (evaluator.isMemberInClass(method, "androidx.appcompat.app.AlertDialog.Builder")) {
LintFix fix = quickFixIssueAlertDialogBuilder(call);
context.report(ALERT_DIALOG_BUILDER_USAGE,
call,
context.getLocation(call),
"Using 'androidx.appcompat.app.AlertDialog.Builder' instead of com.google.android.material.dialog.MaterialAlertDialogBuilder",
fix);
}
}
private LintFix quickFixIssueAlertDialogBuilder(@NotNull UCallExpression alertBuilderCall) {
List<UExpression> arguments = alertBuilderCall.getValueArguments();
UExpression context = arguments.get(0);
String fixSource = "new com.google.android.material.dialog.MaterialAlertDialogBuilder";
switch (arguments.size()) {
case 1:
fixSource += String.format("(%s)", context);
break;
case 2:
UExpression themeOverride = arguments.get(1);
fixSource += String.format("(%s, %s)", context, themeOverride);
break;
default:
throw new IllegalStateException("MaterialAlertDialogBuilder overloads should have 1 or 2 arguments");
}
String builderCallSource = alertBuilderCall.asSourceString();
LintFix.GroupBuilder fixGrouper = fix().group();
fixGrouper.add(fix().replace().text(builderCallSource).shortenNames().reformat(true).with(fixSource).build());
return fixGrouper.build();
}
}