2016-12-19 10 views
11

Piszę niestandardowy detektor kłaczków dla zabawy. Wyjeżdżam z lekcji Ranniki z Dużym Nerdem na temat tworzenia custom lint rule in Android (powinno być takie samo dla Javy)Własne błędy dla Javy/Androida Zgłoś, jeśli znajdziemy połączenie klasy bez implementowania interfejsu

Potrafię wykryć wystąpienie, które chcę. Że został wywołany konstruktor klasy. Jednak ze względu na fakt, że przechodzimy przez Abstract Syntax Tree , nie mogę wykryć implementacji wywołania zwrotnego. Nie jestem pewien, jak powiedzieć Java, aby sprawdzić plik i tylko zgłosić, jeśli nie może znaleźć wystąpienie. W tym przypadku implementacja interfejsu. Ponieważ widzę tylko jeden liść na raz.

Jak mogę wyszukać dwa wystąpienia, zapisać lokalizacje dla każdego wystąpienia, a następnie wykonać moją logikę i odpowiednio zgłosić?

package com.bignerdranch.linette.detectors; 

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

import java.io.File; 
import java.util.EnumSet; 
import java.util.List; 

import lombok.ast.AstVisitor; 
import lombok.ast.Node; 

/** 
* Lint check for the usage of to-do statements 
*/ 
public class CallBackDetector extends Detector implements Detector.JavaScanner { 

    private static final String FRAGMENT_MATCHER_STRING = "NoInternetDialogFragment()"; 
    private static final String INTERFACE_MATCHER_STRING = 
      "NoInternetDialogFragment.NoInternetCallbackInterface"; 

    private static final Class<? extends Detector> DETECTOR_CLASS = CallBackDetector.class; 
    private static final EnumSet<Scope> DETECTOR_SCOPE = Scope.JAVA_FILE_SCOPE; 

    private static final Implementation IMPLEMENTATION = new Implementation(
      DETECTOR_CLASS, 
      DETECTOR_SCOPE 
    ); 

    private static final String ISSUE_ID = "NoInternetDialogFragment"; 
    private static final String ISSUE_DESCRIPTION = 
      "NoInternetDialogFragment Callback not detected"; 
    private static final String ISSUE_EXPLANATION = 
      "When using NoInternetDialogFragment you must implement its' callback -- " 
        + "NoInternetCallbackInterface"; 
    private static final Category ISSUE_CATEGORY = Category.CORRECTNESS; 
    private static final int ISSUE_PRIORITY = 10; 
    private static final Severity ISSUE_SEVERITY = Severity.ERROR; 

    public static final Issue ISSUE = Issue.create(
      ISSUE_ID, 
      ISSUE_DESCRIPTION, 
      ISSUE_EXPLANATION, 
      ISSUE_CATEGORY, 
      ISSUE_PRIORITY, 
      ISSUE_SEVERITY, 
      IMPLEMENTATION 
    ); 

    /** 
    * Constructs a new {@link CallBackDetector} check 
    */ 
    public CallBackDetector() { 
    } 

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

    @Override 
    public List<Class<? extends Node>> getApplicableNodeTypes() { 
     return null; 
    } 

    @Override 
    public AstVisitor createJavaVisitor(@NonNull JavaContext context) { 
     String source = context.getContents(); 

     // Check validity of source 
     if (source == null) { 
      return null; 
     } 

     if(source.indexOf(INTERFACE_MATCHER_STRING) >=0){ 
      return null; 
     } 
     int index = source.indexOf(FRAGMENT_MATCHER_STRING); 

     for (int i = index; i >= 0; i = source.indexOf(FRAGMENT_MATCHER_STRING, i + 1)) { 
      Location location = Location.create(context.file, source, i, 
        i + FRAGMENT_MATCHER_STRING.length()); 
      context.report(ISSUE, location, ISSUE.getBriefDescription(TextFormat.TEXT)); 
     } 
     return null; 
    } 

} 
+0

co, jeśli konstruktor klasy zostanie zawinięty w jakąś metodę fabryczną? –

Odpowiedz

1

Jest to możliwe, jeśli przechowywać odnośniki, które można znaleźć w polu i zgłosić je na końcu wszystkich przechodzenie składni:

Wewnątrz createJavaVisitor zrobić sprawdzanie jak masz teraz do użycia konstruktora . Zamiast zgłaszać problem w tym momencie, utwórz pole kolekcji w swoim CallBackDetector, które będzie zawierało odniesienie do użycia konstruktora. Następnie otrzymasz listę wszystkich zastosowań konstruktora.

Teraz również wewnątrz createJavaVisitor wykonaj sprawdzenie dla dowolnej klasy implementującej interfejs, którego szukasz, i dodaj to do innego zbioru pól.

Można zastąpić metodę afterCheckProject (api here) w swoim Detector, aby wiedzieć, kiedy jest zakończona. W tej metodzie wykonaj iteracje w dwóch kolekcjach i usuń wszystkie elementy z obu kolekcji, które pasują do siebie (konstruktor i implementowany interfejs). Wszystkie, które pozostały w kolekcji, są błędami Lint i możesz je dodać jako problemy w tym momencie.

Powiązane problemy