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 }