001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect ErrorCheck {
032    
033      protected String ASTNode.sourceFile() {
034        ASTNode node = this;
035        while (node != null && !(node instanceof CompilationUnit)) {
036          node = node.getParent();
037        }
038        if (node == null) {
039          return "Unknown file";
040        }
041        CompilationUnit u = (CompilationUnit) node;
042        return u.relativeName();
043      }
044    
045      syn int ASTNode.lineNumber() {
046        ASTNode n = this;
047        while (n.getParent() != null && n.getStart() == 0) {
048          n = n.getParent();
049        }
050        return getLine(n.getStart());
051      }
052    
053      eq ClassDecl.lineNumber() = getLine(IDstart);
054      eq MethodDecl.lineNumber() = getLine(IDstart);
055    
056      // set start and end position to the same as the argument and return self
057      public ASTNode ASTNode.setLocation(ASTNode node) {
058        setStart(node.getStart());
059        setEnd(node.getEnd());
060        return this;
061      }
062    
063      public ASTNode ASTNode.setStart(int i) {
064        start = i;
065        return this;
066      }
067      public int ASTNode.start() {
068        return start;
069      }
070      public ASTNode ASTNode.setEnd(int i) {
071        end = i;
072        return this;
073      }
074      public int ASTNode.end() {
075        return end;
076      }
077    
078      public String ASTNode.location() {
079        return "" + lineNumber();
080      }
081      public String ASTNode.errorPrefix() {
082        return sourceFile() + ":" + location() + ":\n" + "  *** Semantic Error: ";
083      }
084      public String ASTNode.warningPrefix() {
085        return sourceFile() + ":" + location() + ":\n" + "  *** WARNING: ";
086      }
087    
088      protected Collection<Problem> CompilationUnit.errors = new LinkedList<Problem>();
089      protected Collection<Problem> CompilationUnit.warnings = new LinkedList<Problem>();
090    
091      public Collection CompilationUnit.parseErrors() { return parseErrors; }
092      public void CompilationUnit.addParseError(Problem msg) { parseErrors.add(msg); }
093      protected Collection CompilationUnit.parseErrors = new ArrayList();
094    
095      public class Problem implements Comparable {
096        public int compareTo(Object o) {
097          if (o instanceof Problem) {
098            Problem other = (Problem) o;
099            if (!fileName.equals(other.fileName)) {
100              return fileName.compareTo(other.fileName);
101            }
102            if (line != other.line) {
103              return line - other.line;
104            }
105            return message.compareTo(other.message);
106          }
107          return 0;
108        }
109        public static class Severity {
110          public static final Severity ERROR = new Severity();
111          public static final Severity WARNING = new Severity();
112          private Severity() { }
113        }
114        public static class Kind {
115          public static final Kind OTHER = new Kind();
116          public static final Kind LEXICAL = new Kind();
117          public static final Kind SYNTACTIC = new Kind();
118          public static final Kind SEMANTIC = new Kind();
119          private Kind() { }
120        }
121        protected int line = -1;
122        public int line() { return line; }
123        protected int column = -1;
124        public int column() { return column; }
125        protected int endLine = -1;
126        public int endLine() { return endLine; }
127        protected int endColumn = -1;
128        public int endColumn() { return endColumn; }
129        protected String fileName;
130        public String fileName() { return fileName; }
131        public void setFileName(String fileName) { this.fileName = fileName; }
132        protected String message;
133        public String message() { return message; }
134        protected Severity severity = Severity.ERROR;
135        public Severity severity() { return severity; }
136        protected Kind kind = Kind.OTHER;
137        public Kind kind() { return kind; }
138        public Problem(String fileName, String message) {
139          this.fileName = fileName;
140          this.message = message;
141        }
142        public Problem(String fileName, String message, int line) {
143          this(fileName, message);
144          this.line = line;
145        }
146        public Problem(String fileName, String message, int line, Severity severity) {
147          this(fileName, message);
148          this.line = line;
149          this.severity = severity;
150        }
151        public Problem(String fileName, String message, int line, int column, Severity severity) {
152          this(fileName, message);
153          this.line = line;
154          this.column = column;
155          this.severity = severity;
156        }
157        public Problem(String fileName, String message, int line, Severity severity, Kind kind) {
158          this(fileName, message);
159          this.line = line;
160          this.kind = kind;
161          this.severity = severity;
162        }
163        public Problem(String fileName, String message, int line, int column, Severity severity, Kind kind) {
164          this(fileName, message);
165          this.line = line;
166          this.column = column;
167          this.kind = kind;
168          this.severity = severity;
169        }
170        public Problem(String fileName, String message, int line, int column, int endLine, int endColumn, Severity severity, Kind kind) {
171          this(fileName, message);
172          this.line = line;
173          this.column = column;
174          this.endLine = endLine;
175          this.endColumn = endColumn;
176          this.kind = kind;
177          this.severity = severity;
178        }
179        public String toString() {
180          String location = "";
181          if (line != -1 && column != -1) {
182            location = line + "," + column + ":";
183          } else if (line != -1) {
184            location = line + ":";
185          }
186          String s = "";
187          if (this.kind == Kind.LEXICAL) {
188            s = "Lexical Error: ";
189          } else if (this.kind == Kind.SYNTACTIC) {
190            s = "Syntactic Error: ";
191          } else if (this.kind == Kind.SEMANTIC) {
192            s = "Semantic Error: ";
193          }
194          return fileName + ":" + location + "\n" + "  " + s + message;
195        }
196      }
197    
198      public void ASTNode.errorf(String messagefmt, Object... args) {
199        error(String.format(messagefmt, args));
200      }
201    
202      public void ASTNode.error(String message) {
203        ASTNode node = this;
204        while (node != null && !(node instanceof CompilationUnit)) {
205          node = node.getParent();
206        }
207        CompilationUnit cu = (CompilationUnit) node;
208        if (getNumChild() == 0 && getStart() != 0 && getEnd() != 0) {
209          int line = getLine(getStart());
210          int column = getColumn(getStart());
211          int endLine = getLine(getEnd());
212          int endColumn = getColumn(getEnd());
213          cu.errors.add(new Problem(sourceFile(), message, line, column, endLine, endColumn,
214              Problem.Severity.ERROR, Problem.Kind.SEMANTIC));
215        } else {
216          cu.errors.add(new Problem(sourceFile(), message, lineNumber(), Problem.Severity.ERROR,
217              Problem.Kind.SEMANTIC));
218        }
219      }
220    
221      public void ASTNode.warning(String s) {
222        ASTNode node = this;
223        while (node != null && !(node instanceof CompilationUnit)) {
224          node = node.getParent();
225        }
226        CompilationUnit cu = (CompilationUnit) node;
227        cu.warnings.add(new Problem(sourceFile(), "WARNING: " + s, lineNumber(), Problem.Severity.WARNING));
228      }
229    
230      public void ASTNode.collectErrors() {
231        nameCheck();
232        typeCheck();
233        accessControl();
234        exceptionHandling();
235        checkUnreachableStmt();
236        definiteAssignment();
237        checkModifiers();
238        for (int i = 0; i < getNumChild(); i++) {
239          getChild(i).collectErrors();
240        }
241      }
242    
243      public void ClassDecl.collectErrors() {
244        super.collectErrors();
245        if (hasImplicitConstructor()) {
246          getImplicitConstructor().collectErrors();
247        }
248      }
249    
250      public void VarDeclStmt.collectErrors() {
251        // check reachability of the multi-declaration
252        checkUnreachableStmt();
253    
254        // delegate other error checks to NTA single variable declarations
255        getSingleDeclList().collectErrors();
256      }
257    
258      /**
259       * @return collection of semantic errors
260       */
261      public Collection<Problem> CompilationUnit.errors() {
262        return errors;
263      }
264    
265      /**
266       * @return collection of semantic warnings
267       */
268      public Collection<Problem> CompilationUnit.warnings() {
269        return warnings;
270      }
271    }