3131import org .jetbrains .annotations .NotNull ;
3232import org .jetbrains .annotations .Nullable ;
3333
34- import java .util .List ;
35- import java .util .Map ;
36- import java .util .Set ;
34+ import java .util .*;
3735import java .util .stream .Collectors ;
3836
3937public abstract class CAAnnotator extends ExternalAnnotator <CAAnnotator .Info , Map <Dependency , CAAnnotator .Result >> {
@@ -82,7 +80,7 @@ public abstract class CAAnnotator extends ExternalAnnotator<CAAnnotator.Info, Ma
8280 }
8381
8482 LOG .info ("Get vulnerability report from cache" );
85- Map <Dependency , DependencyReport > reports = CAService .getReports (path );
83+ Map <Dependency , Map < VulnerabilitySource , DependencyReport > > reports = CAService .getReports (path );
8684 return this .matchDependencies (info .getDependencies (), reports );
8785 }
8886
@@ -94,39 +92,79 @@ public void apply(@NotNull PsiFile file, Map<Dependency, Result> annotationResul
9492 LOG .info ("Annotate dependencies" );
9593 annotationResult .forEach ((key , value ) -> {
9694 if (value != null ) {
97- DependencyReport report = value .getReport ();
95+ Map < VulnerabilitySource , DependencyReport > reports = value .getReports ();
9896 List <PsiElement > elements = value .getElements ();
99- if (report . getIssues () != null && !report . getIssues () .isEmpty ()
97+ if (reports != null && !reports .isEmpty ()
10098 && elements != null && !elements .isEmpty ()) {
101- if (report .getRef () != null ) {
102- String d = getDependencyString (report .getRef ().purl ());
103- int num = report .getIssues ().size ();
104- String m = d + ", " + "Known security vulnerabilities: " + num + ", " ;
105- String t = "<html>" +
106- "<p>" + d + "</p>" +
107- "<p>Known security vulnerabilities: " + num + "</p>" ;
108-
109- if (report .getHighestVulnerability () != null && report .getHighestVulnerability ().getSeverity () != null ) {
110- String severity = report .getHighestVulnerability ().getSeverity ().getValue ();
111- m += "Highest severity: " + severity + ", " ;
112- t += "<p>Highest severity: " + severity + "</p>" ;
113- }
99+ Optional <DependencyReport > reportOptional = reports .values ().stream ()
100+ .filter (Objects ::nonNull ).findAny ();
101+
102+ if (reportOptional .isPresent () && reportOptional .get ().getRef () != null ) {
103+ String name = getDependencyString (reportOptional .get ().getRef ().purl ());
104+
105+ StringBuilder messageBuilder = new StringBuilder (name );
106+ StringBuilder tooltipBuilder = new StringBuilder ("<html>" ).append ("<p>" ).append (name ).append ("</p>" );
107+ Map <VulnerabilitySource , DependencyReport > quickfixes = new HashMap <>();
108+
109+ reports .forEach ((source , report ) -> {
110+ if (report .getIssues () != null && !report .getIssues ().isEmpty ()) {
111+ messageBuilder .append (System .lineSeparator ());
112+ tooltipBuilder .append ("<p/>" );
114113
115- m += "Dependency Analytics Plugin [Powered by Snyk]" ;
116- t += "<p>Dependency Analytics Plugin [Powered by <a href='https://snyk.io/'>Snyk</a>]</p>" +
117- "</html>" ;
114+ if (source .getProvider ().equals (source .getSource ())) {
115+ messageBuilder .append (source .getProvider ())
116+ .append (" vulnerability info: " );
117+ tooltipBuilder .append ("<p>" )
118+ .append (source .getProvider ())
119+ .append (" vulnerability info:</p>" );
120+ } else {
121+ messageBuilder .append (source .getSource ())
122+ .append (" (" )
123+ .append (source .getProvider ())
124+ .append (") vulnerability info: " );
125+ tooltipBuilder .append ("<p>" )
126+ .append (source .getSource ())
127+ .append (" (" )
128+ .append (source .getProvider ())
129+ .append (") vulnerability info:</p>" );
130+ }
118131
119- String message = m ;
120- String tooltip = t ;
132+ int num = report .getIssues ().size ();
133+ messageBuilder .append ("Known security vulnerabilities: " )
134+ .append (num );
135+ tooltipBuilder .append ("<p>Known security vulnerabilities: " )
136+ .append (num )
137+ .append ("</p>" );
138+
139+ if (report .getHighestVulnerability () != null && report .getHighestVulnerability ().getSeverity () != null ) {
140+ String severity = report .getHighestVulnerability ().getSeverity ().getValue ();
141+ messageBuilder .append (", Highest severity: " )
142+ .append (severity );
143+ tooltipBuilder .append ("<p>Highest severity: " )
144+ .append (severity )
145+ .append ("</p>" );
146+ }
147+ }
148+
149+ if (CAIntentionAction .isQuickFixAvailable (report )) {
150+ quickfixes .put (source , report );
151+ }
152+ });
121153
122154 elements .forEach (e -> {
123155 if (e != null ) {
124- AnnotationBuilder builder = holder
125- .newAnnotation (HighlightSeverity .ERROR , message )
126- .tooltip (tooltip )
127- .range (e )
128- .withFix (new CAIntentionAction ());
129- builder .create ();
156+ if (!quickfixes .isEmpty () && this .isQuickFixApplicable (e )) {
157+ quickfixes .forEach ((source , report ) ->{
158+ AnnotationBuilder builder = holder
159+ .newAnnotation (getHighlightSeverity (report ), messageBuilder .toString ())
160+ .tooltip (tooltipBuilder .toString ())
161+ .range (e );
162+ builder .withFix (new SAIntentionAction ());
163+ builder .withFix (this .createQuickFix (e , source , report ));
164+ builder .create ();
165+ }
166+ );
167+ }
130168 }
131169 });
132170 }
@@ -135,12 +173,29 @@ public void apply(@NotNull PsiFile file, Map<Dependency, Result> annotationResul
135173 });
136174 }
137175
176+ @ NotNull
177+ private static HighlightSeverity getHighlightSeverity (DependencyReport report ) {
178+ if (CAIntentionAction .thereAreNoIssues (report ) && CAIntentionAction .thereIsRecommendation (report ))
179+ {
180+ return HighlightSeverity .WEAK_WARNING ;
181+ }
182+ else
183+ {
184+ return HighlightSeverity .ERROR ;
185+ }
186+
187+ }
188+
138189 abstract protected String getInspectionShortName ();
139190
140191 abstract protected Map <Dependency , List <PsiElement >> getDependencies (PsiFile file );
141192
193+ abstract protected CAIntentionAction createQuickFix (PsiElement element , VulnerabilitySource source , DependencyReport report );
194+
195+ abstract protected boolean isQuickFixApplicable (PsiElement element );
196+
142197 private Map <Dependency , Result > matchDependencies (Map <Dependency , List <PsiElement >> dependencies ,
143- Map <Dependency , DependencyReport > reports ) {
198+ Map <Dependency , Map < VulnerabilitySource , DependencyReport > > reports ) {
144199 if (dependencies != null && !dependencies .isEmpty ()
145200 && reports != null && !reports .isEmpty ()) {
146201 return dependencies .entrySet ()
@@ -217,19 +272,19 @@ public Map<Dependency, List<PsiElement>> getDependencies() {
217272
218273 public static class Result {
219274 List <PsiElement > elements ;
220- DependencyReport report ;
275+ Map < VulnerabilitySource , DependencyReport > reports ;
221276
222- public Result (List <PsiElement > elements , DependencyReport report ) {
277+ public Result (List <PsiElement > elements , Map < VulnerabilitySource , DependencyReport > reports ) {
223278 this .elements = elements ;
224- this .report = report ;
279+ this .reports = reports ;
225280 }
226281
227282 public List <PsiElement > getElements () {
228283 return elements ;
229284 }
230285
231- public DependencyReport getReport () {
232- return report ;
286+ public Map < VulnerabilitySource , DependencyReport > getReports () {
287+ return reports ;
233288 }
234289 }
235290}
0 commit comments