001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect ErrorCheck {
011    
012      protected String ASTNode.sourceFile() {
013        ASTNode node = this;
014        while(node != null && !(node instanceof CompilationUnit))
015          node = node.getParent();
016        if(node == null)
017          return "Unknown file";
018        CompilationUnit u = (CompilationUnit)node;
019        return u.relativeName();
020      }
021    
022      syn int ASTNode.lineNumber() {
023        ASTNode n = this;
024        while(n.getParent() != null && n.getStart() == 0) {
025          n = n.getParent();
026        }
027        return getLine(n.getStart());
028      }
029    
030      eq ClassDecl.lineNumber() = getLine(IDstart);
031      eq MethodDecl.lineNumber() = getLine(IDstart);
032    
033      // set start and end position to the same as the argument and return self
034      public ASTNode ASTNode.setLocation(ASTNode node) {
035        setStart(node.getStart());
036        setEnd(node.getEnd());
037        return this;
038      }
039    
040      public ASTNode ASTNode.setStart(int i) {
041        start = i;
042        return this;
043      }
044      public int ASTNode.start() {
045        return start;
046      }
047      public ASTNode ASTNode.setEnd(int i) {
048        end = i;
049        return this;
050      }
051      public int ASTNode.end() {
052        return end;
053      }
054    
055      public String ASTNode.location() {
056        return "" + lineNumber();
057      }
058      public String ASTNode.errorPrefix() {
059        return sourceFile() + ":" + location() + ":\n" + "  *** Semantic Error: ";
060      }
061      public String ASTNode.warningPrefix() {
062        return sourceFile() + ":" + location() + ":\n" + "  *** WARNING: ";
063      }
064    
065      protected java.util.ArrayList CompilationUnit.errors = new java.util.ArrayList();
066      protected java.util.ArrayList CompilationUnit.warnings = new java.util.ArrayList();
067    
068      public Collection CompilationUnit.parseErrors() { return parseErrors; }
069      public void CompilationUnit.addParseError(Problem msg) { parseErrors.add(msg); }
070      protected Collection CompilationUnit.parseErrors = new ArrayList();
071    
072      class Problem implements Comparable {
073        public int compareTo(Object o) {
074          if(o instanceof Problem) {
075            Problem other = (Problem)o;
076            if(!fileName.equals(other.fileName))
077              return fileName.compareTo(other.fileName);
078            if(line != other.line)
079              return line - other.line;
080            return message.compareTo(other.message);
081          }
082          return 0;
083        }
084        public static class Severity {
085          public static final Severity ERROR = new Severity();
086          public static final Severity WARNING = new Severity();
087          private Severity() { }
088        }
089        public static class Kind {
090          public static final Kind OTHER = new Kind();
091          public static final Kind LEXICAL = new Kind();
092          public static final Kind SYNTACTIC = new Kind();
093          public static final Kind SEMANTIC = new Kind();
094          private Kind() { }
095        }
096        protected int line = -1;
097        public int line() { return line; }
098        protected int column = -1;
099        public int column() { return column; }
100        protected int endLine = -1;
101        public int endLine() { return endLine; }
102        protected int endColumn = -1;
103        public int endColumn() { return endColumn; }
104        protected String fileName;
105        public String fileName() { return fileName; }
106        public void setFileName(String fileName) { this.fileName = fileName; }
107        protected String message;
108        public String message() { return message; }
109        protected Severity severity = Severity.ERROR;
110        public Severity severity() { return severity; }
111        protected Kind kind = Kind.OTHER;
112        public Kind kind() { return kind; }
113        public Problem(String fileName, String message) {
114          this.fileName = fileName;
115          this.message = message;
116        }
117        public Problem(String fileName, String message, int line) {
118          this(fileName, message);
119          this.line = line;
120        }
121        public Problem(String fileName, String message, int line, Severity severity) {
122          this(fileName, message);
123          this.line = line;
124          this.severity = severity;
125        }
126        public Problem(String fileName, String message, int line, int column, Severity severity) {
127          this(fileName, message);
128          this.line = line;
129          this.column = column;
130          this.severity = severity;
131        }
132        public Problem(String fileName, String message, int line, Severity severity, Kind kind) {
133          this(fileName, message);
134          this.line = line;
135          this.kind = kind;
136          this.severity = severity;
137        }
138        public Problem(String fileName, String message, int line, int column, Severity severity, Kind kind) {
139          this(fileName, message);
140          this.line = line;
141          this.column = column;
142          this.kind = kind;
143          this.severity = severity;
144        }
145        public Problem(String fileName, String message, int line, int column, int endLine, int endColumn, Severity severity, Kind kind) {
146          this(fileName, message);
147          this.line = line;
148          this.column = column;
149          this.endLine = endLine;
150          this.endColumn = endColumn;
151          this.kind = kind;
152          this.severity = severity;
153        }
154        public String toString() {
155          String location = "";
156          if(line != -1 && column != -1)
157            location = line + "," + column + ":";
158          else if(line != -1)
159            location = line + ":";
160          String s = "";
161          if(this.kind == Kind.LEXICAL)
162            s = "Lexical Error: ";
163          else if(this.kind == Kind.SYNTACTIC)
164            s = "Syntactic Error: ";
165          else if(this.kind == Kind.SEMANTIC)
166            s = "Semantic Error: ";
167          return fileName + ":" + location + "\n" + "  " + s + message;
168        }
169      }
170    
171      public void ASTNode.error(String s) {
172        ASTNode node = this;
173        while(node != null && !(node instanceof CompilationUnit))
174          node = node.getParent();
175        CompilationUnit cu = (CompilationUnit)node;
176        if(getNumChild() == 0 && getStart() != 0 && getEnd() != 0) {  
177          int line = getLine(getStart());
178          int column = getColumn(getStart());
179          int endLine = getLine(getEnd());
180          int endColumn = getColumn(getEnd());
181          cu.errors.add(new Problem(sourceFile(), s, line, column, endLine, endColumn, Problem.Severity.ERROR, Problem.Kind.SEMANTIC));
182        }
183        else
184          cu.errors.add(new Problem(sourceFile(), s, lineNumber(), Problem.Severity.ERROR, Problem.Kind.SEMANTIC));
185      }
186    
187      public void ASTNode.warning(String s) {
188        ASTNode node = this;
189        while(node != null && !(node instanceof CompilationUnit))
190          node = node.getParent();
191        CompilationUnit cu = (CompilationUnit)node;
192        cu.warnings.add(new Problem(sourceFile(), "WARNING: " + s, lineNumber(), Problem.Severity.WARNING));
193      }
194      
195      public void ASTNode.collectErrors() {
196        nameCheck();
197        typeCheck();
198        accessControl();
199        exceptionHandling();
200        checkUnreachableStmt();
201        definiteAssignment();
202        checkModifiers();
203        for(int i = 0; i < getNumChild(); i++) {
204          getChild(i).collectErrors();
205        }
206      }
207    
208      public void Program.errorCheck(Collection collection) {
209        for(Iterator iter = compilationUnitIterator(); iter.hasNext(); ) {
210          CompilationUnit cu = (CompilationUnit)iter.next();
211          if(cu.fromSource()) {
212            cu.collectErrors();
213            collection.addAll(cu.errors);
214          }
215        }
216      }
217      public void Program.errorCheck(Collection collection, Collection warn) {
218        for(Iterator iter = compilationUnitIterator(); iter.hasNext(); ) {
219          CompilationUnit cu = (CompilationUnit)iter.next();
220          if(cu.fromSource()) {
221            cu.collectErrors();
222            collection.addAll(cu.errors);
223            warn.addAll(cu.warnings);
224          }
225        }
226      }
227    
228      public void CompilationUnit.errorCheck(Collection collection) {
229        collectErrors();
230        collection.addAll(errors);
231      }
232      public void CompilationUnit.errorCheck(Collection err, Collection warn) {
233        collectErrors();
234        err.addAll(errors);
235        warn.addAll(warnings);
236      }
237      
238      public boolean Program.errorCheck() {
239        Collection collection = new LinkedList();
240        errorCheck(collection);
241        if(collection.isEmpty())
242          return false;
243        System.out.println("Errors:");
244        for(Iterator iter = collection.iterator(); iter.hasNext(); ) {
245          String s = (String)iter.next();
246          System.out.println(s);
247        }
248        return true;
249      }
250    }