mirror of
https://github.com/ankidroid/Anki-Android.git
synced 2024-09-19 19:42:17 +02:00
Add lint checks for new time api
This commit is contained in:
parent
7095a48c01
commit
de3f38ee37
@ -274,4 +274,7 @@ dependencies {
|
||||
|
||||
//For AnkiDroid JS API Versioning
|
||||
implementation "com.github.zafarkhaja:java-semver:0.9.0"
|
||||
|
||||
// Adds the custom lint rules
|
||||
lintChecks project(":lint-rules")
|
||||
}
|
||||
|
@ -23,6 +23,11 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
public class SystemTime extends Time {
|
||||
|
||||
public SystemTime() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long intTimeMS() {
|
||||
return System.currentTimeMillis();
|
||||
|
@ -52,6 +52,8 @@ dependencies {
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testImplementation 'org.junit.vintage:junit-vintage-engine:5.6.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.3.1'
|
||||
|
||||
lintChecks project(":lint-rules")
|
||||
}
|
||||
|
||||
// Borrowed from here:
|
||||
|
1
lint-rules/.gitignore
vendored
Normal file
1
lint-rules/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
20
lint-rules/build.gradle
Normal file
20
lint-rules/build.gradle
Normal file
@ -0,0 +1,20 @@
|
||||
apply plugin: "java-library"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "com.android.tools.lint:lint-api:27.0.1"
|
||||
compileOnly "com.android.tools.lint:lint:27.0.1"
|
||||
|
||||
testImplementation "junit:junit:4.13"
|
||||
testImplementation "com.android.tools.lint:lint:27.0.1"
|
||||
testImplementation "com.android.tools.lint:lint-tests:27.0.1"
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.ichi2.anki.lint;
|
||||
|
||||
import com.android.tools.lint.detector.api.ApiKt;
|
||||
import com.android.tools.lint.detector.api.Issue;
|
||||
import com.ichi2.anki.lint.rules.DirectCalendarInstanceUsage;
|
||||
import com.ichi2.anki.lint.rules.DirectSystemTimeInstantiation;
|
||||
import com.ichi2.anki.lint.rules.DirectSystemCurrentTimeMillisUsage;
|
||||
import com.ichi2.anki.lint.rules.DirectDateInstantiation;
|
||||
import com.ichi2.anki.lint.rules.DirectGregorianInstantiation;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IssueRegistry extends com.android.tools.lint.client.api.IssueRegistry {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Issue> getIssues() {
|
||||
List<Issue> issues = new ArrayList<>();
|
||||
issues.add(DirectCalendarInstanceUsage.ISSUE);
|
||||
issues.add(DirectSystemCurrentTimeMillisUsage.ISSUE);
|
||||
issues.add(DirectDateInstantiation.ISSUE);
|
||||
issues.add(DirectGregorianInstantiation.ISSUE);
|
||||
issues.add(DirectSystemTimeInstantiation.ISSUE);
|
||||
return issues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getApi() {
|
||||
return ApiKt.CURRENT_API;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import com.android.tools.lint.client.api.JavaEvaluator;
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.ichi2.anki.lint.utils.Constants;
|
||||
import com.ichi2.anki.lint.utils.LintUtils;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This custom Lint rules will raise an error if a developer uses the {@link Calendar#getInstance()} method instead
|
||||
* of using the Calendar provided by the new SystemTime class.
|
||||
*/
|
||||
public class DirectCalendarInstanceUsage extends Detector implements SourceCodeScanner {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String ID = "DirectCalendarInstanceUsage";
|
||||
@VisibleForTesting
|
||||
static final String DESCRIPTION = "Use SystemTime instead of directly creating Calendar instances";
|
||||
private static final String EXPLANATION = "Manually creating Calendar instances means time cannot be controlled " +
|
||||
"during testing. Calendar instances must be obtained through the collection's method `getTime()`";
|
||||
private static Implementation implementation = new Implementation(DirectCalendarInstanceUsage.class, Scope.JAVA_FILE_SCOPE);
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
ID,
|
||||
DESCRIPTION,
|
||||
EXPLANATION,
|
||||
Constants.ANKI_TIME_CATEGORY,
|
||||
Constants.ANKI_TIME_PRIORITY,
|
||||
Severity.ERROR,
|
||||
implementation
|
||||
);
|
||||
|
||||
|
||||
public DirectCalendarInstanceUsage() {
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
List<String> forbiddenMethods = new ArrayList<>();
|
||||
forbiddenMethods.add("getInstance");
|
||||
return forbiddenMethods;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitMethodCall(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod method) {
|
||||
super.visitMethodCall(context, node, method);
|
||||
JavaEvaluator evaluator = context.getEvaluator();
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Time", "SystemTime") && evaluator.isMemberInClass(method, "java.util.Calendar")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
context.getCallLocation(node, true, true),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.ichi2.anki.lint.utils.Constants;
|
||||
import com.ichi2.anki.lint.utils.LintUtils;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This custom Lint rules will raise an error if a developer instantiates the {@link java.util.Date} class directly
|
||||
* instead of using a {@link java.util.Date} provided through the new SystemTime class.
|
||||
*/
|
||||
public class DirectDateInstantiation extends Detector implements SourceCodeScanner {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String ID = "DirectDateInstantiation";
|
||||
@VisibleForTesting
|
||||
static final String DESCRIPTION = "Use SystemTime instead of directly instantiating Date";
|
||||
private static final String EXPLANATION = "Creating Date instances directly means dates cannot be controlled during" +
|
||||
" testing, so it is not allowed. Use the SystemTime class instead";
|
||||
private static Implementation implementation = new Implementation(DirectDateInstantiation.class, Scope.JAVA_FILE_SCOPE);
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
ID,
|
||||
DESCRIPTION,
|
||||
EXPLANATION,
|
||||
Constants.ANKI_TIME_CATEGORY,
|
||||
Constants.ANKI_TIME_PRIORITY,
|
||||
Severity.ERROR,
|
||||
implementation
|
||||
);
|
||||
|
||||
|
||||
public DirectDateInstantiation() {
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableConstructorTypes() {
|
||||
List<String> forbiddenConstructors = new ArrayList<>();
|
||||
forbiddenConstructors.add("java.util.Date");
|
||||
return forbiddenConstructors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitConstructor(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod constructor) {
|
||||
super.visitConstructor(context, node, constructor);
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Time", "SystemTime")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
node,
|
||||
context.getLocation(node),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import com.android.tools.lint.client.api.JavaEvaluator;
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.ichi2.anki.lint.utils.Constants;
|
||||
import com.ichi2.anki.lint.utils.LintUtils;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This custom Lint rules will raise an error if a developer uses the {@link GregorianCalendar#from(ZonedDateTime)}
|
||||
* method to obtain an instance instead of using the new SystemTime class.
|
||||
*/
|
||||
public class DirectGregorianInstantiation extends Detector implements SourceCodeScanner {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String ID = "DirectGregorianInstantiation";
|
||||
@VisibleForTesting
|
||||
static final String DESCRIPTION = "Use SystemTime instead of directly creating GregorianCalendar instances";
|
||||
private static final String EXPLANATION = "Creating GregorianCalendar instances with from() is not allowed, as " +
|
||||
"it prevents control of time during testing. Use the SystemTime class instead";
|
||||
private static Implementation implementation = new Implementation(DirectGregorianInstantiation.class, Scope.JAVA_FILE_SCOPE);
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
ID,
|
||||
DESCRIPTION,
|
||||
EXPLANATION,
|
||||
Constants.ANKI_TIME_CATEGORY,
|
||||
Constants.ANKI_TIME_PRIORITY,
|
||||
Severity.ERROR,
|
||||
implementation
|
||||
);
|
||||
|
||||
|
||||
public DirectGregorianInstantiation() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
List<String> forbiddenMethods = new ArrayList<>();
|
||||
forbiddenMethods.add("from");
|
||||
return forbiddenMethods;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableConstructorTypes() {
|
||||
List<String> forbiddenConstructors = new ArrayList<>();
|
||||
forbiddenConstructors.add("java.util.GregorianCalendar");
|
||||
return forbiddenConstructors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitMethodCall(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod method) {
|
||||
super.visitMethodCall(context, node, method);
|
||||
JavaEvaluator evaluator = context.getEvaluator();
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Time", "SystemTime") && evaluator.isMemberInClass(method, "java.util.GregorianCalendar")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
context.getCallLocation(node, true, true),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitConstructor(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod constructor) {
|
||||
super.visitConstructor(context, node, constructor);
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Time", "SystemTime")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
node,
|
||||
context.getLocation(node),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import com.android.tools.lint.client.api.JavaEvaluator;
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.ichi2.anki.lint.utils.Constants;
|
||||
import com.ichi2.anki.lint.utils.LintUtils;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This custom Lint rules will raise an error if a developer uses the {@link System#currentTimeMillis()} method instead
|
||||
* of using the time provided by the new SystemTime class.
|
||||
*/
|
||||
public class DirectSystemCurrentTimeMillisUsage extends Detector implements SourceCodeScanner {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String ID = "DirectSystemCurrentTimeMillisUsage";
|
||||
@VisibleForTesting
|
||||
static final String DESCRIPTION = "Use SystemTime instead of System.currentTimeMillis()";
|
||||
private static final String EXPLANATION = "Using time directly means time values cannot be controlled during testing. " +
|
||||
"Time values like System.currentTimeMillis() must be obtained through the SystemTime class";
|
||||
private static Implementation implementation = new Implementation(DirectSystemCurrentTimeMillisUsage.class, Scope.JAVA_FILE_SCOPE);
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
ID,
|
||||
DESCRIPTION,
|
||||
EXPLANATION,
|
||||
Constants.ANKI_TIME_CATEGORY,
|
||||
Constants.ANKI_TIME_PRIORITY,
|
||||
Severity.ERROR,
|
||||
implementation
|
||||
);
|
||||
|
||||
|
||||
public DirectSystemCurrentTimeMillisUsage() {
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableMethodNames() {
|
||||
List<String> forbiddenSystemMethods = new ArrayList<>();
|
||||
forbiddenSystemMethods.add("currentTimeMillis");
|
||||
return forbiddenSystemMethods;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitMethodCall(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod method) {
|
||||
super.visitMethodCall(context, node, method);
|
||||
JavaEvaluator evaluator = context.getEvaluator();
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Time", "SystemTime") && evaluator.isMemberInClass(method, "java.lang.System")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
context.getCallLocation(node, true, true),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
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.Scope;
|
||||
import com.android.tools.lint.detector.api.Severity;
|
||||
import com.android.tools.lint.detector.api.SourceCodeScanner;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.ichi2.anki.lint.utils.Constants;
|
||||
import com.ichi2.anki.lint.utils.LintUtils;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This custom Lint rules will raise an error if a developer instantiates the SystemTime class directly
|
||||
* instead of using the Time class from a Collection.
|
||||
* <br />
|
||||
* NOTE: For future reference, if you plan on creating a Lint rule which looks for a constructor invocation, make sure
|
||||
* that the target class has a constructor defined in its source code!
|
||||
*/
|
||||
public class DirectSystemTimeInstantiation extends Detector implements SourceCodeScanner {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String ID = "DirectSystemTimeInstantiation";
|
||||
@VisibleForTesting
|
||||
static final String DESCRIPTION = "Use Time instead of SystemTime";
|
||||
private static final String EXPLANATION = "Creating SystemTime instances directly means time cannot be controlled during" +
|
||||
" testing, so it is not allowed. Use the Time class instead";
|
||||
private static Implementation implementation = new Implementation(DirectSystemTimeInstantiation.class, Scope.JAVA_FILE_SCOPE);
|
||||
public static final Issue ISSUE = Issue.create(
|
||||
ID,
|
||||
DESCRIPTION,
|
||||
EXPLANATION,
|
||||
Constants.ANKI_TIME_CATEGORY,
|
||||
Constants.ANKI_TIME_PRIORITY,
|
||||
Severity.ERROR,
|
||||
implementation
|
||||
);
|
||||
|
||||
|
||||
public DirectSystemTimeInstantiation() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> getApplicableConstructorTypes() {
|
||||
List<String> forbiddenConstructors = new ArrayList<>();
|
||||
forbiddenConstructors.add("com.ichi2.libanki.utils.SystemTime");
|
||||
return forbiddenConstructors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitConstructor(@NotNull JavaContext context, @NotNull UCallExpression node, @NotNull PsiMethod constructor) {
|
||||
super.visitConstructor(context, node, constructor);
|
||||
List<UClass> foundClasses = context.getUastFile().getClasses();
|
||||
if (!LintUtils.isAnAllowedClass(foundClasses, "Storage", "CollectionHelper")) {
|
||||
context.report(
|
||||
ISSUE,
|
||||
node,
|
||||
context.getLocation(node),
|
||||
DESCRIPTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.ichi2.anki.lint.utils;
|
||||
|
||||
import com.android.tools.lint.detector.api.Category;
|
||||
|
||||
import static com.android.tools.lint.detector.api.Category.create;
|
||||
|
||||
/**
|
||||
* Hold some constants applicable to all lint issues.
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
/**
|
||||
* A special {@link Category} which groups the Lint issues related to the usage of the new SystemTime class as a
|
||||
* sub category for {@link Category#CORRECTNESS}.
|
||||
*/
|
||||
public static final Category ANKI_TIME_CATEGORY = create(Category.CORRECTNESS, "AnkiTime", 10);
|
||||
|
||||
/**
|
||||
* The priority for the Lint issues used by all rules related to the restrictions introduced by SystemTime.
|
||||
*/
|
||||
public static final int ANKI_TIME_PRIORITY = 10;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.ichi2.anki.lint.utils;
|
||||
|
||||
import org.jetbrains.uast.UClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LintUtils {
|
||||
|
||||
private LintUtils() {
|
||||
// no instantiation
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A helper method to check for special classes(Time and SystemTime) where the rules related to time apis shouldn't
|
||||
* be applied.
|
||||
*
|
||||
* @param classes the list of classes to look through
|
||||
* @param allowedClasses the list of classes where the checks should be ignored
|
||||
* @return true if this is a class where the checks should not be applied, false otherwise
|
||||
*/
|
||||
public static boolean isAnAllowedClass(List<UClass> classes, String... allowedClasses) {
|
||||
boolean isInAllowedClass = false;
|
||||
for (int i = 0; i < classes.size(); i++) {
|
||||
final String className = classes.get(i).getName();
|
||||
for (String allowedClass: allowedClasses) {
|
||||
if (className.equals(allowedClass)) {
|
||||
isInAllowedClass = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInAllowedClass;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
com.ichi2.anki.lint.IssueRegistry
|
@ -0,0 +1,52 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFile.JavaTestFile.create;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DirectCalendarInstanceUsageTest {
|
||||
|
||||
private final String stubCalendar = " \n" +
|
||||
"package java.util; \n" +
|
||||
" \n" +
|
||||
"public class Calendar { \n" +
|
||||
" \n" +
|
||||
" public static Calendar getInstance() { \n" +
|
||||
" return null; \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
private final String javaFileToBeTested = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.Calendar; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" Calendar c = Calendar.getInstance(); \n" +
|
||||
" c.clear(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
|
||||
@Test
|
||||
public void showsErrorForInvalidUsage() {
|
||||
lint()
|
||||
.allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubCalendar), create(javaFileToBeTested))
|
||||
.issues(DirectCalendarInstanceUsage.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectCalendarInstanceUsage.ID));
|
||||
assertTrue(output.contains(DirectCalendarInstanceUsage.DESCRIPTION));
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFile.JavaTestFile.create;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DirectDateInstantiationTest {
|
||||
private final String stubDate = " \n" +
|
||||
"package java.util; \n" +
|
||||
" \n" +
|
||||
"public class Date { \n" +
|
||||
" \n" +
|
||||
" public Date() { \n" +
|
||||
" \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
private final String javaFileToBeTested = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.Date; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" Date d = new Date(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
|
||||
@Test
|
||||
public void showsErrorsForInvalidUsage() {
|
||||
lint().
|
||||
allowMissingSdk().
|
||||
allowCompilationErrors()
|
||||
.files(create(stubDate), create(javaFileToBeTested))
|
||||
.issues(DirectDateInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectDateInstantiation.ID));
|
||||
assertTrue(output.contains(DirectDateInstantiation.DESCRIPTION));
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFile.JavaTestFile.create;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DirectGregorianInstantiationTest {
|
||||
|
||||
private final String stubZoned = " \n" +
|
||||
"package java.time; \n" +
|
||||
" \n" +
|
||||
"public class ZonedDateTime { \n" +
|
||||
" \n" +
|
||||
" \n" +
|
||||
" public ZonedDateTime() { \n" +
|
||||
" \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String stubGregorian = " \n" +
|
||||
"package java.util; \n" +
|
||||
" \n" +
|
||||
"import java.time.ZonedDateTime; \n" +
|
||||
" \n" +
|
||||
"public class GregorianCalendar { \n" +
|
||||
" \n" +
|
||||
" public GregorianCalendar() { \n" +
|
||||
" } \n" +
|
||||
" \n" +
|
||||
" \n" +
|
||||
" public static GregorianCalendar from(ZonedDateTime z) { \n" +
|
||||
" return null; \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
private final String javaFileWithFromCall = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.GregorianCalendar; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" GregorianCalendar gc = GregorianCalendar.from(null); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String javaFileWithConstructorInvocation = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.GregorianCalendar; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" GregorianCalendar gc = new GregorianCalendar(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String javaFileWithTime = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.GregorianCalendar; \n" +
|
||||
" \n" +
|
||||
"public class Time { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" GregorianCalendar gc = new GregorianCalendar(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String javaFileWithSystemTime = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.util.GregorianCalendar; \n" +
|
||||
" \n" +
|
||||
"public class SystemTime { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" GregorianCalendar gc = new GregorianCalendar(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
|
||||
@Test
|
||||
public void showsErrorForInvalidUsage() {
|
||||
lint().
|
||||
allowMissingSdk().
|
||||
allowCompilationErrors()
|
||||
.files(create(stubZoned), create(stubGregorian), create(javaFileWithFromCall))
|
||||
.issues(DirectGregorianInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectGregorianInstantiation.ID));
|
||||
assertTrue(output.contains(DirectGregorianInstantiation.DESCRIPTION));
|
||||
});
|
||||
|
||||
lint().
|
||||
allowMissingSdk().
|
||||
allowCompilationErrors()
|
||||
.files(create(stubZoned), create(stubGregorian), create(javaFileWithConstructorInvocation))
|
||||
.issues(DirectGregorianInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectGregorianInstantiation.ID));
|
||||
assertTrue(output.contains(DirectGregorianInstantiation.DESCRIPTION));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesNotShowErrorsWhenUsedInTime() {
|
||||
lint().
|
||||
allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubGregorian), create(javaFileWithTime))
|
||||
.issues(DirectSystemTimeInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectClean();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesNotShowErrorsWhenUsedInSystemTime() {
|
||||
lint().
|
||||
allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubGregorian), create(javaFileWithSystemTime))
|
||||
.issues(DirectSystemTimeInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectClean();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFile.JavaTestFile.create;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DirectSystemCurrentTimeMillisUsageTest {
|
||||
|
||||
private final String stubSystem = " \n" +
|
||||
"package java.lang; \n" +
|
||||
" \n" +
|
||||
"public class System { \n" +
|
||||
" \n" +
|
||||
" public static long currentTimeMillis() { \n" +
|
||||
" return 1L; \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
private final String javaFileToBeTested = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import java.lang.System; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" long time = System.currentTimeMillis(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
|
||||
@Test
|
||||
public void showsErrorsForInvalidUsage() {
|
||||
lint().
|
||||
allowMissingSdk().
|
||||
allowCompilationErrors()
|
||||
.files(create(stubSystem), create(javaFileToBeTested))
|
||||
.issues(DirectSystemCurrentTimeMillisUsage.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectSystemCurrentTimeMillisUsage.ID));
|
||||
assertTrue(output.contains(DirectSystemCurrentTimeMillisUsage.DESCRIPTION));
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.ichi2.anki.lint.rules;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.android.tools.lint.checks.infrastructure.TestFile.JavaTestFile.create;
|
||||
import static com.android.tools.lint.checks.infrastructure.TestLintTask.lint;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DirectSystemTimeInstantiationTest {
|
||||
private final String stubTime = " \n" +
|
||||
"package com.ichi2.libanki.utils; \n" +
|
||||
" \n" +
|
||||
"public abstract class Time { \n" +
|
||||
" \n" +
|
||||
"} \n";
|
||||
private final String stubSystemTime = " \n" +
|
||||
"package com.ichi2.libanki.utils; \n" +
|
||||
" \n" +
|
||||
"public class SystemTime extends Time { \n" +
|
||||
" \n" +
|
||||
" public SystemTime() { \n" +
|
||||
" } \n" +
|
||||
" \n" +
|
||||
"} \n";
|
||||
private final String javaFileToBeTested = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import com.ichi2.libanki.utils.SystemTime; \n" +
|
||||
" \n" +
|
||||
"public class TestJavaClass { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" SystemTime st = new SystemTime(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String javaFileWithStorage = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import com.ichi2.libanki.utils.SystemTime; \n" +
|
||||
" \n" +
|
||||
"public class Storage { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" SystemTime st = new SystemTime(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
private final String javaFileWithCollectionHelper = " \n" +
|
||||
"package com.ichi2.anki.lint.rules; \n" +
|
||||
" \n" +
|
||||
"import com.ichi2.libanki.utils.SystemTime; \n" +
|
||||
" \n" +
|
||||
"public class CollectionHelper { \n" +
|
||||
" \n" +
|
||||
" public static void main(String[] args) { \n" +
|
||||
" SystemTime st = new SystemTime(); \n" +
|
||||
" } \n" +
|
||||
"} \n";
|
||||
|
||||
|
||||
@Test
|
||||
public void showsErrorsForInvalidUsage() {
|
||||
lint()
|
||||
.allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubTime), create(stubSystemTime), create(javaFileToBeTested))
|
||||
.issues(DirectSystemTimeInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectErrorCount(1)
|
||||
.check(output -> {
|
||||
assertTrue(output.contains(DirectSystemTimeInstantiation.ID));
|
||||
assertTrue(output.contains(DirectSystemTimeInstantiation.DESCRIPTION));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesNotShowErrorsWhenUsedInStorage() {
|
||||
lint().
|
||||
allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubTime), create(stubSystemTime), create(javaFileWithStorage))
|
||||
.issues(DirectSystemTimeInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectClean();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void doesNotShowErrorsWhenUsedInCollectionHelper() {
|
||||
lint().
|
||||
allowMissingSdk()
|
||||
.allowCompilationErrors()
|
||||
.files(create(stubTime), create(stubSystemTime), create(javaFileWithCollectionHelper))
|
||||
.issues(DirectSystemTimeInstantiation.ISSUE)
|
||||
.run()
|
||||
.expectClean();
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
include ':lint-rules'
|
||||
include ':api'
|
||||
include ':AnkiDroid'
|
||||
|
Loading…
Reference in New Issue
Block a user