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    aspect Java8NameCheck {
029      inh BodyDecl InferredParameterDeclaration.enclosingBodyDecl();
030      inh VariableScope InferredParameterDeclaration.outerScope();
031      inh VariableScope LambdaParameters.outerScope();
032    
033      //6.3
034      eq LambdaExpr.getLambdaParameters().outerScope() = this;
035      eq LambdaExpr.getLambdaBody().outerScope() = this;
036    
037    
038      public void InferredParameterDeclaration.nameCheck() {
039        SimpleSet decls = outerScope().lookupVariable(name());
040        for (Iterator iter = decls.iterator(); iter.hasNext(); ) {
041          Variable var = (Variable) iter.next();
042          if (var instanceof VariableDeclaration) {
043            VariableDeclaration decl = (VariableDeclaration) var;
044            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
045              errorf("duplicate declaration of parameter %s", name());
046            }
047          } else if (var instanceof ParameterDeclaration) {
048            ParameterDeclaration decl = (ParameterDeclaration) var;
049            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
050              errorf("duplicate declaration of parameter %s", name());
051            }
052          } else if (var instanceof InferredParameterDeclaration) {
053            InferredParameterDeclaration decl = (InferredParameterDeclaration) var;
054            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
055              errorf("duplicate declaration of parameter %s", name());
056            }
057          } else if (var instanceof CatchParameterDeclaration) {
058            CatchParameterDeclaration decl = (CatchParameterDeclaration) var;
059            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
060              errorf("duplicate declaration of parameter %s", name());
061            }
062          }
063        }
064    
065        // 8.4.1
066        if (!lookupVariable(name()).contains(this)) {
067          errorf("duplicate declaration of parameter %s", name());
068        }
069      }
070    
071      refine MultiCatch
072      public void CatchParameterDeclaration.nameCheck() {
073        SimpleSet decls = outerScope().lookupVariable(name());
074        for (Iterator iter = decls.iterator(); iter.hasNext(); ) {
075          Variable var = (Variable) iter.next();
076          if (var instanceof VariableDeclaration) {
077            VariableDeclaration decl = (VariableDeclaration) var;
078            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
079              errorf("duplicate declaration of catch parameter %s", name());
080            }
081          } else if (var instanceof ParameterDeclaration) {
082            ParameterDeclaration decl = (ParameterDeclaration) var;
083            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
084              errorf("duplicate declaration of catch parameter %s", name());
085            }
086          } else if (var instanceof InferredParameterDeclaration) {
087            InferredParameterDeclaration decl = (InferredParameterDeclaration) var;
088            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
089              errorf("duplicate declaration of catch parameter %s", name());
090            }
091          } else if (var instanceof CatchParameterDeclaration) {
092            CatchParameterDeclaration decl = (CatchParameterDeclaration) var;
093            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
094              errorf("duplicate declaration of catch parameter %s", name());
095            }
096          }
097        }
098    
099        // 8.4.1
100        if (!lookupVariable(name()).contains(this)) {
101          errorf("duplicate declaration of catch parameter %s", name());
102        }
103      }
104    
105      refine MultiCatch
106      public void ParameterDeclaration.nameCheck() {
107        SimpleSet decls = outerScope().lookupVariable(name());
108        for (Iterator iter = decls.iterator(); iter.hasNext(); ) {
109          Variable var = (Variable) iter.next();
110          if (var instanceof VariableDeclaration) {
111            VariableDeclaration decl = (VariableDeclaration) var;
112            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
113              errorf("duplicate declaration of parameter %s", name());
114            }
115          } else if (var instanceof ParameterDeclaration) {
116            ParameterDeclaration decl = (ParameterDeclaration) var;
117            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
118              errorf("duplicate declaration of parameter %s", name());
119            }
120          } else if (var instanceof InferredParameterDeclaration) {
121            InferredParameterDeclaration decl = (InferredParameterDeclaration) var;
122            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
123              errorf("duplicate declaration of parameter %s", name());
124            }
125          } else if (var instanceof CatchParameterDeclaration) {
126            CatchParameterDeclaration decl = (CatchParameterDeclaration) var;
127            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
128              errorf("duplicate declaration of parameter %s", name());
129            }
130          }
131        }
132    
133        // 8.4.1
134        if (!lookupVariable(name()).contains(this)) {
135          errorf("duplicate declaration of parameter %s", name());
136        }
137      }
138    
139      refine MultiCatch
140      public void VariableDeclaration.nameCheck() {
141        SimpleSet decls = outerScope().lookupVariable(name());
142        for (Iterator iter = decls.iterator(); iter.hasNext(); ) {
143          Variable var = (Variable) iter.next();
144          if (var instanceof VariableDeclaration) {
145            VariableDeclaration decl = (VariableDeclaration) var;
146            if (decl != this && decl.enclosingBodyDecl() == enclosingBodyDecl()) {
147              errorf("duplicate declaration of local variable %s", name());
148            }
149          }
150          // 8.4.1
151          else if (var instanceof ParameterDeclaration) {
152            ParameterDeclaration decl = (ParameterDeclaration) var;
153            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
154              errorf("duplicate declaration of local variable %s", name());
155            }
156          } else if (var instanceof CatchParameterDeclaration) {
157            CatchParameterDeclaration decl = (CatchParameterDeclaration) var;
158            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
159              errorf("duplicate declaration of local variable %s", name());
160            }
161          } else if (var instanceof InferredParameterDeclaration) {
162            InferredParameterDeclaration decl = (InferredParameterDeclaration) var;
163            if (decl.enclosingBodyDecl() == enclosingBodyDecl()) {
164              errorf("duplicate declaration of local variable %s", name());
165            }
166          }
167        }
168        if (getParent().getParent() instanceof Block) {
169          Block block = (Block) getParent().getParent();
170          for (int i = 0; i < block.getNumStmt(); i++) {
171            if (block.getStmt(i) instanceof Variable) {
172              Variable v = (Variable) block.getStmt(i);
173              if (v.name().equals(name()) && v != this) {
174                errorf("duplicate declaration of local variable %s", name());
175              }
176            }
177          }
178        }
179      }
180    
181      refine NameCheck
182      public void VarAccess.nameCheck() {
183        if (decls().isEmpty() && (!isQualified() || !qualifier().type().isUnknown()
184              || qualifier().isPackageAccess())) {
185          errorf("no field named %s is accessible", name());
186        }
187        if (decls().size() > 1) {
188          StringBuffer sb = new StringBuffer();
189          sb.append("several fields named " + name());
190          for (Iterator iter = decls().iterator(); iter.hasNext(); ) {
191            Variable v = (Variable) iter.next();
192            sb.append("\n    " + v.type().typeName() + "." + v.name() + " declared in "
193                + v.hostType().typeName());
194          }
195          error(sb.toString());
196        }
197    
198        // 8.8.5.1
199        if (inExplicitConstructorInvocation() && !isQualified() && decl().isInstanceVariable()
200            && hostType() == decl().hostType()) {
201          errorf("instance variable %s may not be accessed in an explicit constructor invocation",
202              name());
203        }
204    
205        Variable v = decl();
206        if (!v.isClassVariable() && !v.isInstanceVariable() && v.hostType() != hostType()
207            && !v.isEffectivelyFinal()) {
208          error("A parameter/variable used but not declared in an inner class must be"
209              + " final or effectively final");
210        }
211    
212        // 8.3.2.3
213        if ((decl().isInstanceVariable() || decl().isClassVariable()) && !isQualified()) {
214          if (hostType() != null && !hostType().declaredBeforeUse(decl(), this)) {
215            if (inSameInitializer() && !simpleAssignment() && inDeclaringClass()) {
216              BodyDecl b = closestBodyDecl(hostType());
217              errorf("variable %s is used in %s before it is declared", decl().name(), b.prettyPrint());
218            }
219          }
220        }
221    
222        if (!v.isClassVariable() && !v.isInstanceVariable() && enclosingLambda() != null) {
223          if (v instanceof ParameterDeclaration) {
224            ParameterDeclaration decl = (ParameterDeclaration) v;
225            if (decl.enclosingLambda() != enclosingLambda()) {
226              // 15.27.2
227              if (!decl.isEffectivelyFinal()) {
228                errorf("Parameter %s must be effectively final", v.name());
229              }
230            }
231          } else if (v instanceof InferredParameterDeclaration) {
232            InferredParameterDeclaration decl = (InferredParameterDeclaration) v;
233            if (decl.enclosingLambda() != enclosingLambda()) {
234              // 15.27.2
235              if (!decl.isEffectivelyFinal()) {
236                errorf("Parameter %s must be effectively final", v.name());
237              }
238            }
239          } else if (v instanceof VariableDeclaration) {
240            VariableDeclaration decl = (VariableDeclaration) v;
241            if (decl.enclosingLambda() != enclosingLambda()) {
242              // 15.27.2
243              if (!decl.isEffectivelyFinal()) {
244                errorf("Variable %s must be effectively final", v.name());
245              }
246              // 15.27.2
247              if (!enclosingLambda().isDAbefore(decl)) {
248                errorf("Variable %s must be definitely assigned before used in a lambda", v.name());
249              }
250            }
251          }
252        }
253    
254      }
255    
256      refine TypeCheck
257      protected void TypeDecl.checkAbstractMethodDecls(MethodDecl m1, MethodDecl m2) {
258        if (!m1.subsignatureTo(m2) && !m2.subsignatureTo(m1)) {
259          TypeDecl host1 = m1.hostType();
260          TypeDecl host2 = m2.hostType();
261          String inh1 = "";
262          String inh2 = "";
263          if (host1 != this) {
264            inh1 = "inherited ";
265          }
266          if (host2 != this) {
267            inh2 = "inherited ";
268          }
269    
270          //8.4.8.3
271          errorf("%smethod %s and %smethod %s are multiply declared with"
272              + " the same erasure but not override-equivalent signatures in %s",
273              inh1, m1.fullSignature(), inh2, m2.fullSignature(), fullName());
274        }
275        // DON'T FORGET TO CHECK THIS, REALLY OK TO CHECK BOTH WAYS???
276        if (!m1.returnTypeSubstitutableFor(m2) && !m2.returnTypeSubstitutableFor(m1)) {
277          String inh1 = "";
278          TypeDecl host1 = m1.hostType();
279          TypeDecl host2 = m2.hostType();
280          if (host1 != this || host2 != this) {
281            inh1 = "inherited ";
282          }
283    
284          errorf("%smethod %s is multiply declared with incompatible return types in %s",
285              m1.fullSignature(), fullName());
286        }
287      }
288    
289      protected void TypeDecl.checkInterfaceMethodDecls(MethodDecl m1, MethodDecl m2) {
290        if (m1.isAbstract() && m2.isAbstract()) {
291          checkAbstractMethodDecls(m1, m2);
292          return;
293        } else {
294          TypeDecl host1 = m1.hostType();
295          TypeDecl host2 = m2.hostType();
296          String inh1 = "";
297          String inh2 = "";
298          if (host1 != this) {
299            inh1 = "inherited ";
300          }
301          if (host2 != this) {
302            inh2 = "inherited ";
303          }
304    
305          //9.4
306          errorf("%smethod %s and %smethod %s are multiply declared in %s",
307              inh1, m1.fullSignature(), inh2, m2.fullSignature(), fullName());
308        }
309      }
310    
311      refine TypeHierarchyCheck
312      public void ClassDecl.nameCheck() {
313        refined();
314        for (Iterator<SimpleSet> iter = methodsSignatureMap().values().iterator(); iter.hasNext(); ) {
315          SimpleSet set = iter.next();
316          if (set.size() > 1) {
317            Iterator i2 = set.iterator();
318            boolean foundClassAbstract = false;
319            MethodDecl foundNonAbstract = null;
320            while (i2.hasNext()) {
321              MethodDecl m = (MethodDecl) i2.next();
322              if (!m.isAbstract()) {
323                foundNonAbstract = m;
324              } else {
325                if (m.hostType().isClassDecl() && m.hostType() != this) {
326                  foundClassAbstract = true;
327                }
328              }
329            }
330            // 8.4.8.1
331            if (foundNonAbstract != null && !foundClassAbstract) {
332              errorf("Method %s is multiply declared in %s",
333                  foundNonAbstract.fullSignature(), typeName());
334            }
335          }
336        }
337      }
338    
339      refine TypeHierarchyCheck
340      public void InterfaceDecl.nameCheck() {
341        super.nameCheck();
342    
343        //9.6.3.8
344          if (hasAnnotationFunctionalInterface() && !isFunctional()) {
345            errorf("%s is not a functional interface", name());
346          }
347    
348        if (isCircular()) {
349          errorf("circular inheritance dependency in %s", typeName());
350        } else {
351          for (int i = 0; i < getNumSuperInterface(); i++) {
352            TypeDecl typeDecl = getSuperInterface(i).type();
353            if (typeDecl.isCircular()) {
354              errorf("circular inheritance dependency in %s", typeName());
355            }
356          }
357        }
358        for (Iterator<SimpleSet> iter = methodsSignatureMap().values().iterator(); iter.hasNext(); ) {
359          SimpleSet set = iter.next();
360          if (set.size() > 1) {
361            Iterator i2 = set.iterator();
362            MethodDecl m = (MethodDecl) i2.next();
363            while (i2.hasNext()) {
364              MethodDecl n = (MethodDecl) i2.next();
365              checkInterfaceMethodDecls(m, n);
366            }
367          }
368        }
369      }
370    
371      refine TypeHierarchyCheck
372      public void SuperAccess.nameCheck() {
373        if (isQualified()) {
374          if (decl().isInterfaceDecl()) {
375            InterfaceDecl decl = (InterfaceDecl) decl();
376            if (hostType().isClassDecl()) {
377              ClassDecl hostDecl = (ClassDecl) hostType();
378              InterfaceDecl found = null;
379              for (int i = 0; i < hostDecl.getNumImplements(); i++) {
380                if (hostDecl.getImplements(i).type() == decl) {
381                  found = (InterfaceDecl) hostDecl.getImplements(i).type();
382                  break;
383                }
384              }
385              if (found == null) {
386                // 15.12.1 - fourth bullet
387                errorf("Type %s is not a direct superinterface of %s",
388                    decl().typeName(), hostType().typeName());
389                return;
390              }
391              InterfaceDecl foundRedundant = null;
392              for (int i = 0; i < hostDecl.getNumImplements(); i++) {
393                if (hostDecl.getImplements(i).type() != found && hostDecl.getImplements(i).type().strictSubtype(found)) {
394                  foundRedundant = (InterfaceDecl) hostDecl.getImplements(i).type();
395                  break;
396                }
397              }
398              if (foundRedundant != null) {
399                // 15.12.1 - fourth bullet
400                errorf("Type %s cannot be used as qualifier, it is extended by implemented interface %s and is redundant",
401                    decl().typeName(), foundRedundant.typeName());
402                return;
403              }
404              if (hasNextAccess() && nextAccess() instanceof MethodAccess) {
405                MethodAccess methodAccess = (MethodAccess) nextAccess();
406                if (hostDecl.hasOverridingMethodInSuper(methodAccess.decl())) {
407                  errorf("Cannot make a super reference to method %s,"
408                      + " there is a more specific override",
409                      methodAccess.decl().fullSignature());
410                }
411              }
412            } else if (hostType().isInterfaceDecl()) {
413              InterfaceDecl hostDecl = (InterfaceDecl) hostType();
414              InterfaceDecl found = null;
415              for (int i = 0; i < hostDecl.getNumSuperInterface(); i++) {
416                if (hostDecl.getSuperInterface(i).type() == decl) {
417                  found = (InterfaceDecl) hostDecl.getSuperInterface(i).type();
418                  break;
419                }
420              }
421              if (found == null) {
422                // 15.12.1 - fourth bullet
423                errorf("Type %s is not a direct superinterface of %s",
424                    decl().typeName(), hostType().typeName());
425                return;
426              }
427              InterfaceDecl foundRedundant = null;
428              for (int i = 0; i < hostDecl.getNumSuperInterface(); i++) {
429                if (hostDecl.getSuperInterface(i).type() != found && hostDecl.getSuperInterface(i).type().strictSubtype(found)) {
430                  foundRedundant = (InterfaceDecl) hostDecl.getSuperInterface(i).type();
431                  break;
432                }
433              }
434              if (foundRedundant != null) {
435                // 15.12.1 - fourth bullet
436                errorf("Type %s cannot be used as qualifier, it is extended by"
437                    + " implemented interface %s and is redundant",
438                    decl().typeName(), foundRedundant.typeName());
439                return;
440              }
441              if (hasNextAccess() && nextAccess() instanceof MethodAccess) {
442                MethodAccess methodAccess = (MethodAccess) nextAccess();
443                if (hostDecl.hasOverridingMethodInSuper(methodAccess.decl())) {
444                  errorf("Cannot make a super reference to method %s,"
445                      + " there is a more specific override",
446                      methodAccess.decl().fullSignature());
447                }
448              }
449            } else {
450              error("Illegal context for super access");
451            }
452    
453            if (nextAccess() instanceof MethodAccess) {
454              if (((MethodAccess) nextAccess()).decl().isStatic()) {
455                error("Cannot reference static interface methods with super");
456              }
457            }
458    
459            if (!hostType().strictSubtype(decl())) {
460              errorf("Type %s is not a superinterface for %s",
461                  decl().typeName(), hostType().typeName());
462            }
463          } else if (!hostType().isInnerTypeOf(decl()) && hostType() != decl()) {
464            error("qualified super must name an enclosing type");
465          }
466          if (inStaticContext()) {
467            error("*** Qualified super may not occur in static context");
468          }
469        }
470        // 8.8.5.1
471        // JLSv7 8.8.7.1
472        TypeDecl constructorHostType = enclosingExplicitConstructorHostType();
473        if (constructorHostType != null && (constructorHostType == decl())) {
474          error("super may not be accessed in an explicit constructor invocation");
475        }
476        // 8.4.3.2
477        if (inStaticContext()) {
478          error("super may not be accessed in a static context");
479        }
480      }
481    
482      refine NameCheck
483      eq MethodAccess.validArgs() {
484        for (int i = 0; i < getNumArg(); i++) {
485          if (!getArg(i).isPolyExpression() && getArg(i).type().isUnknown()) {
486            return false;
487          }
488        }
489            return true;
490      }
491    
492      refine NameCheck
493      eq ConstructorAccess.validArgs() {
494        for (int i = 0; i < getNumArg(); i++) {
495          if (!getArg(i).isPolyExpression() && getArg(i).type().isUnknown()) {
496            return false;
497          }
498        }
499        return true;
500      }
501    
502      refine NameCheck
503      eq ClassInstanceExpr.validArgs() {
504        for (int i = 0; i < getNumArg(); i++) {
505          if (!getArg(i).isPolyExpression() && getArg(i).type().isUnknown()) {
506            return false;
507          }
508        }
509        return true;
510      }
511    
512      public void MethodReference.nameCheck() {
513        for (int i = 0; i < getNumTypeArgument(); i++) {
514          if (getTypeArgument(i) instanceof AbstractWildcard) {
515            error("Wildcard not allowed in method reference type argument lists");
516            break;
517          }
518        }
519      }
520    
521      public void ExprMethodReference.nameCheck() {
522        super.nameCheck();
523        if (!getExpr().isSuperAccess()) {
524          if (!getExpr().type().isReferenceType()) {
525            error("Expression in a method reference must have reference type");
526          }
527        }
528      }
529    
530      public void ClassReference.nameCheck() {
531        for (int i = 0; i < getNumTypeArgument(); i++) {
532          if (getTypeArgument(i) instanceof AbstractWildcard) {
533            error("Wildcard not allowed in constructor reference type argument lists");
534            break;
535          }
536        }
537      }
538    
539      public void ArrayReference.nameCheck() {
540        Access typeAccess = getTypeAccess();
541        while (typeAccess instanceof ArrayTypeAccess) {
542          typeAccess = ((ArrayTypeAccess) typeAccess).getAccess();
543        }
544        if (typeAccess instanceof ParTypeAccess) {
545          error("Cannot create array of generic type");
546        }
547      }
548    
549      public void DeclaredLambdaParameters.nameCheck() {
550        for (int i = 0; i < getNumParameter(); i++) {
551          if (getParameter(i).name().equals("_")) {
552            // 15.27.1
553            error("Underscore is not a valid identifier for a lambda parameter");
554            return;
555          }
556        }
557      }
558    
559      public void InferredLambdaParameters.nameCheck() {
560        for (int i = 0; i < getNumParameter(); i++) {
561          if (getParameter(i).name().equals("_")) {
562            // 15.27.1
563            error("Underscore is not a valid identifier for a lambda parameter");
564            return;
565          }
566        }
567      }
568    }