/* * Created on Feb 20, 2005 * */ package org.rubypeople.rdt.internal.core.parser; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.SAXParserFactory; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.jruby.lexer.yacc.ISourcePosition; import org.jruby.lexer.yacc.SyntaxException; import org.rubypeople.rdt.core.IRubyModelMarker; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.core.compiler.IProblem; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; /** * @author Chris * */ public class MarkerUtility { private static Set<IgnoreMarker> toIgnore = new HashSet<IgnoreMarker>(); static { loadIgnoredMarkers(); } /** * @param underlyingResource * @param syntaxException * @param contentLength */ public static void createSyntaxError(IResource underlyingResource, SyntaxException syntaxException) { try { ISourcePosition pos = syntaxException.getPosition(); IMarker marker = underlyingResource.createMarker(IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER); Map<String, Comparable> map = new HashMap<String, Comparable>(); map.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR)); map.put(IMarker.MESSAGE, "Syntax Error"); map.put(IMarker.USER_EDITABLE, Boolean.FALSE); map.put(IMarker.LINE_NUMBER, new Integer(pos.getStartLine())); map.put(IMarker.CHAR_START, new Integer(pos.getStartOffset())); map.put(IMarker.CHAR_END, new Integer(pos.getEndOffset())); map.put(IRubyModelMarker.ID, IProblem.Syntax); marker.setAttributes(map); } catch (CoreException e) { RubyCore.log(e); } } /** * @param underlyingResource */ public static void removeMarkers(IResource underlyingResource) { try { underlyingResource.deleteMarkers(IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); } catch (CoreException e) { RubyCore.log(e); } } /** * @param resource * @param problems */ public static void createProblemMarkers(IResource resource, List<IProblem> problems) { for (Iterator iter = problems.iterator(); iter.hasNext();) { createProblemMarker(resource, (IProblem) iter.next()); } } public static void createProblemMarker(IResource underlyingResource, IProblem problem) { if (problem.isTask()) { try { createTask(underlyingResource, (TaskTag) problem); } catch (CoreException e) { RubyCore.log(e); } return; } try { if (markerExists(underlyingResource, problem.getID(), problem.getSourceStart(), problem.getSourceEnd(), IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER)) return; Map<String, Comparable> map = new HashMap<String, Comparable>(); int severity; if(problem.isWarning()) severity = IMarker.SEVERITY_WARNING; else if(problem.isError()) severity = IMarker.SEVERITY_ERROR; else severity = IMarker.SEVERITY_INFO; IMarker marker = underlyingResource.createMarker(IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER); map.put(IMarker.SEVERITY, new Integer(severity)); map.put(IMarker.MESSAGE, problem.getMessage()); map.put(IMarker.USER_EDITABLE, Boolean.FALSE); map.put(IMarker.LINE_NUMBER, new Integer(problem.getSourceLineNumber())); map.put(IMarker.CHAR_START, new Integer(problem.getSourceStart())); map.put(IMarker.CHAR_END, new Integer(problem.getSourceEnd())); map.put(IRubyModelMarker.ID, problem.getID()); marker.setAttributes(map); } catch (CoreException e) { RubyCore.log(e); } } public static void createTasks(IResource underlyingResource, List<TaskTag> tasks) throws CoreException { for (Iterator iter = tasks.iterator(); iter.hasNext();) { createTask(underlyingResource, (TaskTag) iter.next()); } } /** * @param underlyingResource * @param warning * @throws CoreException */ private static void createTask(IResource resource, TaskTag task) throws CoreException { int lineNumber = task.getSourceLineNumber(); if (lineNumber <= 0) lineNumber = 1; if (markerExists(resource, task.getID(), task.getSourceStart(), task.getSourceEnd(), IRubyModelMarker.TASK_MARKER)) return; HashMap<String, Comparable> map = new HashMap<String, Comparable>(); map.put(IMarker.PRIORITY, new Integer(task.getPriority())); map.put(IMarker.MESSAGE, task.getMessage()); map.put(IMarker.LINE_NUMBER, new Integer(lineNumber)); map.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO)); map.put(IMarker.USER_EDITABLE, new Boolean(false)); map.put(IMarker.TRANSIENT, new Boolean(false)); map.put(IMarker.CHAR_START, new Integer(task.getSourceStart())); map.put(IMarker.CHAR_END, new Integer(task.getSourceEnd())); map.put(IRubyModelMarker.ID, task.getID()); IMarker marker = resource.createMarker(IRubyModelMarker.TASK_MARKER); marker.setAttributes(map); } public static boolean markerExists(IResource resource, int id, int offset, int endOffset, String type) throws CoreException { // Check against ignore list if (ignoring(resource, id, offset, endOffset)) return true; IMarker tasks[] = resource.findMarkers(type, true, IResource.DEPTH_ZERO); for (int i = 0; i < tasks.length; i++) { if (markerMatches(id, offset, endOffset, tasks[i])) return true; } return false; } /** * Return a boolean to indicate if we should ignore a potential marker/annotation with the following attributes. * @param resource * @param id * @param offset * @param endOffset * @return */ public static boolean ignoring(IResource resource, int id, int offset, int endOffset) { for (IgnoreMarker marker : toIgnore) { if (!marker.getResource().equals(resource)) continue; if (markerMatches(id, offset, endOffset, marker)) return true; } return false; } private static boolean markerMatches(int id, int offset, int endOffset, IgnoreMarker marker) { if (marker.getId() != id) return false; if (marker.getOffset() != offset) return false; if (marker.getEndOffset() != endOffset) return false; return true; } public static boolean markerMatches(int id, int offset, int endOffset, IMarker marker) throws CoreException { Integer markerId = (Integer) marker.getAttribute(IRubyModelMarker.ID); if (markerId.intValue() != id) return false; Integer start = (Integer) marker.getAttribute(IMarker.CHAR_START); if (start != offset) return false; Integer end = (Integer) marker.getAttribute(IMarker.CHAR_END); if (end != endOffset) return false; return true; } public static void ignore(IResource resource, int problemId, int offset, int length) { ignore(new IgnoreMarker(resource, problemId, offset, offset + length)); } public static void ignore(IMarker marker) { try { ignore(new IgnoreMarker(marker)); } catch (CoreException e) { RubyCore.log(e); } } public synchronized static void ignore(IgnoreMarker marker) { if (toIgnore.contains(marker)) return; toIgnore.add(marker); saveIgnoredMarkers(); } private static void saveIgnoredMarkers() { PrintWriter out = null; try { out = new PrintWriter(new FileWriter(getConfigFile())); writeXML(out); } catch (FileNotFoundException e) { RubyCore.log(e); } catch (IOException e) { RubyCore.log(e); } finally { if (out != null) out.close(); } } private static void loadIgnoredMarkers() { Reader fileReader = null; try { fileReader = new FileReader(getConfigFile()); XMLReader reader = SAXParserFactory.newInstance().newSAXParser() .getXMLReader(); IgnoreMarkersContentHandler handler = new IgnoreMarkersContentHandler(); reader.setContentHandler(handler); reader.parse(new InputSource(fileReader)); toIgnore.clear(); Collection<IgnoreMarker> markers = handler.getIgnoreMarkers(); for (IgnoreMarker marker : markers) { toIgnore.add(marker); } } catch (FileNotFoundException e) { // This is okay, will get thrown if no config exists yet } catch (Exception e) { RubyCore.log(e); } finally { try { if (fileReader != null) fileReader.close(); } catch (IOException e) { // ignore } } } private static File getConfigFile() { IPath rubyCoreMetadataDir = RubyCore.getPlugin().getStateLocation(); return rubyCoreMetadataDir.append("ignore_warnings.xml").toFile(); } /** * Writes each server configuration to file in XML format. * * @param out * the writer to use */ private static void writeXML(PrintWriter out) { out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); out.println(tag(IgnoreMarkersContentHandler.ROOT)); Iterator i = toIgnore.iterator(); while (i.hasNext()) { IgnoreMarker s = (IgnoreMarker) i.next(); out.println(tag(IgnoreMarkersContentHandler.WARNING)); out.println(tag(IgnoreMarkersContentHandler.RESOURCE, s.getResource().getLocation().toPortableString())); out.println(tag(IgnoreMarkersContentHandler.ID, s.getId())); out.println(tag(IgnoreMarkersContentHandler.OFFSET, s.getOffset())); out.println(tag(IgnoreMarkersContentHandler.END_OFFSET,s.getEndOffset())); out.println(endTag(IgnoreMarkersContentHandler.WARNING)); } out.println(endTag(IgnoreMarkersContentHandler.ROOT)); out.flush(); } private static String tag(String tag) { return "<" + tag + ">"; } private static String endTag(String tag) { return "</" + tag + ">"; } private static String tag(String tag, String content) { return tag(tag) + content + endTag(tag); } private static String tag(String tag, int intValue) { return tag (tag, Integer.toString(intValue)); } }