构造函数中注入次数的 lint 规则
Lint rule for number of injections in a constructor
我正在尝试在我的 Android 代码中创建一个 Lint 规则来检查构造函数中注入的次数,因此如果我超过某个视图模型的特定次数,例如,我将提高棉绒警告。
我知道我必须在我的 Lint 检测器中实施 UastScanner,但我迷路了,因为我找不到好的文档。有没有其他人做过这样的事情?或者我在哪里可以找到关于它的良好说明?
谢谢!
所以我能够找到使用 JavaScanner 的解决方案,但我还没有找到任何使用 UastScanner 的解决方案(这是我想使用的,因为我们也有 Kotlin 类):
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.JavaScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
@Override
public boolean appliesTo(Context context, File file) {
return true;
}
@Override
public Speed getSpeed(Issue issue) {
return Speed.FAST;
}
@Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
return Collections.<Class<? extends Node>>singletonList(ConstructorDeclaration.class);
}
@Override
public AstVisitor createJavaVisitor(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends ForwardingAstVisitor {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
@Override
public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.astParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, node, javaContext.getLocation(node), "My message goes here");
return true;
}
return false;
}
}
}
* 注意 - 阅读完整答案以获取已编辑的解决方案。 *
我能够像这样编写 UAST 转换:
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.UastScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.<Class<? extends UElement>>singletonList(UClass.class);
}
@Override
public UElementHandler createUastHandler(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends UElementHandler {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
@Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getParameterList().getParametersCount() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, method, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
}
}
然而,这似乎仍然没有提取 Kotlin 源文件...非常混乱。
编辑:12/19/17 - 修复
问题有两个方面:
1) 确实存在 Psi 方法的隐藏用法,该方法阻止了检查工作。 visitClass 方法不应使用 getParameterList(),而应使用 getUastParameters()。将上面的 visitclass 替换为:
@Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getUastParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, clazz, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
2) 在 lint-dev 组直接与 Tor Norbye 交谈后,他指出 Android Studio 3.0 事实上 lint 不能在外部与 kotlin 一起工作,因此预计不会像这里描述的那样工作.升级到 Android Studio 3.1 Canary 和 运行 linter 生成了预期的报告。
我正在尝试在我的 Android 代码中创建一个 Lint 规则来检查构造函数中注入的次数,因此如果我超过某个视图模型的特定次数,例如,我将提高棉绒警告。
我知道我必须在我的 Lint 检测器中实施 UastScanner,但我迷路了,因为我找不到好的文档。有没有其他人做过这样的事情?或者我在哪里可以找到关于它的良好说明?
谢谢!
所以我能够找到使用 JavaScanner 的解决方案,但我还没有找到任何使用 UastScanner 的解决方案(这是我想使用的,因为我们也有 Kotlin 类):
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.JavaScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
@Override
public boolean appliesTo(Context context, File file) {
return true;
}
@Override
public Speed getSpeed(Issue issue) {
return Speed.FAST;
}
@Override
public List<Class<? extends Node>> getApplicableNodeTypes() {
return Collections.<Class<? extends Node>>singletonList(ConstructorDeclaration.class);
}
@Override
public AstVisitor createJavaVisitor(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends ForwardingAstVisitor {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
@Override
public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.astParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, node, javaContext.getLocation(node), "My message goes here");
return true;
}
return false;
}
}
}
* 注意 - 阅读完整答案以获取已编辑的解决方案。 *
我能够像这样编写 UAST 转换:
public class NumberOfDependenciesInjectedDetector extends Detector implements Detector.UastScanner {
private static final int NUMBER_OF_INJECTIONS_ALLOWED = 5;
private static final Class<? extends Detector> DETECTOR = NumberOfDependenciesInjectedDetector.class;
private static final EnumSet<Scope> SCOPE = Scope.JAVA_FILE_SCOPE;
private static final Implementation IMPLEMENTATION = new Implementation(DETECTOR, SCOPE);
public static final Issue ISSUE = Issue.create(
"NumberOfDependenciesInjected",
"Limit number of injections in a class via constructor",
"A longer description here",
Category.CORRECTNESS,
10,
Severity.ERROR,
IMPLEMENTATION
);
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.<Class<? extends UElement>>singletonList(UClass.class);
}
@Override
public UElementHandler createUastHandler(JavaContext context) {
return new ConstructorVisitor(context);
}
private static class ConstructorVisitor extends UElementHandler {
private JavaContext javaContext;
private ConstructorVisitor(JavaContext javaContext) {
this.javaContext = javaContext;
}
@Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getParameterList().getParametersCount() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, method, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
}
}
然而,这似乎仍然没有提取 Kotlin 源文件...非常混乱。
编辑:12/19/17 - 修复
问题有两个方面:
1) 确实存在 Psi 方法的隐藏用法,该方法阻止了检查工作。 visitClass 方法不应使用 getParameterList(),而应使用 getUastParameters()。将上面的 visitclass 替换为:
@Override
public void visitClass(UClass clazz){
UMethod[] methods = clazz.getMethods();
for(UMethod method : methods){
if(!method.isConstructor()) continue;
if (method.getUastParameters().size() > NUMBER_OF_INJECTIONS_ALLOWED) {
javaContext.report(ISSUE, clazz, javaContext.getLocation(method), "Injections exceed allowed value of " + NUMBER_OF_INJECTIONS_ALLOWED);
}
}
}
2) 在 lint-dev 组直接与 Tor Norbye 交谈后,他指出 Android Studio 3.0 事实上 lint 不能在外部与 kotlin 一起工作,因此预计不会像这里描述的那样工作.升级到 Android Studio 3.1 Canary 和 运行 linter 生成了预期的报告。