7017664: Add listeners infrastracture to javac scopes

Tue, 15 Feb 2011 11:49:46 +0000

author
mcimadamore
date
Tue, 15 Feb 2011 11:49:46 +0000
changeset 877
351027202f60
parent 876
ef6c66215a93
child 878
fa0e4e1916f4

7017664: Add listeners infrastracture to javac scopes
Summary: Add listeners to javac scopes, added CompoundScope and correct invalidation logic for ImplementationCache
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/code/Scope.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/code/Symbol.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/code/Types.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Check.java file | annotate | diff | comparison | revisions
test/tools/javac/scope/7017664/CompoundScopeTest.java file | annotate | diff | comparison | revisions
test/tools/javac/scope/7017664/ImplementationCacheTest.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Scope.java	Mon Feb 14 14:27:47 2011 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Scope.java	Tue Feb 15 11:49:46 2011 +0000
     1.3 @@ -74,7 +74,7 @@
     1.4  
     1.5      /** A list of scopes to be notified if items are to be removed from this scope.
     1.6       */
     1.7 -    List<Scope> listeners = List.nil();
     1.8 +    List<ScopeListener> listeners = List.nil();
     1.9  
    1.10      /** Use as a "not-found" result for lookup.
    1.11       * Also used to mark deleted entries in the table.
    1.12 @@ -219,12 +219,27 @@
    1.13          Entry e = makeEntry(sym, old, elems, s, origin);
    1.14          table[hash] = e;
    1.15          elems = e;
    1.16 +
    1.17 +        //notify listeners
    1.18 +        for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
    1.19 +            l.head.symbolAdded(sym, this);
    1.20 +        }
    1.21      }
    1.22  
    1.23      Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
    1.24          return new Entry(sym, shadowed, sibling, scope);
    1.25      }
    1.26  
    1.27 +
    1.28 +    public interface ScopeListener {
    1.29 +        public void symbolAdded(Symbol sym, Scope s);
    1.30 +        public void symbolRemoved(Symbol sym, Scope s);
    1.31 +    }
    1.32 +
    1.33 +    public void addScopeListener(ScopeListener sl) {
    1.34 +        listeners = listeners.prepend(sl);
    1.35 +    }
    1.36 +
    1.37      /** Remove symbol from this scope.  Used when an inner class
    1.38       *  attribute tells us that the class isn't a package member.
    1.39       */
    1.40 @@ -258,9 +273,9 @@
    1.41              te = te.sibling;
    1.42          }
    1.43  
    1.44 -        // remove items from scopes that have done importAll
    1.45 -        for (List<Scope> l = listeners; l.nonEmpty(); l = l.tail) {
    1.46 -            l.head.remove(sym);
    1.47 +        //notify listeners
    1.48 +        for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
    1.49 +            l.head.symbolRemoved(sym, this);
    1.50          }
    1.51      }
    1.52  
    1.53 @@ -393,7 +408,32 @@
    1.54                  };
    1.55              }
    1.56          };
    1.57 +    }
    1.58  
    1.59 +    public Iterable<Symbol> getElementsByName(Name name) {
    1.60 +        return getElementsByName(name, noFilter);
    1.61 +    }
    1.62 +
    1.63 +    public Iterable<Symbol> getElementsByName(final Name name, final Filter<Symbol> sf) {
    1.64 +        return new Iterable<Symbol>() {
    1.65 +            public Iterator<Symbol> iterator() {
    1.66 +                 return new Iterator<Symbol>() {
    1.67 +                    Scope.Entry currentEntry = lookup(name, sf);
    1.68 +
    1.69 +                    public boolean hasNext() {
    1.70 +                        return currentEntry.scope != null;
    1.71 +                    }
    1.72 +                    public Symbol next() {
    1.73 +                        Scope.Entry prevEntry = currentEntry;
    1.74 +                        currentEntry = currentEntry.next(sf);
    1.75 +                        return prevEntry.sym;
    1.76 +                    }
    1.77 +                    public void remove() {
    1.78 +                        throw new UnsupportedOperationException();
    1.79 +                    }
    1.80 +                };
    1.81 +            }
    1.82 +        };
    1.83      }
    1.84  
    1.85      public String toString() {
    1.86 @@ -488,7 +528,7 @@
    1.87          }
    1.88      }
    1.89  
    1.90 -    public static class StarImportScope extends ImportScope {
    1.91 +    public static class StarImportScope extends ImportScope implements ScopeListener {
    1.92  
    1.93          public StarImportScope(Symbol owner) {
    1.94              super(owner);
    1.95 @@ -500,8 +540,13 @@
    1.96                      enter(e.sym, fromScope);
    1.97              }
    1.98              // Register to be notified when imported items are removed
    1.99 -            fromScope.listeners = fromScope.listeners.prepend(this);
   1.100 +            fromScope.addScopeListener(this);
   1.101          }
   1.102 +
   1.103 +        public void symbolRemoved(Symbol sym, Scope s) {
   1.104 +            remove(sym);
   1.105 +        }
   1.106 +        public void symbolAdded(Symbol sym, Scope s) { }
   1.107      }
   1.108  
   1.109      /** An empty scope, into which you can't place anything.  Used for
   1.110 @@ -538,6 +583,151 @@
   1.111          }
   1.112      }
   1.113  
   1.114 +    /** A class scope adds capabilities to keep track of changes in related
   1.115 +     *  class scopes - this allows client to realize whether a class scope
   1.116 +     *  has changed, either directly (because a new member has been added/removed
   1.117 +     *  to this scope) or indirectly (i.e. because a new member has been
   1.118 +     *  added/removed into a supertype scope)
   1.119 +     */
   1.120 +    public static class CompoundScope extends Scope implements ScopeListener {
   1.121 +
   1.122 +        public static final Entry[] emptyTable = new Entry[0];
   1.123 +
   1.124 +        private List<Scope> subScopes = List.nil();
   1.125 +        private int mark = 0;
   1.126 +
   1.127 +        public CompoundScope(Symbol owner) {
   1.128 +            super(null, owner, emptyTable);
   1.129 +        }
   1.130 +
   1.131 +        public void addSubScope(Scope that) {
   1.132 +           if (that != null) {
   1.133 +                subScopes = subScopes.prepend(that);
   1.134 +                that.addScopeListener(this);
   1.135 +                mark++;
   1.136 +                for (ScopeListener sl : listeners) {
   1.137 +                    sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes
   1.138 +                }
   1.139 +           }
   1.140 +         }
   1.141 +
   1.142 +        public void symbolAdded(Symbol sym, Scope s) {
   1.143 +            mark++;
   1.144 +            for (ScopeListener sl : listeners) {
   1.145 +                sl.symbolAdded(sym, s);
   1.146 +            }
   1.147 +        }
   1.148 +
   1.149 +        public void symbolRemoved(Symbol sym, Scope s) {
   1.150 +            mark++;
   1.151 +            for (ScopeListener sl : listeners) {
   1.152 +                sl.symbolRemoved(sym, s);
   1.153 +            }
   1.154 +        }
   1.155 +
   1.156 +        public int getMark() {
   1.157 +            return mark;
   1.158 +        }
   1.159 +
   1.160 +        @Override
   1.161 +        public String toString() {
   1.162 +            StringBuilder buf = new StringBuilder();
   1.163 +            buf.append("CompoundScope{");
   1.164 +            String sep = "";
   1.165 +            for (Scope s : subScopes) {
   1.166 +                buf.append(sep);
   1.167 +                buf.append(s);
   1.168 +                sep = ",";
   1.169 +            }
   1.170 +            buf.append("}");
   1.171 +            return buf.toString();
   1.172 +        }
   1.173 +
   1.174 +        @Override
   1.175 +        public Iterable<Symbol> getElements(final Filter<Symbol> sf) {
   1.176 +            return new Iterable<Symbol>() {
   1.177 +                public Iterator<Symbol> iterator() {
   1.178 +                    return new CompoundScopeIterator(subScopes) {
   1.179 +                        Iterator<Symbol> nextIterator(Scope s) {
   1.180 +                            return s.getElements().iterator();
   1.181 +                        }
   1.182 +                    };
   1.183 +                }
   1.184 +            };
   1.185 +        }
   1.186 +
   1.187 +        @Override
   1.188 +        public Iterable<Symbol> getElementsByName(final Name name, final Filter<Symbol> sf) {
   1.189 +            return new Iterable<Symbol>() {
   1.190 +                public Iterator<Symbol> iterator() {
   1.191 +                    return new CompoundScopeIterator(subScopes) {
   1.192 +                        Iterator<Symbol> nextIterator(Scope s) {
   1.193 +                            return s.getElementsByName(name, sf).iterator();
   1.194 +                        }
   1.195 +                    };
   1.196 +                }
   1.197 +            };
   1.198 +        }
   1.199 +
   1.200 +        abstract class CompoundScopeIterator implements Iterator<Symbol> {
   1.201 +
   1.202 +            private Iterator<Symbol> currentIterator;
   1.203 +            private List<Scope> scopesToScan;
   1.204 +
   1.205 +            public CompoundScopeIterator(List<Scope> scopesToScan) {
   1.206 +                this.scopesToScan = scopesToScan;
   1.207 +                update();
   1.208 +            }
   1.209 +
   1.210 +            abstract Iterator<Symbol> nextIterator(Scope s);
   1.211 +
   1.212 +            public boolean hasNext() {
   1.213 +                return currentIterator != null;
   1.214 +            }
   1.215 +
   1.216 +            public Symbol next() {
   1.217 +                Symbol sym = currentIterator.next();
   1.218 +                if (!currentIterator.hasNext()) {
   1.219 +                    update();
   1.220 +                }
   1.221 +                return sym;
   1.222 +            }
   1.223 +
   1.224 +            public void remove() {
   1.225 +                throw new UnsupportedOperationException();
   1.226 +            }
   1.227 +
   1.228 +            private void update() {
   1.229 +                while (scopesToScan.nonEmpty()) {
   1.230 +                    currentIterator = nextIterator(scopesToScan.head);
   1.231 +                    scopesToScan = scopesToScan.tail;
   1.232 +                    if (currentIterator.hasNext()) return;
   1.233 +                }
   1.234 +                currentIterator = null;
   1.235 +            }
   1.236 +        }
   1.237 +
   1.238 +        @Override
   1.239 +        public Entry lookup(Name name, Filter<Symbol> sf) {
   1.240 +            throw new UnsupportedOperationException();
   1.241 +        }
   1.242 +
   1.243 +        @Override
   1.244 +        public Scope dup(Symbol newOwner) {
   1.245 +            throw new UnsupportedOperationException();
   1.246 +        }
   1.247 +
   1.248 +        @Override
   1.249 +        public void enter(Symbol sym, Scope s, Scope origin) {
   1.250 +            throw new UnsupportedOperationException();
   1.251 +        }
   1.252 +
   1.253 +        @Override
   1.254 +        public void remove(Symbol sym) {
   1.255 +            throw new UnsupportedOperationException();
   1.256 +        }
   1.257 +    }
   1.258 +
   1.259      /** An error scope, for which the owner should be an error symbol. */
   1.260      public static class ErrorScope extends Scope {
   1.261          ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
     2.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Mon Feb 14 14:27:47 2011 -0800
     2.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Feb 15 11:49:46 2011 +0000
     2.3 @@ -731,7 +731,7 @@
     2.4  
     2.5          /** members closure cache (set by Types.membersClosure)
     2.6           */
     2.7 -        Scope membersClosure;
     2.8 +        Scope.CompoundScope membersClosure;
     2.9  
    2.10          public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
    2.11              super(flags, name, type, owner);
     3.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Feb 14 14:27:47 2011 -0800
     3.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Feb 15 11:49:46 2011 +0000
     3.3 @@ -2023,18 +2023,22 @@
     3.4              final MethodSymbol cachedImpl;
     3.5              final Filter<Symbol> implFilter;
     3.6              final boolean checkResult;
     3.7 +            final int prevMark;
     3.8  
     3.9              public Entry(MethodSymbol cachedImpl,
    3.10                      Filter<Symbol> scopeFilter,
    3.11 -                    boolean checkResult) {
    3.12 +                    boolean checkResult,
    3.13 +                    int prevMark) {
    3.14                  this.cachedImpl = cachedImpl;
    3.15                  this.implFilter = scopeFilter;
    3.16                  this.checkResult = checkResult;
    3.17 +                this.prevMark = prevMark;
    3.18              }
    3.19  
    3.20 -            boolean matches(Filter<Symbol> scopeFilter, boolean checkResult) {
    3.21 +            boolean matches(Filter<Symbol> scopeFilter, boolean checkResult, int mark) {
    3.22                  return this.implFilter == scopeFilter &&
    3.23 -                        this.checkResult == checkResult;
    3.24 +                        this.checkResult == checkResult &&
    3.25 +                        this.prevMark == mark;
    3.26              }
    3.27          }
    3.28  
    3.29 @@ -2046,10 +2050,11 @@
    3.30                  _map.put(ms, new SoftReference<Map<TypeSymbol, Entry>>(cache));
    3.31              }
    3.32              Entry e = cache.get(origin);
    3.33 +            CompoundScope members = membersClosure(origin.type);
    3.34              if (e == null ||
    3.35 -                    !e.matches(implFilter, checkResult)) {
    3.36 -                MethodSymbol impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter);
    3.37 -                cache.put(origin, new Entry(impl, implFilter, checkResult));
    3.38 +                    !e.matches(implFilter, checkResult, members.getMark())) {
    3.39 +                MethodSymbol impl = implementationInternal(ms, origin, checkResult, implFilter);
    3.40 +                cache.put(origin, new Entry(impl, implFilter, checkResult, members.getMark()));
    3.41                  return impl;
    3.42              }
    3.43              else {
    3.44 @@ -2057,8 +2062,8 @@
    3.45              }
    3.46          }
    3.47  
    3.48 -        private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) {
    3.49 -            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) {
    3.50 +        private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) {
    3.51 +            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = supertype(t)) {
    3.52                  while (t.tag == TYPEVAR)
    3.53                      t = t.getUpperBound();
    3.54                  TypeSymbol c = t.tsym;
    3.55 @@ -2066,7 +2071,7 @@
    3.56                       e.scope != null;
    3.57                       e = e.next(implFilter)) {
    3.58                      if (e.sym != null &&
    3.59 -                             e.sym.overrides(ms, origin, types, checkResult))
    3.60 +                             e.sym.overrides(ms, origin, Types.this, checkResult))
    3.61                          return (MethodSymbol)e.sym;
    3.62                  }
    3.63              }
    3.64 @@ -2082,46 +2087,35 @@
    3.65      // </editor-fold>
    3.66  
    3.67      // <editor-fold defaultstate="collapsed" desc="compute transitive closure of all members in given site">
    3.68 -    public Scope membersClosure(Type site) {
    3.69 +    public CompoundScope membersClosure(Type site) {
    3.70          return membersClosure.visit(site);
    3.71      }
    3.72  
    3.73 -    UnaryVisitor<Scope> membersClosure = new UnaryVisitor<Scope>() {
    3.74 -
    3.75 -        public Scope visitType(Type t, Void s) {
    3.76 +    UnaryVisitor<CompoundScope> membersClosure = new UnaryVisitor<CompoundScope>() {
    3.77 +
    3.78 +        public CompoundScope visitType(Type t, Void s) {
    3.79              return null;
    3.80          }
    3.81  
    3.82          @Override
    3.83 -        public Scope visitClassType(ClassType t, Void s) {
    3.84 +        public CompoundScope visitClassType(ClassType t, Void s) {
    3.85              ClassSymbol csym = (ClassSymbol)t.tsym;
    3.86              if (csym.membersClosure == null) {
    3.87 -                Scope membersClosure = new Scope(csym);
    3.88 +                CompoundScope membersClosure = new CompoundScope(csym);
    3.89                  for (Type i : interfaces(t)) {
    3.90 -                    enterAll(visit(i), membersClosure);
    3.91 +                    membersClosure.addSubScope(visit(i));
    3.92                  }
    3.93 -                enterAll(visit(supertype(t)), membersClosure);
    3.94 -                enterAll(csym.members(), membersClosure);
    3.95 +                membersClosure.addSubScope(visit(supertype(t)));
    3.96 +                membersClosure.addSubScope(csym.members());
    3.97                  csym.membersClosure = membersClosure;
    3.98              }
    3.99              return csym.membersClosure;
   3.100          }
   3.101  
   3.102          @Override
   3.103 -        public Scope visitTypeVar(TypeVar t, Void s) {
   3.104 +        public CompoundScope visitTypeVar(TypeVar t, Void s) {
   3.105              return visit(t.getUpperBound());
   3.106          }
   3.107 -
   3.108 -        public void enterAll(Scope s, Scope to) {
   3.109 -            if (s == null) return;
   3.110 -            List<Symbol> syms = List.nil();
   3.111 -            for (Scope.Entry e = s.elems ; e != null ; e = e.sibling) {
   3.112 -                syms = syms.prepend(e.sym);
   3.113 -            }
   3.114 -            for (Symbol sym : syms) {
   3.115 -                to.enter(sym);
   3.116 -            }
   3.117 -        }
   3.118      };
   3.119      // </editor-fold>
   3.120  
     4.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Feb 14 14:27:47 2011 -0800
     4.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Feb 15 11:49:46 2011 +0000
     4.3 @@ -2106,32 +2106,32 @@
     4.4      void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
     4.5           ClashFilter cf = new ClashFilter(site);
     4.6           //for each method m1 that is a member of 'site'...
     4.7 -         for (Scope.Entry e1 = types.membersClosure(site).lookup(sym.name, cf) ;
     4.8 -                e1.scope != null ; e1 = e1.next(cf)) {
     4.9 +         for (Symbol s1 : types.membersClosure(site).getElementsByName(sym.name, cf)) {
    4.10              //...find another method m2 that is overridden (directly or indirectly)
    4.11              //by method 'sym' in 'site'
    4.12 -            for (Scope.Entry e2 = types.membersClosure(site).lookup(sym.name, cf) ;
    4.13 -                    e2.scope != null ; e2 = e2.next(cf)) {
    4.14 -                if (e1.sym == e2.sym || !sym.overrides(e2.sym, site.tsym, types, false)) continue;
    4.15 +            for (Symbol s2 : types.membersClosure(site).getElementsByName(sym.name, cf)) {
    4.16 +                if (s1 == s2 || !sym.overrides(s2, site.tsym, types, false)) continue;
    4.17                  //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
    4.18                  //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error
    4.19 -                if (!types.isSubSignature(sym.type, types.memberType(site, e1.sym)) &&
    4.20 -                        types.hasSameArgs(e1.sym.erasure(types), e2.sym.erasure(types))) {
    4.21 +                if (!types.isSubSignature(sym.type, types.memberType(site, s1)) &&
    4.22 +                        types.hasSameArgs(s1.erasure(types), s2.erasure(types))) {
    4.23                      sym.flags_field |= CLASH;
    4.24 -                    String key = e2.sym == sym ?
    4.25 +                    String key = s2 == sym ?
    4.26                              "name.clash.same.erasure.no.override" :
    4.27                              "name.clash.same.erasure.no.override.1";
    4.28                      log.error(pos,
    4.29                              key,
    4.30                              sym, sym.location(),
    4.31 -                            e1.sym, e1.sym.location(),
    4.32 -                            e2.sym, e2.sym.location());
    4.33 +                            s1, s1.location(),
    4.34 +                            s2, s2.location());
    4.35                      return;
    4.36                  }
    4.37              }
    4.38          }
    4.39      }
    4.40  
    4.41 +
    4.42 +
    4.43      /** Check that all static methods accessible from 'site' are
    4.44       *  mutually compatible (JLS 8.4.8).
    4.45       *
    4.46 @@ -2142,16 +2142,15 @@
    4.47      void checkHideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
    4.48          ClashFilter cf = new ClashFilter(site);
    4.49          //for each method m1 that is a member of 'site'...
    4.50 -        for (Scope.Entry e = types.membersClosure(site).lookup(sym.name, cf) ;
    4.51 -                e.scope != null ; e = e.next(cf)) {
    4.52 +        for (Symbol s : types.membersClosure(site).getElementsByName(sym.name, cf)) {
    4.53              //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
    4.54              //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
    4.55 -            if (!types.isSubSignature(sym.type, types.memberType(site, e.sym)) &&
    4.56 -                    types.hasSameArgs(e.sym.erasure(types), sym.erasure(types))) {
    4.57 +            if (!types.isSubSignature(sym.type, types.memberType(site, s)) &&
    4.58 +                    types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
    4.59                  log.error(pos,
    4.60                          "name.clash.same.erasure.no.hide",
    4.61                          sym, sym.location(),
    4.62 -                        e.sym, e.sym.location());
    4.63 +                        s, s.location());
    4.64                  return;
    4.65               }
    4.66           }
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/javac/scope/7017664/CompoundScopeTest.java	Tue Feb 15 11:49:46 2011 +0000
     5.3 @@ -0,0 +1,212 @@
     5.4 +/*
     5.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/*
    5.28 + * @test
    5.29 + * @bug 7017664
    5.30 + * @summary Basher for CompoundScopes
    5.31 + */
    5.32 +
    5.33 +import java.util.Random;
    5.34 +import java.util.Map;
    5.35 +import java.util.HashMap;
    5.36 +import com.sun.tools.javac.util.*;
    5.37 +import com.sun.tools.javac.code.*;
    5.38 +import com.sun.tools.javac.code.Scope.*;
    5.39 +import com.sun.tools.javac.code.Symbol.*;
    5.40 +import com.sun.tools.javac.file.JavacFileManager;
    5.41 +
    5.42 +public class CompoundScopeTest {
    5.43 +    public static void main(String... args) throws Exception {
    5.44 +        new CompoundScopeTest().run(args);
    5.45 +    }
    5.46 +
    5.47 +    static final int MAX_SYMBOLS_COUNT = 20;
    5.48 +    static final int PASSES = 10;
    5.49 +
    5.50 +    void run(String... args) throws Exception {
    5.51 +        int count = PASSES;
    5.52 +
    5.53 +        for (int i = 0; i < args.length; i++) {
    5.54 +            String arg = args[i];
    5.55 +            if (arg.equals("-seed") && (i + 1 < args.length))
    5.56 +                seed = Long.parseLong(args[++i]);
    5.57 +            else if(arg.equals("-tests") && (i + 1 < args.length))
    5.58 +                count = Integer.parseInt(args[++i]);
    5.59 +            else
    5.60 +                throw new Exception("unknown arg: " + arg);
    5.61 +        }
    5.62 +
    5.63 +        rgen = new Random(seed);
    5.64 +
    5.65 +        for (int i = 0; i < count; i++) {
    5.66 +            Test t = new Test();
    5.67 +            t.run();
    5.68 +        }
    5.69 +
    5.70 +        if (errors > 0)
    5.71 +            throw new Exception(errors + " errors found");
    5.72 +    }
    5.73 +
    5.74 +    /**
    5.75 +     * Write a message to stderr.
    5.76 +     */
    5.77 +    void log(String msg) {
    5.78 +        System.err.println(msg);
    5.79 +    }
    5.80 +
    5.81 +    /**
    5.82 +     * Write an error message to stderr.
    5.83 +     */
    5.84 +    void error(String msg) {
    5.85 +        System.err.println("Error: " + msg);
    5.86 +        errors++;
    5.87 +    }
    5.88 +
    5.89 +    Random rgen;
    5.90 +    long seed = 0;
    5.91 +
    5.92 +    int errors;
    5.93 +
    5.94 +    /** Class to encapsulate a test run. */
    5.95 +    class Test {
    5.96 +
    5.97 +        List<Symbol> elems = List.nil();
    5.98 +        Map<Name, List<Symbol>> shadowedMap = new HashMap<Name, List<Symbol>>();
    5.99 +
   5.100 +        /** Run the test. */
   5.101 +        void run() throws Exception {
   5.102 +            log ("starting test");
   5.103 +            setup();
   5.104 +            Scope[] scopes = { createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)),
   5.105 +                               createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)),
   5.106 +                               createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)) };
   5.107 +            boolean[][] scopeNesting = { {false, true, false, true},
   5.108 +                                   {false, true, true, true},
   5.109 +                                   {false, false, true, true} };
   5.110 +            /**
   5.111 +             * We want to generate (and check) the following compound scopes:
   5.112 +             * C1 = C(S1, S2, S3)
   5.113 +             * C2 = C((S1, S2), S3)
   5.114 +             * C3 = C(S1, (S2, S3))
   5.115 +             * C3 = C(C(S1, S2, S3))
   5.116 +             */
   5.117 +            for (int i = 0 ; i < 4 ; i ++) {
   5.118 +                CompoundScope root = new CompoundScope(symtab.noSymbol);
   5.119 +                CompoundScope sub = new CompoundScope(symtab.noSymbol);
   5.120 +                boolean subAdded = false;
   5.121 +                for (int sc = 0 ; sc < 3 ; sc ++) {
   5.122 +                    if (scopeNesting[sc][i]) {
   5.123 +                        sub.addSubScope(scopes[sc]);
   5.124 +                        if (!subAdded) {
   5.125 +                            root.addSubScope(sub);
   5.126 +                            subAdded = true;
   5.127 +                        }
   5.128 +                    } else {
   5.129 +                        root.addSubScope(scopes[sc]);
   5.130 +                    }
   5.131 +                }
   5.132 +                log("testing scope: " + root);
   5.133 +                checkElems(root);
   5.134 +                checkShadowed(root);
   5.135 +            }
   5.136 +        }
   5.137 +
   5.138 +        /**
   5.139 +         * Create a scope containing a given number of synthetic symbols
   5.140 +         */
   5.141 +        Scope createScope(int nelems) {
   5.142 +            Scope s = new Scope(symtab.noSymbol);
   5.143 +            for (int i = 0 ; i < nelems ; i++) {
   5.144 +                Symbol sym = new TypeSymbol(0, names.fromString("s" + i), null, null);
   5.145 +                s.enter(sym);
   5.146 +                elems = elems.prepend(sym);
   5.147 +                List<Symbol> shadowed = shadowedMap.get(sym.name);
   5.148 +                if (shadowed == null) {
   5.149 +                    shadowed = List.nil();
   5.150 +                }
   5.151 +                shadowedMap.put(sym.name, shadowed.prepend(sym));
   5.152 +            }
   5.153 +            return s;
   5.154 +        }
   5.155 +
   5.156 +        /**
   5.157 +         * Setup compiler context
   5.158 +         */
   5.159 +        void setup() {
   5.160 +            log ("setup");
   5.161 +            context = new Context();
   5.162 +            JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
   5.163 +            names = Names.instance(context);       // Name.Table impls tied to an instance of Names
   5.164 +            symtab = Symtab.instance(context);
   5.165 +        }
   5.166 +
   5.167 +        /**
   5.168 +         * Check that CompoundScope.getElements() correctly visits all symbols
   5.169 +         * in all subscopes (in the correct order)
   5.170 +         */
   5.171 +        void checkElems(CompoundScope cs) {
   5.172 +            List<Symbol> allSymbols = elems;
   5.173 +            int count = 0;
   5.174 +            for (Symbol s : cs.getElements()) {
   5.175 +                checkSameSymbols(s, allSymbols.head);
   5.176 +                allSymbols = allSymbols.tail;
   5.177 +                count++;
   5.178 +            }
   5.179 +            if (count != elems.size()) {
   5.180 +                error("CompoundScope.getElements() did not returned enough symbols");
   5.181 +            }
   5.182 +        }
   5.183 +
   5.184 +        /**
   5.185 +         * Check that CompoundScope.getElements() correctly visits all symbols
   5.186 +         * with a given name in all subscopes (in the correct order)
   5.187 +         */
   5.188 +        void checkShadowed(CompoundScope cs) {
   5.189 +            for (Map.Entry<Name, List<Symbol>> shadowedEntry : shadowedMap.entrySet()) {
   5.190 +                int count = 0;
   5.191 +                List<Symbol> shadowed = shadowedEntry.getValue();
   5.192 +                Name name = shadowedEntry.getKey();
   5.193 +                for (Symbol s : cs.getElementsByName(name)) {
   5.194 +                    checkSameSymbols(s, shadowed.head);
   5.195 +                    shadowed = shadowed.tail;
   5.196 +                    count++;
   5.197 +                }
   5.198 +                if (count != shadowedEntry.getValue().size()) {
   5.199 +                    error("CompoundScope.lookup() did not returned enough symbols for name " + name);
   5.200 +                }
   5.201 +            }
   5.202 +        }
   5.203 +
   5.204 +        void checkSameSymbols(Symbol found, Symbol req) {
   5.205 +            if (found != req) {
   5.206 +                error("Symbol mismatch - found    : " + found + ":" + found.hashCode() + "\n" +
   5.207 +                      "                  required : " + req + ":" + req.hashCode());
   5.208 +            }
   5.209 +        }
   5.210 +
   5.211 +        Context context;
   5.212 +        Symtab symtab;
   5.213 +        Names names;
   5.214 +    }
   5.215 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/tools/javac/scope/7017664/ImplementationCacheTest.java	Tue Feb 15 11:49:46 2011 +0000
     6.3 @@ -0,0 +1,129 @@
     6.4 +/*
     6.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.
    6.11 + *
    6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.15 + * version 2 for more details (a copy is included in the LICENSE file that
    6.16 + * accompanied this code).
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License version
    6.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.21 + *
    6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.23 + * or visit www.oracle.com if you need additional information or have any
    6.24 + * questions.
    6.25 + */
    6.26 +
    6.27 +/*
    6.28 + * @test
    6.29 + * @bug 7017664
    6.30 + * @summary Basher for CompoundScopes
    6.31 + */
    6.32 +
    6.33 +import com.sun.source.util.JavacTask;
    6.34 +import com.sun.tools.javac.code.Symbol;
    6.35 +import com.sun.tools.javac.code.Types;
    6.36 +import com.sun.tools.javac.file.JavacFileManager;
    6.37 +import com.sun.tools.javac.util.Context;
    6.38 +
    6.39 +import com.sun.tools.javac.code.Symbol.*;
    6.40 +
    6.41 +import java.io.IOException;
    6.42 +import java.net.URI;
    6.43 +import java.util.Arrays;
    6.44 +import java.util.List;
    6.45 +import javax.lang.model.element.Element;
    6.46 +import javax.tools.JavaCompiler;
    6.47 +import javax.tools.JavaFileObject;
    6.48 +import javax.tools.SimpleJavaFileObject;
    6.49 +import javax.tools.ToolProvider;
    6.50 +
    6.51 +import static javax.tools.JavaFileObject.Kind;
    6.52 +
    6.53 +public class ImplementationCacheTest {
    6.54 +
    6.55 +    static class SourceFile extends SimpleJavaFileObject {
    6.56 +
    6.57 +        final String source = "interface I { void m(); }\n" +
    6.58 +                              "class A implements I { public void m() {} }\n" +
    6.59 +                              "class B extends A { }\n";
    6.60 +
    6.61 +        public SourceFile() {
    6.62 +            super(URI.create("test.java"), Kind.SOURCE);
    6.63 +        }
    6.64 +
    6.65 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
    6.66 +            return source;
    6.67 +        }
    6.68 +    }
    6.69 +
    6.70 +    public static void main(String[] args) throws IOException {
    6.71 +        List<? extends JavaFileObject> files = Arrays.asList(new SourceFile());
    6.72 +        JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
    6.73 +        JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, files);
    6.74 +        Context ctx = new Context();
    6.75 +        JavacFileManager.preRegister(ctx);
    6.76 +        checkImplementationCache(ct.analyze(), Types.instance(ctx));
    6.77 +    }
    6.78 +
    6.79 +    static void checkImplementationCache(Iterable<? extends Element> elements, Types types) {
    6.80 +        if (types == null) {
    6.81 +            throw new AssertionError("problems initializing Types");
    6.82 +        }
    6.83 +
    6.84 +        Symbol a = null;
    6.85 +        Symbol b = null;
    6.86 +        Symbol i = null;
    6.87 +
    6.88 +        for (Element e : elements) {
    6.89 +            if (e.getSimpleName().contentEquals("A")) {
    6.90 +                a = (Symbol)e;
    6.91 +            } else if (e.getSimpleName().contentEquals("B")) {
    6.92 +                b = (Symbol)e;
    6.93 +            } else if (e.getSimpleName().contentEquals("I")) {
    6.94 +                i = (Symbol)e;
    6.95 +            }
    6.96 +        }
    6.97 +
    6.98 +        if (a == null || b == null || i == null) {
    6.99 +            throw new AssertionError("missing class");
   6.100 +        }
   6.101 +
   6.102 +        MethodSymbol I_m = null;
   6.103 +
   6.104 +        for (Symbol sym : i.members().getElements()) {
   6.105 +            if (sym.name.contentEquals("m")) {
   6.106 +                I_m = (MethodSymbol)sym;
   6.107 +            }
   6.108 +        }
   6.109 +
   6.110 +        if (I_m == null) {
   6.111 +            throw new AssertionError("missing method m() in scope of interface I");
   6.112 +        }
   6.113 +
   6.114 +        Symbol impl = I_m.implementation((TypeSymbol)b, types, true);
   6.115 +
   6.116 +        if (impl == null || impl.owner != a) {
   6.117 +            throw new AssertionError("wrong implementation for m() in B");
   6.118 +        }
   6.119 +
   6.120 +        b.members().enter(I_m.clone(b));
   6.121 +
   6.122 +        Symbol newImpl = I_m.implementation((TypeSymbol)b, types, true);
   6.123 +
   6.124 +        if (newImpl == impl) {
   6.125 +            throw new AssertionError("stale implementation for m() in B");
   6.126 +        }
   6.127 +
   6.128 +        if (newImpl == null || newImpl.owner != b) {
   6.129 +            throw new AssertionError("wrong implementation for m() in B");
   6.130 +        }
   6.131 +    }
   6.132 +}

mercurial