/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ca.weblite.netbeans.mirah.lexer; import ca.weblite.netbeans.mirah.ImportFixList; import ca.weblite.netbeans.mirah.lexer.MirahParser.MirahParseDiagnostics.SyntaxError; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.text.Document; import org.netbeans.api.lexer.Token; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.parsing.api.Source; import org.netbeans.modules.parsing.spi.Parser; import org.netbeans.modules.parsing.spi.ParserResultTask; import org.netbeans.modules.parsing.spi.Scheduler; import org.netbeans.modules.parsing.spi.SchedulerEvent; import org.netbeans.spi.editor.hints.ErrorDescription; import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; import org.netbeans.spi.editor.hints.Fix; import org.netbeans.spi.editor.hints.HintsController; import org.netbeans.spi.editor.hints.Severity; import org.openide.util.RequestProcessor; /** * * @author shannah */ class SyntaxErrorsHighlightingTask extends ParserResultTask { private static final Logger LOG = Logger.getLogger(SyntaxErrorsHighlightingTask.class.getCanonicalName()); public SyntaxErrorsHighlightingTask() { } @Override public void run(Parser.Result t, SchedulerEvent se) { MirahParser.NBMirahParserResult result = (MirahParser.NBMirahParserResult) t; if ( result == null || result.getMirahDiagnostics() == null ){ return; } List<SyntaxError> syntaxErrors = result.getMirahDiagnostics().getErrors(); Snapshot snapshot = result.getSnapshot(); if ( snapshot == null ){ return; } Source source = snapshot.getSource(); if ( source == null ){ return; } Document document = source.getDocument(false); if ( document == null ){ return; } List<ErrorDescription> errors = new ArrayList<ErrorDescription>(); for (SyntaxError syntaxError : syntaxErrors) { String message = syntaxError.message; int line =-1; try { if ( syntaxError.position != null ){ //System.out.println("Syntax error position is not null: "+syntaxError.position); String[] pieces = syntaxError.position.substring(0, syntaxError.position.lastIndexOf(":")).split(":"); //System.out.println(Arrays.toString(pieces)); String file = pieces[0]; File f = new File(file); // Sometimes the error seems to cite a line in the mirah core source // files instead of the file that was being parsed. check // for that here if ( source.getFileObject() != null && !source.getFileObject().getName().equals(f.getName()) && !source.getFileObject().getNameExt().equals(f.getName())){ //System.out.println(source.getFileObject().getName()+" -- "+f.getName()); } else { int idx = pieces.length; while (--idx >0 && line == -1 ){ if ( pieces[idx].trim().length() == 0){ continue; } try { line = Integer.parseInt(pieces[idx]); } catch (NumberFormatException nfe){} } } } else { //System.out.println("Syntax error position is null"); } if ( line == -1 ){ // If we're here then it may be an inference error // Let's look through the document to see if we can find any // class references that don't have an import DocumentQuery q = new DocumentQuery(document); SourceQuery sq = new SourceQuery(document); List<Token<MirahTokenId>> lambdas = q.findLambdaTypes(); for ( Token<MirahTokenId> tok : lambdas ){ String className = String.valueOf(tok.text()); String fqn = sq.getFQN(className, tok.offset(TokenHierarchy.get(document))); if ( q.requiresImport(fqn)){ message = "cannot find class "+className; } } List<Token<MirahTokenId>> constants = q.findConstants(); for ( Token<MirahTokenId> tok : constants ){ String className = String.valueOf(tok.text()); String fqn = sq.getFQN(className, tok.offset(TokenHierarchy.get(document))); if ( q.requiresImport(fqn)){ message = "cannot find class "+className; } } line = 1; } } catch (NumberFormatException ex){ ex.printStackTrace(); } if (line <= 0) { continue; } ErrorDescription errorDescription = null; if ( message.toLowerCase().contains("cannot find class")){ //List<Fix> imports = new ArrayList<Fix>(); Pattern p = Pattern.compile("cannot find class ([a-zA-Z][a-zA-Z0-9\\.\\$]*)", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(message); if ( m.find() ){ String className = m.group(1); if ( className.indexOf(".") != -1 ){ int pos = className.lastIndexOf("."); if ( pos < className.length()-1 ){ pos++; } className = className.substring(pos); } ImportFixList importFixes = new ImportFixList(source, className); errorDescription = ErrorDescriptionFactory.createErrorDescription( Severity.ERROR, message, importFixes, document, line ); RequestProcessor rp = new RequestProcessor(SyntaxErrorsHighlightingTask.class); rp.submit(importFixes); } } if ( errorDescription == null ){ errorDescription = ErrorDescriptionFactory.createErrorDescription( Severity.ERROR, message, document, line); } errors.add(errorDescription); } CodeHintsTask codeHints = new CodeHintsTask(); codeHints.run(t, se); errors.addAll(codeHints.getErrors()); HintsController.setErrors(document, "mirah", errors); } @Override public int getPriority() { return 100; } @Override public Class<? extends Scheduler> getSchedulerClass() { return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER; } @Override public void cancel() { } }