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,38 +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+ }
131+
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+ }
118148
119- String message = m ;
120- String tooltip = t ;
149+ if (CAIntentionAction .isQuickFixAvailable (report )) {
150+ quickfixes .put (source , report );
151+ }
152+ });
121153
122154 elements .forEach (e -> {
123155 if (e != null ) {
124156 AnnotationBuilder builder = holder
125- .newAnnotation (HighlightSeverity .ERROR , message )
126- .tooltip (tooltip )
127- .range (e )
128- .withFix (new CAIntentionAction ());
157+ .newAnnotation (HighlightSeverity .ERROR , messageBuilder .toString ())
158+ .tooltip (tooltipBuilder .toString ())
159+ .range (e );
160+
161+ builder .withFix (new SAIntentionAction ());
162+
163+ if (!quickfixes .isEmpty () && this .isQuickFixApplicable (e )) {
164+ quickfixes .forEach ((source , report ) ->
165+ builder .withFix (this .createQuickFix (e , source , report )));
166+ }
167+
129168 builder .create ();
130169 }
131170 });
@@ -139,8 +178,12 @@ public void apply(@NotNull PsiFile file, Map<Dependency, Result> annotationResul
139178
140179 abstract protected Map <Dependency , List <PsiElement >> getDependencies (PsiFile file );
141180
181+ abstract protected CAIntentionAction createQuickFix (PsiElement element , VulnerabilitySource source , DependencyReport report );
182+
183+ abstract protected boolean isQuickFixApplicable (PsiElement element );
184+
142185 private Map <Dependency , Result > matchDependencies (Map <Dependency , List <PsiElement >> dependencies ,
143- Map <Dependency , DependencyReport > reports ) {
186+ Map <Dependency , Map < VulnerabilitySource , DependencyReport > > reports ) {
144187 if (dependencies != null && !dependencies .isEmpty ()
145188 && reports != null && !reports .isEmpty ()) {
146189 return dependencies .entrySet ()
@@ -217,19 +260,19 @@ public Map<Dependency, List<PsiElement>> getDependencies() {
217260
218261 public static class Result {
219262 List <PsiElement > elements ;
220- DependencyReport report ;
263+ Map < VulnerabilitySource , DependencyReport > reports ;
221264
222- public Result (List <PsiElement > elements , DependencyReport report ) {
265+ public Result (List <PsiElement > elements , Map < VulnerabilitySource , DependencyReport > reports ) {
223266 this .elements = elements ;
224- this .report = report ;
267+ this .reports = reports ;
225268 }
226269
227270 public List <PsiElement > getElements () {
228271 return elements ;
229272 }
230273
231- public DependencyReport getReport () {
232- return report ;
274+ public Map < VulnerabilitySource , DependencyReport > getReports () {
275+ return reports ;
233276 }
234277 }
235278}
0 commit comments