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 GenericTypeVariables {
032    
033      // The bounds of a type variable should be resolved to type names
034      eq TypeVariable.getTypeBound().nameType() = NameType.TYPE_NAME;
035    
036      rewrite TypeVariable {
037        when (getNumTypeBound() == 0)
038        to TypeVariable {
039          addTypeBound(
040            new TypeAccess(
041              "java.lang",
042              "Object"
043            )
044          );
045          return this;
046        }
047      }
048    
049      public void TypeVariable.nameCheck() {
050        if (extractSingleType(lookupType(name())) != this) {
051          errorf("*** Semantic Error: type variable %s is multiply declared", name());
052        }
053      }
054    
055      syn TypeDecl TypeVariable.lowerBound() = getTypeBound(0).type();
056    
057    }
058    
059    aspect GenericTypeVariablesMembers {
060      eq TypeVariable.memberMethods(String name) {
061        Collection list = new HashSet();
062        for (int i = 0; i < getNumTypeBound(); i++) {
063          for (Iterator iter = getTypeBound(i).type().memberMethods(name).iterator(); iter.hasNext(); ) {
064            MethodDecl decl = (MethodDecl) iter.next();
065            list.add(decl);
066          }
067        }
068        return list;
069      }
070    
071      eq TypeVariable.memberFields(String name) {
072        SimpleSet set = SimpleSet.emptySet;
073        for (int i = 0; i < getNumTypeBound(); i++) {
074          for (Iterator iter = getTypeBound(i).type().memberFields(name).iterator(); iter.hasNext(); ) {
075            FieldDeclaration decl = (FieldDeclaration) iter.next();
076            set = set.add(decl);
077          }
078        }
079        return set;
080      }
081    
082    }
083    
084    aspect GenricTypeVariablesTypeAnalysis {
085    
086      public void TypeVariable.typeCheck() {
087        if (!getTypeBound(0).type().isTypeVariable() && !getTypeBound(0).type().isClassDecl()
088            && !getTypeBound(0).type().isInterfaceDecl()) {
089          errorf("the first type bound must be either a type variable,"
090              + " or a class or interface type which %s is not",
091              getTypeBound(0).type().fullName());
092        }
093        for (int i = 1; i < getNumTypeBound(); i++) {
094          if (!getTypeBound(i).type().isInterfaceDecl()) {
095            errorf("type bound %s must be an interface type which %s is not",
096                i, getTypeBound(i).type().fullName());
097          }
098        }
099        HashSet typeSet = new HashSet();
100        for (int i = 0; i < getNumTypeBound(); i++) {
101          TypeDecl type = getTypeBound(i).type();
102          TypeDecl erasure = type.erasure();
103          if (typeSet.contains(erasure)) {
104            if (type != erasure) {
105              errorf("the erasure %s of typebound %s is multiply declared in %s",
106                  erasure.fullName(), getTypeBound(i).prettyPrint(), this);
107            } else {
108              errorf("%s is multiply declared", type.fullName());
109            }
110          }
111          typeSet.add(erasure);
112        }
113    
114        for (int i = 0; i < getNumTypeBound(); i++) {
115          TypeDecl type = getTypeBound(i).type();
116          for (Iterator iter = type.methodsIterator(); iter.hasNext(); ) {
117            MethodDecl m = (MethodDecl) iter.next();
118            for (int j = i+1; j < getNumTypeBound(); j++) {
119              TypeDecl destType = getTypeBound(j).type();
120              for (Iterator destIter = destType.memberMethods(m.name()).iterator(); destIter.hasNext(); ) {
121                MethodDecl n = (MethodDecl) destIter.next();
122                if (m.sameSignature(n) && m.type() != n.type()) {
123                  errorf("the two bounds, %s and %s, in type variable %s have"
124                      + " a method %s with conflicting return types %s and %s",
125                      type.name(), destType.name(), name(), m.signature(),
126                      m.type().name(), n.type().name());
127                }
128              }
129            }
130          }
131        }
132    
133    
134      }
135    
136    
137    }