2016-10-19 7 views
5

Pisałem dopiskiem:Pisanie zwyczaj ostrzegania szarpie, aby sprawdzić niestandardowego adnotacji

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 { 

} 

który jest przeznaczony do opisywania metod, które mogą powodować problemy, jeśli nazywa się niedbale. Dodałem procesor adnotacji do mojego projektu, ale dostarcza to tylko ostrzeżenia w wynikach logu polecenia javac. Chcę, aby to ostrzeżenie pojawiło się w Android Studio wraz z innymi ostrzeżeniami lint wszędzie tam, gdzie wywoływana jest metoda z tą adnotacją. Właśnie dlatego próbuję napisać niestandardową regułę lint. Mam podstawowy szkielet reguły niestrzępiącą:

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); 
    } 

} 

Ale nie wiem, jak postępować stąd. Jak mogę sprawdzić, czy istnieje irytacja metody i podnieść ostrzeżenie, które będzie widoczne w Android Studio?

UPDATE

Tu jest moja klasa detektora dla każdego, kto chce zrobić to samo:

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

można zintegrować swój własny niestrzępiącą sprawdzanie kontroli Android Studio tworząc plik lint.xml w katalogu głównym projektu i dodając niestandardową regułę Lint tam:

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

Zauważ, że id znacznika wydania to identyfikator podany przy pierwszym argumencie metody Issue.create() w klasie CaimitoDetector. Będziesz musiał również skopiować plik jar wyprowadzany przez utworzenie reguły linta do folderu /home/{user}/.android/lint, aby działał. Napisałem do tego niestandardowe zadanie stopniowania. Oto plik build.gradle mojego Lint reguła jest

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) 

UPDATE 3

Można również dodać swój projekt niestrzępiącą Java jako zależność od innych projektów, aby uzyskać taki sam efekt jak zmiana 2.

enter image description here

UPDATE 4

Od tego czasu napisałem post na blogu na ten temat: https://medium.com/@mosesJay/writing-custom-lint-rules-and-integrating-them-with-android-studio-inspections-or-carefulnow-c54d72f00d30#.3hm576b4f.

Odpowiedz

2

Ale nie wiem, jak postępować stąd

Proponuję napisać pomiarowe dla Detector pierwszy. Oto przykładowy projekt, który pokazuje, jak pisać testy [1]. W ten sposób możesz spróbować dostosować swój model Detector, tak jak chcesz.

Jak mogę sprawdzić, jeśli annoation istnieje na metodzie

Proponuję spojrzeć na czujek domyślnych Android [2]. Tam prawdopodobnie znajdziesz dobry punkt wyjścia. Na przykład. AnnotationDetector.

i podnieść ostrzeżenie, które będzie widoczne w Android Studio?

Jeśli poprawnie włączysz własne reguły do ​​projektu, Lint podniesie dla Ciebie ostrzeżenie. Zajrzyj tutaj [3], aby poznać różne opcje integracji reguł niestandardowych w projekcie. Uwaga: Ostrzeżenia AFAIK dotyczące reguł niestandardowych będą zgłaszane tylko podczas uruchamiania odpowiedniego zadania Gradle. "Automatyczne wyróżnianie" w Android Studio nie działa z regułami niestandardowymi.

  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

Czy lombok.ast biblioteka posiada żadnej dokumentacji mogę odnieść się w celu lepszego zrozumienia tego, co dzieje się w kodzie źródłowym drugiego linku? – Moses

+0

Znalazłem ten https://jar-download.com/java-documentation-javadoc.php?a=lombok-ast&g=com.android.tools.external.lombok&v=0.2.3, ale w większości są puste, nie dużo informacji. – Moses

+0

Obawiam się, że to wszystko, co dostaniesz. Istnieje więcej detektorów Androida, które wykorzystują lombok i wyszukują adnotacje (np. CallSuperDetector). Wiem, że to nie jest wyrafinowanie, ale przyjęcie istniejących rozwiązań, zrozumienie ich działania i dostosowanie ich podejścia to może wszystko, co mamy. Jeśli dowiesz się więcej, proszę dać mi znać :-) – a11n

Powiązane problemy