4545import java .util .Set ;
4646import java .util .logging .Level ;
4747import java .util .logging .Logger ;
48+ import java .util .regex .Matcher ;
49+ import java .util .regex .Pattern ;
4850import org .netbeans .api .annotations .common .NonNull ;
4951import org .netbeans .api .java .classpath .ClassPath ;
5052import org .netbeans .api .project .FileOwnerQuery ;
5355import org .netbeans .modules .parsing .impl .indexing .PathRegistry ;
5456import org .netbeans .modules .parsing .impl .indexing .URLCache ;
5557import org .netbeans .modules .parsing .impl .indexing .implspi .CacheFolderProvider ;
58+ import org .netbeans .modules .parsing .spi .indexing .ErrorsCache ;
5659import org .netbeans .modules .parsing .spi .indexing .ErrorsCache .Convertor ;
5760import org .netbeans .modules .parsing .spi .indexing .ErrorsCache .ErrorKind ;
61+ import org .netbeans .modules .parsing .spi .indexing .ErrorsCache .ReverseConvertor ;
5862import org .netbeans .modules .parsing .spi .indexing .Indexable ;
5963import org .netbeans .spi .tasklist .Task ;
6064import org .openide .filesystems .FileObject ;
@@ -77,6 +81,10 @@ public class TaskCache {
7781
7882 private static final Logger LOG = Logger .getLogger (TaskCache .class .getName ());
7983
84+ // Matches the diagnostic range with both the start and the end positions specified (e.g. 1,2-1,7)
85+ // or with only the start position specified (e.g. 1,2) where positions are written in a form line,column
86+ private static final Pattern PATTERN = Pattern .compile ("(\\ d*),(\\ d*)(?:-(\\ d*),(\\ d*))?" );
87+
8088 static {
8189// LOG.setLevel(Level.FINEST);
8290 }
@@ -103,17 +111,31 @@ private String getTaskType( ErrorKind k ) {
103111 }
104112 return null ;
105113 }
106-
114+
115+ private ReverseConvertor <Task > getTaskConvertor (FileObject file ) {
116+ return (kind , range , message ) -> {
117+ String severity = getTaskType (kind );
118+ if (null != severity ) {
119+ return Task .create (file , severity , message , range .start ().line ());
120+ }
121+ return null ;
122+ };
123+ }
124+
107125 public List <Task > getErrors (FileObject file ) {
108- List <Task > result = new LinkedList <Task >();
126+ return getErrors (file , getTaskConvertor (file ));
127+ }
128+
129+ public <T > List <T > getErrors (FileObject file , ReverseConvertor <T > convertor ) {
130+ List <T > result = new LinkedList <>();
109131
110- result .addAll (getErrors (file , ERR_EXT ));
111- result .addAll (getErrors (file , WARN_EXT ));
132+ result .addAll (getErrors (file , convertor , ERR_EXT ));
133+ result .addAll (getErrors (file , convertor , WARN_EXT ));
112134
113135 return result ;
114136 }
115137
116- private List <Task > getErrors (FileObject file , String ext ) {
138+ private < T > List <T > getErrors (FileObject file , ReverseConvertor < T > convertor , String ext ) {
117139 LOG .log (Level .FINE , "getErrors, file={0}, ext={1}" , new Object [] {FileUtil .getFileDisplayName (file ), ext }); //NOI18N
118140
119141 try {
@@ -122,16 +144,16 @@ private List<Task> getErrors(FileObject file, String ext) {
122144 LOG .log (Level .FINE , "getErrors, error file={0}" , input == null ? "null" : input .getAbsolutePath ()); //NOI18N
123145
124146 if (input == null || !input .canRead ())
125- return Collections .< Task > emptyList ();
147+ return Collections .emptyList ();
126148
127149 input .getParentFile ().mkdirs ();
128150
129- return loadErrors (input , file );
151+ return loadErrors (input , convertor );
130152 } catch (IOException e ) {
131153 LOG .log (Level .FINE , null , e );
132154 }
133155
134- return Collections .< Task > emptyList ();
156+ return Collections .emptyList ();
135157 }
136158
137159 private <T > boolean dumpErrors (File output , Iterable <? extends T > errors , Convertor <T > convertor , boolean interestedInReturnValue ) throws IOException {
@@ -144,7 +166,15 @@ private <T> boolean dumpErrors(File output, Iterable<? extends T> errors, Conver
144166 for (T err : errors ) {
145167 pw .print (convertor .getKind (err ).name ());
146168 pw .print (':' ); //NOI18N
147- pw .print (convertor .getLineNumber (err ));
169+ ErrorsCache .Range range = convertor .getRange (err );
170+ if (range != null ) {
171+ pw .print (String .format ("%d,%d" , range .start ().line (), range .start ().column ()));
172+ if (range .end () != null ) {
173+ pw .print (String .format ("-%d,%d" , range .end ().line (), range .end ().column ()));
174+ }
175+ } else {
176+ pw .print (convertor .getLineNumber (err ));
177+ }
148178 pw .print (':' ); //NOI18N
149179
150180 String description = convertor .getMessage (err );
@@ -200,6 +230,7 @@ public <T> void dumpErrors(final URL root, final Indexable i, final Iterable<? e
200230 }
201231 });
202232 } catch (IOException ex ) {
233+ Exceptions .attachMessage (ex , "can't dump errors for: " + String .valueOf (i ));
203234 Exceptions .printStackTrace (ex );
204235 }
205236 }
@@ -255,8 +286,8 @@ private <T> void dumpErrors(TransactionContext c, URL root, Indexable i, Iterabl
255286 c .rootsToRefresh .add (root );
256287 }
257288
258- private List <Task > loadErrors (File input , FileObject file ) throws IOException {
259- List <Task > result = new LinkedList <Task >();
289+ private < T > List <T > loadErrors (File input , ReverseConvertor < T > convertor ) throws IOException {
290+ List <T > result = new LinkedList <>();
260291 BufferedReader pw = new BufferedReader (new InputStreamReader (new FileInputStream (input ), StandardCharsets .UTF_8 ));
261292 String line ;
262293
@@ -277,18 +308,26 @@ private List<Task> loadErrors(File input, FileObject file) throws IOException {
277308 continue ;
278309 }
279310
280- int lineNumber = Integer .parseInt (parts [1 ]);
281- String message = parts [2 ];
311+ ErrorsCache .Range range ;
312+ Matcher matcher = PATTERN .matcher (parts [1 ]);
313+ if (matcher .matches ()) {
314+ ErrorsCache .Position start = new ErrorsCache .Position (Integer .parseInt (matcher .group (1 )), Integer .parseInt (matcher .group (2 )));
315+ ErrorsCache .Position end = matcher .group (3 ) != null && matcher .group (4 ) != null ? new ErrorsCache .Position (Integer .parseInt (matcher .group (3 )), Integer .parseInt (matcher .group (4 ))) : null ;
316+ range = new ErrorsCache .Range (start , end );
317+ } else {
318+ int lineNumber = Integer .parseInt (parts [1 ]);
319+ range = new ErrorsCache .Range (new ErrorsCache .Position (lineNumber , 1 ), null );
320+ }
282321
283- message = message .replaceAll ("\\ \\ d" , ":" ); //NOI18N
284- message = message .replaceAll ("\\ \\ n" , " " ); //NOI18N
285- message = message .replaceAll ("\\ \\ \\ \\ " , "\\ \\ " ); //NOI18N
322+ String message = parts [2 ];
286323
287- String severity = getTaskType (kind );
324+ message = message .replace ("\\ d" , ":" ) //NOI18N
325+ .replace ("\\ n" , "\n " ) //NOI18N
326+ .replace ("\\ \\ " , "\\ " ); //NOI18N
288327
289- if ( null != severity ) {
290- Task err = Task . create ( file , severity , message , lineNumber );
291- result .add (err );
328+ T item = convertor . get ( kind , range , message );
329+ if ( null != item ) {
330+ result .add (item );
292331 }
293332 }
294333
@@ -351,12 +390,12 @@ private List<URL> getAllFilesWithRecord(URL root, boolean onlyErrors) throws IOE
351390 public List <URL > getAllFilesInError (URL root ) throws IOException {
352391 return getAllFilesWithRecord (root , true );
353392 }
354-
393+
355394 public boolean isInError (FileObject file , boolean recursive ) {
356395 LOG .log (Level .FINE , "file={0}, recursive={1}" , new Object [] {file , Boolean .valueOf (recursive )}); //NOI18N
357396
358397 if (file .isData ()) {
359- return !getErrors (file , ERR_EXT ).isEmpty ();
398+ return !getErrors (file , getTaskConvertor ( file ), ERR_EXT ).isEmpty ();
360399 } else {
361400 try {
362401 ClassPath cp = Utilities .getSourceClassPathFor (file );
0 commit comments