2016-10-19 22 views
5

Tôi đã viết các chú thích sau đây:Viết cảnh báo lint tùy chỉnh để kiểm tra tùy chỉnh chú thích

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.SOURCE) 
@Target({ElementType.METHOD}) 
public @interface Warning { 

} 

Đó là dự định để chú thích các phương pháp mà có thể gây ra vấn đề nếu gọi là cẩu thả. Tôi đã thêm một bộ xử lý chú thích vào dự án của mình, nhưng điều này chỉ cung cấp cảnh báo trong đầu ra bản ghi của lệnh javac. Tôi muốn cảnh báo này xuất hiện trong Android Studio cùng với các cảnh báo lint khác ở bất kỳ đâu mà phương thức có chú thích này được gọi. Đây là lý do tại sao tôi đang cố gắng viết một quy tắc lint tùy chỉnh. Tôi có bộ xương cơ bản của quy tắc lint:

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.Scope; 
import com.android.tools.lint.detector.api.Severity; 

public class CaimitoDetector extends Detector implements Detector.JavaScanner { 

    public static final Issue ISSUE = Issue.create(
     "WarningAnnotation", 
     "This method has been annotated with @Warning", 
     "This method has special conditions surrounding it's use, be careful when using it and refer to its documentation.", 
     Category.USABILITY, 7, Severity.WARNING, 
     new Implementation(CaimitoDetector.class, Scope.JAVA_FILE_SCOPE)); 

    @Override 
    public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { 

    } 

} 

import com.android.tools.lint.client.api.IssueRegistry; 
import com.android.tools.lint.detector.api.Issue; 

import java.util.Collections; 
import java.util.List; 

public class CaimitoIssueRegistry extends IssueRegistry { 

    @Override 
    public List<Issue> getIssues() { 
    return Collections.singletonList(CaimitoDetector.ISSUE); 
    } 

} 

Nhưng tôi không biết làm thế nào để tiếp tục từ đây. Làm thế nào tôi có thể kiểm tra xem một annoation có tồn tại trên một phương thức hay không và tăng một cảnh báo sao cho nó sẽ được hiển thị trong Android Studio?

CẬP NHẬT

Dưới đây là lớp Detector của tôi cho bất cứ ai tìm cách để làm điều tương tự:

import com.android.annotations.NonNull; 
import com.android.tools.lint.client.api.JavaParser.ResolvedAnnotation; 
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod; 
import com.android.tools.lint.client.api.JavaParser.ResolvedNode; 
import com.android.tools.lint.detector.api.Category; 
import com.android.tools.lint.detector.api.Context; 
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.Speed; 

import java.io.File; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import lombok.ast.AstVisitor; 
import lombok.ast.ConstructorInvocation; 
import lombok.ast.ForwardingAstVisitor; 
import lombok.ast.MethodInvocation; 
import lombok.ast.Node; 

public class CaimitoAnnotationDetector extends Detector implements Detector.JavaScanner { 

    private static final String WARNING_ANNOTATION = "com.treemetrics.caimito.annotations.Warning"; 

    public static final Issue ISSUE = Issue.create(
     "Waqrning.", 
     "Be careful when using this method.", 
     "This method has special conditions surrounding it's use," + 
      " be careful when calling it and refer to its documentation.", 
     Category.USABILITY, 
     7, 
     Severity.WARNING, 
     new Implementation(
      CaimitoAnnotationDetector.class, 
      Scope.JAVA_FILE_SCOPE)); 

    @Override 
    public boolean appliesTo(@NonNull Context context, @NonNull File file) { 
    return true; 
    } 

    @NonNull 
    @Override 
    public Speed getSpeed() { 
    return Speed.FAST; 
    } 

    private static void checkMethodAnnotation(@NonNull JavaContext context, 
              @NonNull ResolvedMethod method, 
              @NonNull Node node, 
              @NonNull ResolvedAnnotation annotation) { 
    String signature = annotation.getSignature(); 
    if(WARNING_ANNOTATION.equals(signature) || signature.endsWith(".Warning")) { 
     checkWarning(context, node, annotation); 
    } 
    } 

    private static void checkWarning(@NonNull JavaContext context, 
             @NonNull Node node, 
             @NonNull ResolvedAnnotation annotation) { 
    context.report(ISSUE, node, context.getLocation(node), "Warning"); 
    } 

    // ---- Implements JavaScanner ---- 

    @Override 
    public List<Class<? extends Node>> getApplicableNodeTypes() { 
    return Arrays.asList(
     MethodInvocation.class, 
     ConstructorInvocation.class); 
    } 

    @Override 
    public AstVisitor createJavaVisitor(@NonNull JavaContext context) { 
    return new CallChecker(context); 
    } 

    private static class CallChecker extends ForwardingAstVisitor { 

    private final JavaContext mContext; 

    public CallChecker(JavaContext context) { 
     mContext = context; 
    } 

    @Override 
    public boolean visitMethodInvocation(@NonNull MethodInvocation call) { 
     ResolvedNode resolved = mContext.resolve(call); 
     if(resolved instanceof ResolvedMethod) { 
     ResolvedMethod method = (ResolvedMethod) resolved; 
     checkCall(call, method); 
     } 

     return false; 
    } 

    @Override 
    public boolean visitConstructorInvocation(@NonNull ConstructorInvocation call) { 
     ResolvedNode resolved = mContext.resolve(call); 
     if(resolved instanceof ResolvedMethod) { 
     ResolvedMethod method = (ResolvedMethod) resolved; 
     checkCall(call, method); 
     } 

     return false; 
    } 

