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 BoundNames {
032      public Access FieldDeclaration.createQualifiedBoundAccess() {
033        if (isStatic()) {
034          return hostType().createQualifiedAccess().qualifiesAccess(new BoundFieldAccess(this));
035        } else
036          return new ThisAccess("this").qualifiesAccess(
037            new BoundFieldAccess(this));
038      }
039    
040      // The memberMethods(String name) attribute is used to lookup member methods.
041      // It uses the methodsNameMap() map where a name is mapped to a list of member
042      // methods. We extend the map with the declaration m by either appending
043      // it to an existing list of declarations or adding a new list. That list
044      // will be used to name bind a new qualified name access.
045      public MethodDecl TypeDecl.addMemberMethod(MethodDecl m) {
046        addBodyDecl(m);
047        return (MethodDecl) getBodyDecl(getNumBodyDecl()-1);
048        /*
049        HashMap map = methodsNameMap();
050        ArrayList list = (ArrayList) map.get(m.name());
051        if (list == null) {
052          list = new ArrayList(4);
053          map.put(m.name(), list);
054        }
055        list.add(m);
056        if (!memberMethods(m.name()).contains(m)) {
057          throw new Error("The method " + m.signature() + " added to " + typeName() + " can not be found using lookupMemberMethod");
058        }
059        */
060      }
061    
062      public ConstructorDecl TypeDecl.addConstructor(ConstructorDecl c) {
063        addBodyDecl(c);
064        return (ConstructorDecl) getBodyDecl(getNumBodyDecl()-1);
065      }
066    
067      public ClassDecl TypeDecl.addMemberClass(ClassDecl c) {
068        addBodyDecl(new MemberClassDecl(c));
069        return ((MemberClassDecl) getBodyDecl(getNumBodyDecl()-1)).getClassDecl();
070      }
071    
072    
073      // the new field must be unique otherwise an error occurs
074      public FieldDeclaration TypeDecl.addMemberField(FieldDeclaration f) {
075        addBodyDecl(f);
076        return (FieldDeclaration) getBodyDecl(getNumBodyDecl()-1);
077      }
078    
079      // A BoundMethodAccess is a MethodAccess where the name analysis is bypassed by explicitly setting the desired binding
080      // this is useful when name binding is cached and recomputation is undesired
081      public BoundMethodAccess.BoundMethodAccess(String name, List args, MethodDecl methodDecl) {
082        this(name, args);
083        this.methodDecl = methodDecl;
084      }
085      private MethodDecl BoundMethodAccess.methodDecl;
086      eq BoundMethodAccess.decl() = methodDecl;
087    
088      public BoundFieldAccess.BoundFieldAccess(FieldDeclaration f) {
089        this(f.name(), f);
090      }
091    
092      eq BoundFieldAccess.decl() = getFieldDeclaration();
093      public boolean BoundFieldAccess.isExactVarAccess() {
094        return false;
095      }
096    
097      public Access MethodDecl.createBoundAccess(List args) {
098        if (isStatic()) {
099          return hostType().createQualifiedAccess().qualifiesAccess(
100            new BoundMethodAccess(name(), args, this)
101          );
102        }
103        return new BoundMethodAccess(name(), args, this);
104      }
105    
106      public Access FieldDeclaration.createBoundFieldAccess() {
107        return createQualifiedBoundAccess();
108      }
109    
110      public TypeAccess TypeDecl.createBoundAccess() {
111        return new BoundTypeAccess("", name(), this);
112      }
113      eq BoundTypeAccess.decls() = SimpleSet.emptySet.add(getTypeDecl());
114    
115      rewrite BytecodeTypeAccess {
116        to Access {
117          if (name().indexOf("$") == -1) {
118            return new TypeAccess(packageName(), name());
119          } else {
120            String[] names = name().split("\\$");
121            Access a = null; // the resulting access
122            String newName = null; // the subname to try
123            TypeDecl type = null; // qualifying type if one
124            for (int i = 0; i < names.length; i++) {
125              newName = newName == null ? names[i] : (newName + "$" + names[i]);
126              SimpleSet set;
127              if (type != null) {
128                set = type.memberTypes(newName);
129              } else if (packageName().equals("")) {
130                set = lookupType(newName);
131              } else {
132                set = lookupType(packageName(), newName).asSet();
133              }
134              if (!set.isEmpty()) {
135                a = a == null ? (Access) new TypeAccess(packageName(), newName) : (Access) a.qualifiesAccess(new TypeAccess(newName));
136                type = (TypeDecl) set.iterator().next();
137                newName = null; // reset subname
138              }
139            }
140            if (a == null) {
141              a = new TypeAccess(packageName(), name());
142            }
143            return a;
144          }
145        }
146      }
147    }