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 TypeHierarchyCheck {
011      inh String Expr.methodHost();
012      eq TypeDecl.getBodyDecl().methodHost() = typeName();
013      eq AbstractDot.getRight().methodHost() = getLeft().type().typeName();
014      eq Program.getChild().methodHost() {
015        throw new Error("Needs extra equation for methodHost()");
016      }
017      eq MethodAccess.getChild().methodHost() = unqualifiedScope().methodHost();
018      eq ConstructorAccess.getChild().methodHost() = unqualifiedScope().methodHost();
019      
020      syn boolean Expr.isUnknown() = type().isUnknown();
021      eq PackageAccess.isUnknown() = !hasPackage(packageName());
022      
023      public void MethodAccess.nameCheck() {
024        if(isQualified() && qualifier().isPackageAccess() && !qualifier().isUnknown())
025          error("The method " + decl().signature() + 
026              " can not be qualified by a package name.");
027        if(isQualified() && decl().isAbstract() && qualifier().isSuperAccess())
028          error("may not access abstract methods in superclass");
029        if(decls().isEmpty() && (!isQualified() || !qualifier().isUnknown())) {
030          StringBuffer s = new StringBuffer();
031          s.append("no method named " + name());
032          s.append("(");
033          for(int i = 0; i < getNumArg(); i++) {
034            if(i != 0)
035              s.append(", ");
036            s.append(getArg(i).type().typeName());
037          }
038          s.append(")" + " in " + methodHost() + " matches.");
039          if(singleCandidateDecl() != null)
040            s.append(" However, there is a method " + singleCandidateDecl().signature());
041          error(s.toString());
042        }
043        if(decls().size() > 1) {
044          boolean allAbstract = true;
045          for(Iterator iter = decls().iterator(); iter.hasNext() && allAbstract; ) {
046             MethodDecl m = (MethodDecl)iter.next();
047            if(!m.isAbstract() && !m.hostType().isObject())
048              allAbstract = false;
049          }
050          if(!allAbstract && validArgs()) {
051            StringBuffer s = new StringBuffer();
052            s.append("several most specific methods for " + this + "\n");
053            for(Iterator iter = decls().iterator(); iter.hasNext(); ) {
054              MethodDecl m = (MethodDecl)iter.next();
055              s.append("    " + m.signature() + " in " + m.hostType().typeName() + "\n");
056            }
057            error(s.toString());
058          }
059           
060        }
061      }
062    
063      public void SuperConstructorAccess.nameCheck() {
064        super.nameCheck();
065        // 8.8.5.1
066        TypeDecl c = hostType();
067        TypeDecl s = c.isClassDecl() && ((ClassDecl)c).hasSuperclass() ? ((ClassDecl)c).superclass() : unknownType();
068        if(isQualified()) {
069          if(!s.isInnerType() || s.inStaticContext())
070            error("the super type " + s.typeName() + " of " + c.typeName() +
071               " is not an inner class");
072        
073          else if(!qualifier().type().instanceOf(s.enclosingType()))
074            error("The type of this primary expression, " +
075                    qualifier().type().typeName() + " is not enclosing the super type, " + 
076                    s.typeName() + ", of " + c.typeName());
077        }
078        if(!isQualified() && s.isInnerType()) {
079          if(!c.isInnerType()) {
080            error("no enclosing instance for " + s.typeName() + " when accessed in " + this);
081          }
082        }
083        if(s.isInnerType() && hostType().instanceOf(s.enclosingType()))
084          error("cannot reference this before supertype constructor has been called");
085      }
086    
087      public void SuperAccess.nameCheck() {
088        if(isQualified()) {
089          if(!hostType().isInnerTypeOf(decl()) && hostType() != decl())
090            error("qualified super must name an enclosing type");
091          if(inStaticContext()) {
092            error("*** Qualified super may not occur in static context");
093          }
094        }
095        // 8.8.5.1
096        if(inExplicitConstructorInvocation() && hostType().instanceOf(decl().hostType()) )
097          error("super may not be accessed in an explicit constructor invocation");
098        // 8.4.3.2
099        if(inStaticContext())
100          error("super may not be accessed in a static context");
101      }
102    
103      public void ThisAccess.nameCheck() {
104        // 8.8.5.1
105        if(inExplicitConstructorInvocation() && hostType() == type())
106          error("this may not be accessed in an explicit constructor invocation");
107        else if(isQualified()) {
108          // 15.8.4
109          if(inStaticContext())
110            error("qualified this may not occur in static context");
111          else if(!hostType().isInnerTypeOf(decl()) && hostType() != decl())
112            error("qualified this must name an enclosing type: " + getParent());
113        }
114        // 8.4.3.2
115        else if(!isQualified() && inStaticContext())
116          error("this may not be accessed in static context: " + enclosingStmt());
117      }
118      
119      
120    
121      // 8.8.5.1
122      inh boolean VarAccess.inExplicitConstructorInvocation();
123      inh boolean MethodAccess.inExplicitConstructorInvocation();
124      inh boolean SuperAccess.inExplicitConstructorInvocation();
125      inh boolean ThisAccess.inExplicitConstructorInvocation();
126      inh boolean ClassInstanceExpr.inExplicitConstructorInvocation();
127      inh lazy boolean TypeDecl.inExplicitConstructorInvocation();
128      eq Program.getChild().inExplicitConstructorInvocation() = false;
129    
130      eq ConstructorAccess.getArg().inExplicitConstructorInvocation() = true;
131      eq SuperConstructorAccess.getArg().inExplicitConstructorInvocation() = true;
132      eq ConstructorDecl.getConstructorInvocation().inExplicitConstructorInvocation() = true;
133    
134      inh boolean Expr.inStaticContext(); // SuperAccess, ThisAccess, ClassInstanceExpr, MethodAccess
135      inh lazy boolean TypeDecl.inStaticContext();
136      
137      eq Program.getChild().inStaticContext() = false;
138      eq TypeDecl.getBodyDecl().inStaticContext() = isStatic() || inStaticContext();
139      eq StaticInitializer.getBlock().inStaticContext() = true;
140      eq InstanceInitializer.getBlock().inStaticContext() = false;
141      eq FieldDeclaration.getInit().inStaticContext() = isStatic() || hostType().isInterfaceDecl();
142      eq MethodDecl.getBlock().inStaticContext() = isStatic();
143      eq ConstructorDecl.getBlock().inStaticContext() = false;
144      eq ConstructorDecl.getConstructorInvocation().inStaticContext() = false;
145      eq MemberClassDecl.getClassDecl().inStaticContext() = false;
146      
147      eq ClassInstanceExpr.getTypeDecl().inStaticContext() = isQualified() ?
148        qualifier().staticContextQualifier() : inStaticContext();
149    
150      syn boolean Expr.staticContextQualifier() = false;
151      eq ParExpr.staticContextQualifier() = getExpr().staticContextQualifier();
152      eq CastExpr.staticContextQualifier() = getExpr().staticContextQualifier();
153      eq AbstractDot.staticContextQualifier() = lastAccess().staticContextQualifier();
154      eq TypeAccess.staticContextQualifier() = true;
155      eq ArrayTypeAccess.staticContextQualifier() = true;
156    
157      public void TypeDecl.typeCheck() {
158        // 8.4.6.4 & 9.4.1
159        for(Iterator iter1 = localMethodsIterator(); iter1.hasNext(); ) {
160          MethodDecl m = (MethodDecl)iter1.next();
161          ASTNode target = m.hostType() == this ? (ASTNode)m : (ASTNode)this;
162          
163          //for(Iterator i2 = overrides(m).iterator(); i2.hasNext(); ) {
164          for(Iterator i2 = ancestorMethods(m.signature()).iterator(); i2.hasNext(); ) {
165            MethodDecl decl = (MethodDecl)i2.next();
166            if(m.overrides(decl)) {
167              // 8.4.6.1
168              if(!m.isStatic() && decl.isStatic())
169                target.error("an instance method may not override a static method");
170     
171              // regardless of overriding
172              // 8.4.6.3
173              if(!m.mayOverrideReturn(decl))
174                target.error("the return type of method " + m.signature() + " in " + m.hostType().typeName() + " does not match the return type of method " + decl.signature() + " in " + decl.hostType().typeName() + " and may thus not be overriden");
175     
176              // regardless of overriding
177              // 8.4.4
178              for(int i = 0; i < m.getNumException(); i++) {
179                Access e = m.getException(i);
180                boolean found = false;
181                for(int j = 0; !found && j < decl.getNumException(); j++) {
182                  if(e.type().instanceOf(decl.getException(j).type()))
183                    found = true;
184                }
185                if(!found && e.type().isUncheckedException())
186                  target.error(m.signature() + " in " + m.hostType().typeName() + " may not throw more checked exceptions than overridden method " +
187                   decl.signature() + " in " + decl.hostType().typeName());
188              }
189              // 8.4.6.3
190              if(decl.isPublic() && !m.isPublic())
191                target.error("overriding access modifier error");
192              // 8.4.6.3
193              if(decl.isProtected() && !(m.isPublic() || m.isProtected()))
194                target.error("overriding access modifier error");
195              // 8.4.6.3
196              if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate())
197                target.error("overriding access modifier error");
198     
199              // regardless of overriding
200              if(decl.isFinal())
201                target.error("method " + m.signature() + " in " + hostType().typeName() + " can not override final method " + decl.signature() + " in " + decl.hostType().typeName());
202            }
203            if(m.hides(decl)) {
204              // 8.4.6.2
205              if(m.isStatic() && !decl.isStatic())
206                target.error("a static method may not hide an instance method");
207              // 8.4.6.3
208              if(!m.mayOverrideReturn(decl))
209                target.error("can not hide a method with a different return type");
210              // 8.4.4
211              for(int i = 0; i < m.getNumException(); i++) {
212                Access e = m.getException(i);
213                boolean found = false;
214                for(int j = 0; !found && j < decl.getNumException(); j++) {
215                  if(e.type().instanceOf(decl.getException(j).type()))
216                    found = true;
217                }
218                if(!found)
219                  target.error("may not throw more checked exceptions than hidden method");
220              }
221              // 8.4.6.3
222              if(decl.isPublic() && !m.isPublic())
223                target.error("hiding access modifier error: public method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by non public method " + m.signature() + " in " + m.hostType().typeName());
224              // 8.4.6.3
225              if(decl.isProtected() && !(m.isPublic() || m.isProtected()))
226                target.error("hiding access modifier error: protected method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by non (public|protected) method " + m.signature() + " in " + m.hostType().typeName());
227              // 8.4.6.3
228              if((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate())
229                target.error("hiding access modifier error: default method " + decl.signature() + " in " + decl.hostType().typeName() + " is hidden by private method " + m.signature() + " in " + m.hostType().typeName());
230              if(decl.isFinal())
231                target.error("method " + m.signature() + " in " + hostType().typeName() + " can not hide final method " + decl.signature() + " in " + decl.hostType().typeName());
232            }
233          }
234        }
235      }
236    
237      syn boolean MethodDecl.mayOverrideReturn(MethodDecl m) = type() == m.type();
238    
239      public void ClassDecl.nameCheck() {
240        super.nameCheck();
241        if(hasSuperClassAccess() && !getSuperClassAccess().type().isClassDecl())
242          error("class may only inherit a class and not " + getSuperClassAccess().type().typeName());
243        if(isObject() && hasSuperClassAccess())
244          error("class Object may not have superclass");
245        if(isObject() && getNumImplements() != 0)
246          error("class Object may not implement interfaces");
247        
248        // 8.1.3
249        if(isCircular())
250          error("circular inheritance dependency in " + typeName()); 
251          
252        // 8.1.4
253        HashSet set = new HashSet();
254        for(int i = 0; i < getNumImplements(); i++) {
255          TypeDecl decl = getImplements(i).type();
256          if(!decl.isInterfaceDecl() && !decl.isUnknown())
257            error("type " + fullName() + " tries to implement non interface type " + decl.fullName());
258          if(set.contains(decl))
259            error("type " + decl.fullName() + " mentionened multiple times in implements clause");
260          set.add(decl);
261        }
262    
263        for(Iterator iter = interfacesMethodsIterator(); iter.hasNext(); ) {
264          MethodDecl m = (MethodDecl)iter.next();
265          if(localMethodsSignature(m.signature()).isEmpty()) {
266            SimpleSet s = superclass().methodsSignature(m.signature());
267            for(Iterator i2 = s.iterator(); i2.hasNext(); ) {
268              MethodDecl n = (MethodDecl)i2.next();
269              if(n.accessibleFrom(this)) {
270                interfaceMethodCompatibleWithInherited(m, n);
271              }
272            }
273            if(s.isEmpty()) {
274              for(Iterator i2 = interfacesMethodsSignature(m.signature()).iterator(); i2.hasNext(); ) {
275                MethodDecl n = (MethodDecl)i2.next();
276                if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(n))
277                  error("Xthe return type of method " + m.signature() + " in " + m.hostType().typeName() + 
278                      " does not match the return type of method " + n.signature() + " in " + 
279                      n.hostType().typeName() + " and may thus not be overriden");
280              }
281            }
282          }
283        }
284      }
285    
286      private void ClassDecl.interfaceMethodCompatibleWithInherited(MethodDecl m, MethodDecl n) {
287        if(n.isStatic())
288          error("Xa static method may not hide an instance method");
289        if(!n.isAbstract() && !n.isPublic())
290          error("Xoverriding access modifier error for " + m.signature() + " in " + m.hostType().typeName() + " and " + n.hostType().typeName());
291        if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(m))
292          error("Xthe return type of method " + m.signature() + " in " + m.hostType().typeName() + 
293                " does not match the return type of method " + n.signature() + " in " + 
294                n.hostType().typeName() + " and may thus not be overriden");
295        if(!n.isAbstract()) {
296          // n implements and overrides method m in the interface
297          // may not throw more checked exceptions
298          for(int i = 0; i < n.getNumException(); i++) {
299            Access e = n.getException(i);
300            boolean found = false;
301            for(int j = 0; !found && j < m.getNumException(); j++) {
302              if(e.type().instanceOf(m.getException(j).type()))
303                found = true;
304            }
305            if(!found && e.type().isUncheckedException())
306              error("X" + n.signature() + " in " + n.hostType().typeName() + " may not throw more checked exceptions than overridden method " +
307               m.signature() + " in " + m.hostType().typeName());
308          }
309        }
310      }
311    
312      public void InterfaceDecl.nameCheck() {
313        super.nameCheck();
314        if(isCircular())
315          error("circular inheritance dependency in " + typeName()); 
316        else {
317          for(int i = 0; i < getNumSuperInterfaceId(); i++) {
318            TypeDecl typeDecl = getSuperInterfaceId(i).type();
319            if(typeDecl.isCircular())
320              error("circular inheritance dependency in " + typeName()); 
321          }
322        }
323        for(Iterator iter = methodsSignatureMap().values().iterator(); iter.hasNext(); ) {
324          SimpleSet set = (SimpleSet)iter.next();
325          if(set.size() > 1) {
326            Iterator i2 = set.iterator();
327            MethodDecl m = (MethodDecl)i2.next();
328            while(i2.hasNext()) {
329              MethodDecl n = (MethodDecl)i2.next();
330              if(!n.mayOverrideReturn(m) && !m.mayOverrideReturn(n))
331                error("multiply inherited methods with the same signature must have the same return type");
332            }
333          }
334        }
335      }
336    }
337    
338