0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-19 19:42:17 +02:00

Add lint check: Use of JetBrains annotations

We have standardised on androidx annotations, this helps new users and suggests
an IDE option to change to the correct library.

This does appear in the IDE, so we can define it as an error, rather than a warning.
This commit is contained in:
David Allison 2020-09-04 00:01:34 +01:00 committed by Mike Hardy
parent 49a343230f
commit da5968ec39
4 changed files with 213 additions and 0 deletions

View File

@ -7,6 +7,7 @@ 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 com.ichi2.anki.lint.rules.InconsistentAnnotationUsage;
import org.jetbrains.annotations.NotNull;
@ -23,6 +24,7 @@ public class IssueRegistry extends com.android.tools.lint.client.api.IssueRegist
issues.add(DirectDateInstantiation.ISSUE);
issues.add(DirectGregorianInstantiation.ISSUE);
issues.add(DirectSystemTimeInstantiation.ISSUE);
issues.add(InconsistentAnnotationUsage.ISSUE);
return issues;
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 David Allison <davidallisongithub@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki.lint.rules;
import com.android.annotations.NonNull;
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.SourceCodeScanner;
import com.google.common.annotations.VisibleForTesting;
import com.ichi2.anki.lint.utils.Constants;
import com.ichi2.anki.lint.utils.ImportStatementDetector;
import org.jetbrains.uast.UElement;
import org.jetbrains.uast.UImportStatement;
public class InconsistentAnnotationUsage extends ImportStatementDetector implements SourceCodeScanner {
@VisibleForTesting
static final String ID = "InconsistentAnnotationUsage";
@VisibleForTesting
static final String DESCRIPTION = "Use androidx.annotation.NonNull and androidx.annotation.Nullable. See explanation for IDE-level fix";
private static final String EXPLANATION = "AnkiDroid uses androidx nullability annotations over JetBrains for nullability. " +
"The annotations library can be specified in Settings - Inspections - @NotNull/@Nullable problems";
private static Implementation implementation = new Implementation(InconsistentAnnotationUsage.class, Scope.JAVA_FILE_SCOPE);
public static final Issue ISSUE = Issue.create(
ID,
DESCRIPTION,
EXPLANATION,
Constants.ANKI_TIME_CATEGORY,
Constants.ANKI_TIME_PRIORITY,
Constants.ANKI_TIME_SEVERITY,
implementation
);
public InconsistentAnnotationUsage() {
}
@Override
public void visitImportStatement(@NonNull JavaContext context, @NonNull UImportStatement node) {
UElement importReference = node.getImportReference();
if (importReference != null && isJetbrains(importReference.asRenderString())) {
context.report(
ISSUE,
node,
context.getLocation(node),
DESCRIPTION
);
}
}
private boolean isJetbrains(String importReference) {
return importReference.equals("org.jetbrains.annotations.NotNull") || importReference.equals("org.jetbrains.annotations.Nullable");
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 David Allison <davidallisongithub@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki.lint.utils;
import com.android.tools.lint.client.api.UElementHandler;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.JavaContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.uast.UElement;
import org.jetbrains.uast.UImportStatement;
import java.util.Collections;
import java.util.List;
public abstract class ImportStatementDetector extends Detector {
public abstract void visitImportStatement(@NotNull JavaContext context, @NotNull UImportStatement node);
@Nullable
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.singletonList(UImportStatement.class);
}
@Nullable
@Override
public UElementHandler createUastHandler(@NotNull JavaContext context) {
return new UElementHandler() {
@Override
public void visitImportStatement(@NotNull UImportStatement node) {
// do not call super
ImportStatementDetector.this.visitImportStatement(context, node);
}
};
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2020 David Allison <davidallisongithub@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
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 InconsistentAnnotationUsageTest {
private final String mNotNullUsage = " \n" +
"package java.util; \n" +
" \n" +
"import org.jetbrains.annotations.NotNull; \n";
private final String mNullable = " \n" +
"package java.util; \n" +
" \n" +
"import org.jetbrains.annotations.Nullable; \n";
// Should be OK
private final String mContract = " \n" +
"package java.util; \n" +
" \n" +
"import org.jetbrains.annotations.Contract; \n";
@Test
public void showsErrorForNotNull() {
lint()
.allowMissingSdk()
.allowCompilationErrors()
.files(create(mNotNullUsage))
.issues(InconsistentAnnotationUsage.ISSUE)
.run()
.expectErrorCount(1)
.check(output -> {
assertTrue(output.contains(InconsistentAnnotationUsage.ID));
assertTrue(output.contains(InconsistentAnnotationUsage.DESCRIPTION));
});
}
@Test
public void showsErrorForNullable() {
lint()
.allowMissingSdk()
.allowCompilationErrors()
.files(create(mNullable))
.issues(InconsistentAnnotationUsage.ISSUE)
.run()
.expectErrorCount(1)
.check(output -> {
assertTrue(output.contains(InconsistentAnnotationUsage.ID));
assertTrue(output.contains(InconsistentAnnotationUsage.DESCRIPTION));
});
}
@Test
public void noErrorForContract() {
lint()
.allowMissingSdk()
.allowCompilationErrors()
.files(create(mContract))
.issues(InconsistentAnnotationUsage.ISSUE)
.run()
.expectErrorCount(0);
}
}