001    /* Copyright (c) 2011, Jesper Öqvist <jesper.oqvist@cs.lth.se>
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    /**
032     * This aspect adds the Project Coin/JSR 334 Strings in Switch language change
033     * to the ExtendJ frontend.
034     *
035     * <p>The following features were modified:
036     * <ul>
037     * <li>type checking of the switch expression</li>
038     * <li>duplicate checking of switch labels</li>
039     * </ul>
040     */
041    aspect StringsInSwitch {
042      /**
043       * Overrides the type checking of the switch statement's expression.
044       *
045       * <p>In JSR 334 a switch statement may use an expression of type String.
046       */
047      refine Enums public void SwitchStmt.typeCheck() {
048        TypeDecl type = getExpr().type();
049        if ((!type.isIntegralType() || type.isLong()) && !type.isEnumDecl() && !type.isString()) {
050          error("Switch expression must be of type char, byte, short, int, enum, or string");
051        }
052      }
053    
054      /* Type checking for case labels need not be changed as it
055       * already tests if the case labels have expressions which are
056       * assignable to the switch expression
057       */
058    
059      syn boolean Case.isDefaultCase() = false;
060      eq DefaultCase.isDefaultCase() = true;
061    
062      /**
063       * This attribute overrides the default duplicate checking for
064       * switch case labels.
065       */
066      refine Enums eq ConstCase.constValue(Case c) {
067        if (isDefaultCase() || c.isDefaultCase()) {
068          return isDefaultCase() && c.isDefaultCase();
069        }
070    
071        Expr myValue = getValue();
072        Expr otherValue = ((ConstCase) c).getValue();
073        TypeDecl myType = myValue.type();
074        TypeDecl otherType = otherValue.type();
075        if (myType.isString() || otherType.isString()) {
076          if (!myType.isString() || !otherType.isString()) {
077            return false;
078          }
079          if (!myValue.isConstant() || !otherValue.isConstant()) {
080            return false;
081          }
082          return myValue.constant().stringValue().equals(otherValue.constant().stringValue());
083        }
084    
085        return refined(c);
086      }
087    
088      /**
089       * Improve the type checking error messages given for case labels.
090       */
091      refine Enums public void ConstCase.typeCheck() {
092        boolean isEnumConstant = getValue().isEnumConstant();
093        TypeDecl switchType = switchType();
094        TypeDecl type = getValue().type();
095        if (switchType.isEnumDecl() && !isEnumConstant) {
096          error("Unqualified enumeration constant required");
097        }
098        if (!type.assignConversionTo(switchType, getValue())) {
099          errorf("Case label has incompatible type %s, expected type compatible with %s",
100              switchType.name(), type.name());
101        }
102        if (!getValue().isConstant() && !getValue().type().isUnknown() && !isEnumConstant) {
103          error("Case label must have constant expression");
104        }
105      }
106    
107    }