001    /* Copyright (c) 2014, Erik Hogeman <Erik.Hogemn@gmail.com>
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     *     * Redistributions of source code must retain the above copyright notice,
008     *       this list of conditions and the following disclaimer.
009     *     * Redistributions in binary form must reproduce the above copyright
010     *       notice, this list of conditions and the following disclaimer in the
011     *       documentation and/or other materials provided with the distribution.
012     *     * Neither the name of the Lund University nor the names of its
013     *       contributors may be used to endorse or promote products derived from
014     *       this software without specific prior written permission.
015     *
016     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
017     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
020     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
021     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
022     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
023     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
024     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
025     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
026     * POSSIBILITY OF SUCH DAMAGE.
027     */
028    
029    aspect Java8TypeHierarchyCheck {
030      refine GenericsTypeCheck
031      public void TypeDecl.typeCheck() {
032      // 8.4.6.4 & 9.4.1
033        for (Iterator iter1 = localMethodsIterator(); iter1.hasNext(); ) {
034          MethodDecl m = (MethodDecl)iter1.next();
035          ASTNode target = m.hostType() == this ? (ASTNode)m : (ASTNode)this;
036    
037          for (Iterator i2 = ancestorMethods(m.signature()).iterator(); i2.hasNext(); ) {
038            MethodDecl decl = (MethodDecl)i2.next();
039            if (m.overrides(decl)) {
040              // 8.4.6.1
041              if (!decl.hostType().isInterfaceDecl() && !m.isStatic() && decl.isStatic()) {
042                target.error("an instance method may not override a static method");
043              }
044    
045              // regardless of overriding
046              // 8.4.6.3
047              if (!m.mayOverride(decl)) {
048                // 9.4.3
049                if (m.isDefault() && decl.hostType() == m.type().typeObject() && !decl.isPrivate()) {
050                  target.error("default methods may not override methods in Object");
051                } else {
052                  target.errorf("the return type of method %s in %s does not match the return type of"
053                      + " method %s in %s and may thus not be overridden",
054                      m.fullSignature(), m.hostType().typeName(), decl.fullSignature(),
055                      decl.hostType().typeName());
056                }
057              }
058    
059              // regardless of overriding
060              // 8.4.4
061              for (Access e: m.getExceptionList()) {
062                if (e.type().isCheckedException()) {
063                  boolean found = false;
064                  for (Access declException: decl.getExceptionList()) {
065                    if (e.type().instanceOf(declException.type())) {
066                      found = true;
067                      break;
068                    }
069                  }
070                  if (!found) {
071                    target.errorf("%s in %s may not throw more checked exceptions than"
072                        + " overridden method %s in %s",
073                        m.fullSignature(), m.hostType().typeName(), decl.fullSignature(),
074                        decl.hostType().typeName());
075                  }
076                }
077              }
078    
079              // 8.4.6.3
080              if (decl.isPublic() && !m.isPublic()) {
081                target.error("overriding access modifier error");
082              }
083              // 8.4.6.3
084              if (decl.isProtected() && !(m.isPublic() || m.isProtected())) {
085                target.error("overriding access modifier error");
086              }
087              // 8.4.6.3
088              if ((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) {
089                target.error("overriding access modifier error");
090              }
091              // regardless of overriding
092              if (decl.isFinal()) {
093                target.errorf("method %s in %s can not override final method %s in %s",
094                    m.fullSignature(), hostType().typeName(), decl.fullSignature(),
095                    decl.hostType().typeName());
096              }
097            }
098            if (m.hides(decl)) {
099              // 8.4.6.2
100              if (m.isStatic() && !decl.isStatic()) {
101                target.error("a static method may not hide an instance method");
102              }
103              // 8.4.6.3
104              if (!m.mayOverride(decl)) {
105                target.error("can not hide a method with a different return type");
106              }
107              // 8.4.4
108              for (int i = 0; i < m.getNumException(); i++) {
109                Access e = m.getException(i);
110                boolean found = false;
111                for (int j = 0; !found && j < decl.getNumException(); j++) {
112                  if (e.type().instanceOf(decl.getException(j).type())) {
113                    found = true;
114                  }
115                }
116                if (!found) {
117                  target.error("may not throw more checked exceptions than hidden method");
118                }
119              }
120              // 8.4.6.3
121              if (decl.isPublic() && !m.isPublic()) {
122                target.errorf("hiding access modifier: public method %s in %s is hidden by"
123                    + " non public method %s in %s",
124                    decl.fullSignature(), decl.hostType().typeName(), m.fullSignature(),
125                    m.hostType().typeName());
126              }
127              // 8.4.6.3
128              if (decl.isProtected() && !(m.isPublic() || m.isProtected())) {
129                target.errorf("hiding access modifier: protected method %s in %s is hidden by"
130                    + " non (public|protected) method %s in %s",
131                    decl.fullSignature(), decl.hostType().typeName(), m.fullSignature(),
132                    m.hostType().typeName());
133              }
134              // 8.4.6.3
135              if ((!decl.isPrivate() && !decl.isProtected() && !decl.isPublic()) && m.isPrivate()) {
136                target.errorf("hiding access modifier: default method %s in %s is hidden by"
137                    + " private method %s in %s",
138                    decl.fullSignature(), decl.hostType().typeName(), m.fullSignature(),
139                    m.hostType().typeName());
140              }
141              if (decl.isFinal()) {
142                target.errorf("method %s in %s can not hide final method %s in %s",
143                    m.fullSignature(), hostType().typeName(), decl.fullSignature(),
144                    decl.hostType().typeName());
145              }
146            }
147          }
148        }
149    
150    
151        // different parameterizations of the same generic interface may not be implemented
152        ArrayList list = new ArrayList();
153        list.addAll(implementedInterfaces());
154        for (int i = 0; i < list.size(); i++) {
155          InterfaceDecl decl = (InterfaceDecl)list.get(i);
156          if (decl instanceof ParInterfaceDecl) {
157            ParInterfaceDecl p = (ParInterfaceDecl)decl;
158            for (Iterator i2 = list.listIterator(i); i2.hasNext(); ) {
159              InterfaceDecl decl2 = (InterfaceDecl)i2.next();
160              if (decl2 instanceof ParInterfaceDecl) {
161                ParInterfaceDecl q = (ParInterfaceDecl)decl2;
162                if (p != q && p.genericDecl() == q.genericDecl() && !p.sameArgument(q)) {
163                  errorf("%s cannot be inherited with different type arguments: %s and %s",
164                      p.genericDecl().name(), p.typeName(), q.typeName());
165                }
166              }
167            }
168          }
169        }
170      }
171    }