    private void checkCall(@NonNull Node call, ResolvedMethod method) { 
     Iterable<ResolvedAnnotation> annotations = method.getAnnotations(); 
     annotations = filterRelevantAnnotations(annotations); 
     for(ResolvedAnnotation annotation : annotations) { 
     checkMethodAnnotation(mContext, method, call, annotation); 
     } 
    } 

    private Iterable<ResolvedAnnotation> filterRelevantAnnotations(Iterable<ResolvedAnnotation> resolvedAnnotationsIn) { 
     List<ResolvedAnnotation> resolvedAnnotationsOut = new ArrayList<>(); 
     for(ResolvedAnnotation resolvedAnnotation : resolvedAnnotationsIn) { 
     if(resolvedAnnotation.matches(WARNING_ANNOTATION)) { 
      resolvedAnnotationsOut.add(resolvedAnnotation); 
     } 
     } 

     return resolvedAnnotationsOut; 
    } 

    } 

} 

UPDATE 2

Bạn có thể tích hợp kiểm tra lint tùy chỉnh của bạn với Android Studio kiểm tra bằng cách tạo tệp lint.xml trong thư mục gốc của dự án của bạn và thêm quy tắc lint tùy chỉnh của bạn ở đó như sau:

<?xml version="1.0" encoding="UTF-8"?> 
<lint> 
    <issue id="Warning" severity="warning"/> 
</lint> 

Lưu ý id của thẻ phát hành là id được cung cấp tại đối số đầu tiên của phương thức Issue.create() trong lớp CaimitoDetector. Bạn cũng sẽ phải sao chép tệp jar được xuất ra bằng cách xây dựng quy tắc lint của bạn vào thư mục /home/{user}/.android/lint của bạn để làm cho nó hoạt động. Tôi đã viết một nhiệm vụ gradle tùy chỉnh cho việc này. Dưới đây là tập tin build.gradle quy tắc lint của tôi

apply plugin: 'java' 

targetCompatibility = '1.7' 
sourceCompatibility = '1.7' 

repositories { 
    jcenter() 
} 

dependencies { 
    compile 'com.android.tools.lint:lint-api:24.2.1' 
    compile 'com.android.tools.lint:lint-checks:24.2.1' 
} 

jar { 
    manifest { 
     attributes 'Manifest-Version': 1.0 
     attributes 'Lint-Registry': 'com.treemetrics.caimito.lint.CaimitoIssueRegistry' 
    } 
} 

defaultTasks 'assemble' 

task copyLintJar(type: Copy) { 
    description = 'Copies the caimito-lint jar file into the {user.home}/.android/lint folder.' 
    from('build/libs/') 
    into(System.getProperty("user.home") + '/.android/lint') 
    include("*.jar") 
} 

// Runs the copyLintJar task after build has completed. 
build.finalizedBy(copyLintJar) 

CẬP NHẬT 3

Bạn cũng có thể thêm dự án Java lint của bạn như là một sự phụ thuộc vào các dự án khác để có được những tác dụng tương tự như cập nhật 2.

enter image description here

CẬP NHẬT 4

Tôi đã viết một bài đăng blog về chủ đề này https://medium.com/@mosesJay/writing-custom-lint-rules-and-integrating-them-with-android-studio-inspections-or-carefulnow-c54d72f00d30#.3hm576b4f.

Trả lời

2

Nhưng tôi không biết làm thế nào để tiếp tục từ đây

tôi đề nghị viết một bài kiểm tra cho bạn Detector đầu tiên. Đây là một dự án ví dụ minh họa cách viết các bài kiểm tra Detector [1]. Bằng cách đó, bạn có thể thử và điều chỉnh Detector tùy thích.

Làm thế nào tôi có thể kiểm tra xem một annoation tồn tại trên một phương pháp

Tôi đề nghị để có một cái nhìn tại dò mặc định Android [2]. Có thể bạn sẽ tìm thấy một điểm tốt để bắt đầu. Ví dụ. số AnnotationDetector.

và tăng cảnh báo sao cho nó sẽ hiển thị trong Android Studio?

Nếu bạn tích hợp các quy tắc tùy chỉnh chính xác vào dự án của mình, thì Lint sẽ tăng cảnh báo cho bạn. Vui lòng xem tại đây [3] để biết các tùy chọn khác nhau về cách tích hợp các quy tắc tùy chỉnh trong dự án của bạn. Lưu ý: Cảnh báo AFAIK về quy tắc tùy chỉnh sẽ chỉ được báo cáo khi chạy tác vụ Gradle tương ứng. "Tự động đánh dấu" của Android Studio không hoạt động với các quy tắc tùy chỉnh.

  1. https://github.com/a11n/CustomLintRules
  2. https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks
  3. https://github.com/a11n/android-lint/tree/master/6_application
+0

Liệu các thư viện lombok.ast có bất kỳ tài liệu tôi có thể tham khảo để hiểu rõ hơn về những gì đang xảy ra trong mã nguồn của liên kết thứ hai? – Moses

+0

Tôi đã tìm thấy https://jar-download.com/java-documentation-javadoc.php?a=lombok-ast&g=com.android.tools.external.lombok&v=0.2.3 này, nhưng chúng hầu như trống, không nhiều thông tin. – Moses

+0

Tôi e rằng đây là tất cả những gì bạn sẽ nhận được. Có nhiều trình phát hiện Android sử dụng lombok và tìm kiếm các chú thích (ví dụ: CallSuperDetector). Tôi biết điều này không phức tạp, nhưng lấy các giải pháp hiện có, hiểu cách họ làm việc và thích ứng với cách tiếp cận của họ là tất cả những gì chúng tôi có. Nếu bạn tìm hiểu thêm, vui lòng cho tôi biết :-) – a11n

Các vấn đề liên quan