Upgrade to Pro — share decks privately, control downloads, hide ads and more …

how to make custom lint at shibuya apk 24

how to make custom lint at shibuya apk 24

android向けのcustom lintの作り方の資料です
shibuya.apk#24

Shinnosuke Kugimiya

April 13, 2018
Tweet

More Decks by Shinnosuke Kugimiya

Other Decks in Programming

Transcript

  1. © DMM.com X w LHNZTIJOఝٶ ͗͘Έ΍  w "OESPJEΤϯδχΞ w

    %..DPNϥϘ$50ࣨॴଐ w ೥݄͔Β ࣗݾ঺հ
  2. © DMM.com X w LPUMJOΛ࢖ͬͨ"OESPJEϓϩδΣΫτͰMJOUΛ͔͚Δ ʹ͸ʁ w $VTUPN-JOUΛ࡞Δʹ͸ʁ w BOESPJEMJOUͰ$VTUPN-JOUΛ࡞ͬͯΈΔ

    w ࡞ͬͨBOESPJEMJOUͷ$VTUPN-JOUΛςετ͢Δ w ࡞ͬͨBOESPJEMJOUͷ$VTUPN-JOUΛ࢖͏ w ·ͱΊ BHFOEB
  3. © DMM.com X LPUMJOΛ࢖ͬͨ"OESPJEϓϩδΣΫτͰMJOUΛ͔͚Δʹ͸ʁ Ҏલ͸ ओʹ ͭͷํ๏͔͠ͳ͔ͬͨ w LUMJOU w

    IUUQTHJUIVCDPNTIZJLPLUMJOU w EFUFLU w IUUQTHJUIVCDPNBSUVSCPTDIEFUFLU
  4. © DMM.com X LPUMJOΛ࢖ͬͨ"OESPJEϓϩδΣΫτͰMJOUΛ͔͚Δʹ͸ʁ ͓ͦΒ͘ BOESPJEHSBMEFQMVHJO͔Β w LUMJOU w IUUQTHJUIVCDPNTIZJLPLUMJOU

    w EFUFLU w IUUQTHJUIVCDPNBSUVSCPTDIEFUFLU w BOESPJEMJOU ศٓͷͨΊɺBOESPJEMJOUͱݺͼ·͢  ‏/FX w IUUQTHJUIVCDPNHPPHMFTBNQMFTBOESPJE DVTUPNMJOUSVMFT αϯϓϧ  
  5. © DMM.com X ॴײ ओ؍ LUMJOU 4UZMFدΓɻEFUFLUͱେ͖ͳࠩ͸ͳ͍ɻ ͨͩɺϧʔϧͷҰ෦ແࢹͱ͔͕Ͱ͖ͳ͍ɻ FEJUPSDPOpHͰҰ෦͸ม͑ΕΔ EFUFLU

    4UZMFدΓɻLUMJOUͱେ͖ͳࠩ͸ͳ͍ɻ BOESPJEMJOU 4UZMF΋ϩδοΫͷ֬ೝͳͲ΋Ͱ͖Δɻ ͨͩ͠ɺEFUFLU΍LUMJOUͰ༻ҙ͍ͯ͠Δ ඪ४ϧʔϧʹ֘౰͢Δ΋ͷ͸ɺ·ͩͳ͍໛༷  "4ͷJOTQFDUJPOʹ͸͋Δ
  6. © DMM.com X ͲΕ࢖͏ʁ ओ؍ ౰෼͸BOESPJEMJOUͱ LUMJOUPSEFUFLU ͷซ༻ w BOESPJEMJOU͸ඪ४ͰೖͬͯΔͷͰ֎͢ͱ͍͏બ୒ࢶ͸ͳ͍

    w LUMJOU΍EFUFLUͰελΠϧͷνΣοΫΛ͢Δ w ࣗ෼͸LUMJOUΛ࢖͍ͬͯΔ w ελΠϧدΓͷ$VTUPN-JOU͸LUMJOUͰ࡞͍ͬͯΔ w LUMJOU͸ݸผʹϧʔϧΛແޮʹͨ͠ΓͰ͖ͳ͍ͷͰɺEFUFLU ͷํ͕͍͍ͷͰ͸ʁͱࢥ͍࢝Ίͯ͸͍Δɻ  w LUMJOU΋EFUFLU΋$VTUPN-JOU͸खܰʹγϡοͱ࡞ΕΔ w BOESPJEMJOUͰ΋͠ࠓޙελΠϧपΓͷϧʔϧ͕ॆ࣮͖ͯͨ͠Βɺ ͦͷ࣌ʹLUMJOU΍EFUFLU͸֎͢͜ͱΛߟ͑Δ
  7. © DMM.com X ·ͣ͸"45 ˺14* Λ஌Δ 'JMF 1"$,"(& %*3&$5*7& $-"44

    FMFNFOU DMBTT 8)*5&@41"$& FMFNFOU
 *%&/5*'*&3 8)*5&@41"$& $-"44@#0%: package yourpackage class Hoge { fun fuga(): Int = 2 + 3 } πϦʔߏ଄Ͱղऍ͞ΕΔ
  8. © DMM.com X ͨͱ͑͹ɺҾ਺ͰA A͕͋ͬͨΒઈରվߦ͢Δ$VTUPN-JOUΛ࡞Δ࣌ 7"-6& "3(6.&/5-*45 7"-6& "3(6.&/5 $0.."

    8)*5&41"$& 7"-6& "3(6.&/5 /(ͷ࣌΋0,ͷ࣌΋ 14*ͷπϦʔ͸͜ͷΑ͏ʹͳΔ Ұ෦୺ંͬͯ·͢    
  9. © DMM.com X ͨͱ͑͹ɺҾ਺ͰA A͕͋ͬͨΒઈରվߦ͢Δ$VTUPN-JOUΛ࡞Δ࣌ $VTUPN-JOUͷϩδοΫ͸ɺԼهΛ֬ೝ͢Δ w Լهͷߏ଄ʹͳ͍ͬͯΔͱ͖ʹ 7"-6& "3(6.&/5-*45

    7"-6& "3(6.&/5 $0.." 8)*5&41"$& 7"-6& "3(6.&/5 w ࡾͭ໨ͷ8)*5&@41"$&ʹվߦίʔυΛؚ·ΕΔ͜ͱ EFUFLUͰ΋LUMJOUͰ΋BOESPJEMJOUͰ΋ͲΕͰ΋ɺ ɹɹɹɹɹɹɹɹɹ$VTUPN-JOU͸͜ͷΑ͏ʹͯ͠࡞͍͖ͬͯ·͢
  10. © DMM.com X खॱ  ϓϩδΣΫτΛ࡞Δ  %FUFDUPSΛ࡞Δ  *TTVFΛ࡞Δ

     3FHJTUSZΛ࡞Δ  3FHJTUSZΛCVJMEHSBEMFʹهड़
  11. © DMM.com X ̎%FUFDUPSΛ࡞Δ public class NotHandledDisposableDetector extends Detector implements

    UastScanner { @Override public List<Class<? extends UElement>> getApplicableUastTypes() { return Collections.singletonList(UQualifiedReferenceExpression.class); } @Override public UElementHandler createUastHandler(JavaContext context) { return new UElementHandler() { @Override public void visitQualifiedReferenceExpression( ɹɹɹɹɹɹɹ UQualifiedReferenceExpression node ɹɹɹɹɹɹɹ) { : ॲཧ } }; } } ׬੒ܗ
  12. © DMM.com X ̎%FUFDUPSΛ࡞Δ public class NotHandledDisposableDetector extends Detector implements

    UastScanner { @Override public List<Class<? extends UElement>> getApplicableUastTypes() { return Collections.singletonList(UQualifiedReferenceExpression.class); } @Override public UElementHandler createUastHandler(JavaContext context) { return new UElementHandler() { @Override public void visitQualifiedReferenceExpression( ɹɹɹɹɹɹɹ UQualifiedReferenceExpression node ɹɹɹɹɹɹɹ) { : ॲཧ } }; } } %FUFDUPSΛFYUFOETɺ6BTU4DBOOFSΛJNQMFNFOUTɻ 6BTU͸6OJpFE"45ͷུɻ
  13. © DMM.com X ̎%FUFDUPSΛ࡞Δ public class NotHandledDisposableDetector extends Detector implements

    UastScanner { @Override public List<Class<? extends UElement>> getApplicableUastTypes() { return Collections.singletonList(UQualifiedReferenceExpression.class); } @Override public UElementHandler createUastHandler(JavaContext context) { return new UElementHandler() { @Override public void visitQualifiedReferenceExpression( ɹɹɹɹɹɹɹ UQualifiedReferenceExpression node ɹɹɹɹɹɹɹ) { : ॲཧ } }; } } DSFBUF6BTU)BOEMFSΛPWFSSJEF͢Δɻ ͭ·Γ6*&MFNFOU)BOEMFSΛ࣮૷͢Δɻ
  14. © DMM.com X ̎%FUFDUPSΛ࡞Δ public class NotHandledDisposableDetector extends Detector implements

    UastScanner { @Override public List<Class<? extends UElement>> getApplicableUastTypes() { return Collections.singletonList(UQualifiedReferenceExpression.class); } @Override public UElementHandler createUastHandler(JavaContext context) { return new UElementHandler() { @Override public void visitQualifiedReferenceExpression( ɹɹɹɹɹɹɹ UQualifiedReferenceExpression node ɹɹɹɹɹɹɹ) { : ॲཧ } }; } } WJTJUର৅ͷOPEFͷΫϥεҰཡΛHFU"QQMJDBCMF6BTU5ZQFTͰ ฦ٫͢Δɻ͜ΕΛ͠ͳ͍ͱWJTJUϝιου͕ݺ͹Ε·ͤΜ
  15. © DMM.com X ̎%FUFDUPSΛ࡞Δ // kotlin if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().toString().equals("BLOCK") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType() .getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); return; } WJTJU2VBMJpFE3FGFSFODF&YQSFTTJPOͷத਎Λઆ໌͠·͢ɻ
  16. © DMM.com X ̎%FUFDUPSΛ࡞Δ // kotlin if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().toString().equals("BLOCK") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType() .getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); return; } ਌͕#MPDLA\^AͰɺ
  17. © DMM.com X ̎%FUFDUPSΛ࡞Δ // kotlin if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().toString().equals("BLOCK") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType() .getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); return; } ϝιουνΣʔϯͷ࠷ޙ͕ATVCTDSJCF AͰ
  18. © DMM.com X ̎%FUFDUPSΛ࡞Δ // kotlin if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().toString().equals("BLOCK") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType() .getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); return; } ͦͷTVCTDJSCFϝιουͷฦΓ஋͕JPSFBDUJWFYEJTQPTBCMFT%JTQPTBCMFͷ࣌ ‐͜Ε͕LUMJOUͱEFUFLUͰ͸ࠓͷॴͰ͖·ͤΜ
  19. © DMM.com X ̎%FUFDUPSΛ࡞Δ // kotlin if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().toString().equals("BLOCK") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType() .getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); return; } Ϩϙʔτ͢Δʂ ܯࠂ͕ग़Δ
  20. © DMM.com X ̎%FUFDUPSΛ࡞Δ // java if (node.getPsi() != null

    && node.getPsi().getContext() != null && node.getPsi().getContext().getContext() != null && node.getPsi().getContext().getContext().toString() .equals(“PsiCodeBlock") && node.getSelector().asRenderString().startsWith("subscribe(") && node.getSelector().getExpressionType() != null && node.getSelector().getExpressionType().getCanonicalText() .equals("io.reactivex.disposables.Disposable")) { context.report( ISSUE, node, context.getLocation(node), "Should handle Disposable” ); } KBWBͷ৔߹΋ॻ͖·͢ɻ6BTU4DBOOFS͸LPUMJOͱKBWBͰ۠ผͳ͘WJTJUͯ͘͠Ε·͢ɻ ͨͩ͠ɺLPUMJOͷ࣌ͱߏ଄͸େମಉ͡Ͱ͕͢ɺ14*ͷܕ͕ҧ͏ͷͰผ్ॻ͘ඞཁ͕͋Γ·͢ɻ
  21. © DMM.com X ̏*TTVFΛ࡞Δ public class NotHandledDisposableDetector extends Detector implements

    UastScanner { public static final Issue ISSUE = Issue.create( "NotHandledDisposable", "Not Handled Disposable", "Disposable should be called dispose.", Category.CORRECTNESS, 6, Severity.ERROR, new Implementation( NotHandledDisposableDetector.class, Scope.JAVA_FILE_SCOPE ) ); *%΍આ໌ɺΧςΰϦ৘ใΛ࣋ͬͨTUBUJDͳ*TTVFΠϯελϯεΛ࡞Γ·͢ɻ ৔ॴ͸Ͳ͜Ͱ΋͍͍͚Ͳɺطଘͷ-JOUΛݟΔݶΓ%FUFDUPSΫϥεʹॻ͍ͯΔͱ͜Ζ͕΄ͱΜͲ Ͱ͢ɻ
  22. © DMM.com X ̐3FHJTUSZΛ࡞Δ public class CustomIssueRegistry extends IssueRegistry {

    @Override public List<Issue> getIssues() { return Collections.singletonList( NotHandledDisposableDetector.ISSUE ); } } ࡞ͬͨ*TTVFΛొ࿥͢Δ3FHJTUPSZΫϥεΛ࡞Γ·͢ɻ *TTVF͸ෳ਺ొ࿥Ͱ͖·͢ɻ
  23. © DMM.com X ̑3FHJTUSZΛCVJMEHSBEMFʹهड़ jar { manifest { attributes("Lint-Registry-v2": "com.kgmyshin.lint.CustomIssueRegistry")

    } } A-JOU3FHJTUSZ7Aʹઌ΄Ͳ࡞ͬͨ3FHJTUSZΛઃఆ͠·͢ɻ A7AΛ๨Εͳ͍Α͏ʹɻ
  24. © DMM.com X ςετͷॻ͖ํ public void ςετϝιου໊() { @Language("kotlin") String

    content = "ʢର৅ίʔυʣ"; lint().files( kotlin(content) ).run().expect("Τϥʔݕग़࣌΋͘͠͸੒ޭ࣌ͷจݴ") } ςετ͸͜ͷΑ͏ʹॻ͖·͢ɻ
  25. © DMM.com X ςετͷॻ͖ํ public void ςετϝιου໊() { @Language("kotlin") String

    content = "ʢର৅ίʔυʣ"; lint().files( kotlin(content) ).run().expect("Τϥʔݕग़࣌΋͘͠͸੒ޭ࣌ͷจݴ") } ର৅ίʔυΛจࣈྻͰ༻ҙɻ ௕͘ͳΔ͜ͱ͕ଟ͍ͱࢥ͏ͷͰɺϑΝΠϧಡΈࠐΈʹ͢Δͷ͕٢ɻ
  26. © DMM.com X ςετͷॻ͖ํ public void ςετϝιου໊() { @Language("kotlin") String

    content = "ʢର৅ίʔυʣ"; lint().files( kotlin(content) ).run().expect("Τϥʔݕग़࣌΋͘͠͸੒ޭ࣌ͷจݴ") } LPUMJOϑΝΠϧͱͯ͠౉ͯ͠ɺΤϥʔจݴ͕͋ͬͯΔ͔Ͳ͏ ͔ΛAFYQFDUAϝιουͰ֬ೝ͢Δɻ
  27. © DMM.com X ςετͷॻ͖ํ public void ςετϝιου໊() { @Language(“JAVA") String

    content = "ʢର৅ίʔυʣ"; lint().files( java(content) ).run().expect("Τϥʔݕग़࣌΋͘͠͸੒ޭ࣌ͷจݴ") } KBWBͷͱ͖͸ɺԼهՕॴ͕KBWBʹͳΓ·͢ɻ
  28. © DMM.com X ࡞ͬͨ$VTUPN-JOUͷ࢖͍ํ dependencies { implementation 'io.reactivex.rxjava2:rxjava:2.1.10' lintChecks project(":checks")

    } ಉҰϓϩδΣΫτʹ͋Δ৔߹͸ɺԼهͷΑ͏ʹEFQFOEFODJFTʹ MJOU$IFDLTQSPKFDU $VTUPN-JOUϞδϡʔϧ  Λ௥Ճ
  29. © DMM.com X ࡞ͬͨ$VTUPN-JOUͷ࢖͍ํ dependencies { implementation 'io.reactivex.rxjava2:rxjava:2.1.10' lintChecks files("lint/custom-lint.jar")

    } ଞͷϓϩδΣΫτͳͲͰͷ࠶ར༻໨తͰKBSͷΈ͔͠ͳ͍৔߹͸ MJOU$IFDLTpMFT KBSͷύε  Λ௥Ճ
  30. © DMM.com X ࡞ͬͨ$VTUPN-JOUͷ࢖͍ํ ./gradlew lint : Errors found: /../custom-lint-rules/library/src/main/java/test/pkg/MainJava.java:8:

    Error: Should handle Disposable [NotHandledDisposable] Single.just("test").subscribe(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /../custom-lint-rules/library/src/main/java/test/pkg/MainKt.kt:8: Error: Should handle Disposable [NotHandledDisposable] Single.just("aa").subscribe() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ : ແࣄಈ͖·ͨ͠ʂ