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    
029    aspect PreciseRethrow {
030      inh boolean InferredParameterDeclaration.inhModifiedInScope(Variable var);
031      inh boolean LambdaParameters.inhModifiedInScope(Variable var);
032      inh boolean VariableDeclaration.inhModifiedInScope(Variable var);
033    
034      eq LambdaExpr.getLambdaParameters().inhModifiedInScope(Variable var) = modifiedInScope(var);
035      eq DeclaredLambdaParameters.getParameter().inhModifiedInScope(Variable var) =
036          inhModifiedInScope(var);
037      eq InferredLambdaParameters.getParameter().inhModifiedInScope(Variable var) =
038          inhModifiedInScope(var);
039    
040      syn boolean BodyDecl.modifiedInScope(Variable var);
041      syn boolean TypeDecl.modifiedInScope(Variable var);
042    
043      syn boolean LambdaBody.modifiedInScope(Variable var);
044      eq LambdaExpr.modifiedInScope(Variable var) = getLambdaBody().modifiedInScope(var);
045      eq BlockLambdaBody.modifiedInScope(Variable var) = getBlock().modifiedInScope(var);
046      eq ExprLambdaBody.modifiedInScope(Variable var) = getExpr().modifiedInScope(var);
047    
048      eq EnhancedForStmt.getVariableDeclaration().inhModifiedInScope(Variable var) =
049          modifiedInScope(var);
050      eq EnhancedForStmt.getStmt().inhModifiedInScope(Variable var) = false;
051      eq Block.getStmt().inhModifiedInScope(Variable var) = modifiedInScope(var);
052      eq IfStmt.getThen().inhModifiedInScope(Variable var) = false;
053      eq IfStmt.getElse().inhModifiedInScope(Variable var) = false;
054      eq WhileStmt.getStmt().inhModifiedInScope(Variable var) = false;
055      eq DoStmt.getStmt().inhModifiedInScope(Variable var) = false;
056      eq ForStmt.getInitStmt().inhModifiedInScope(Variable var) = modifiedInScope(var);
057      eq ForStmt.getUpdateStmt().inhModifiedInScope(Variable var) = modifiedInScope(var);
058      eq ForStmt.getStmt().inhModifiedInScope(Variable var) = false;
059    
060      eq ConstructorDecl.getParsedConstructorInvocation().inhModifiedInScope(Variable var) = false;
061      eq ConstructorDecl.getImplicitConstructorInvocation().inhModifiedInScope(Variable var) = false;
062    
063      eq BodyDecl.modifiedInScope(Variable var) = false;
064      eq ConstructorDecl.modifiedInScope(Variable var) = getBlock().modifiedInScope(var);
065      eq InstanceInitializer.modifiedInScope(Variable var) = getBlock().modifiedInScope(var);
066      eq StaticInitializer.modifiedInScope(Variable var) = getBlock().modifiedInScope(var);
067    
068      refine PreciseRethrow
069      eq LocalClassDeclStmt.modifiedInScope(Variable var) = getClassDecl().modifiedInScope(var);
070      eq MemberClassDecl.modifiedInScope(Variable var) = getClassDecl().modifiedInScope(var);
071      eq MemberInterfaceDecl.modifiedInScope(Variable var) = getInterfaceDecl().modifiedInScope(var);
072      eq MethodDecl.modifiedInScope(Variable var) = hasBlock() && getBlock().modifiedInScope(var);
073    
074      eq TypeDecl.modifiedInScope(Variable var) {
075        for (int i = 0; i < getNumBodyDecl(); i++) {
076          BodyDecl body = getBodyDecl(i);
077          if (body.modifiedInScope(var)) {
078            return true;
079          }
080        }
081        return false;
082      }
083    
084      eq ArrayAccess.modifiedInScope(Variable var) = getExpr().modifiedInScope(var);
085    
086      refine PreciseRethrow
087      eq AbstractDot.modifiedInScope(Variable var) =
088          getLeft().modifiedInScope(var) || getRight().modifiedInScope(var);
089    
090      eq PostIncExpr.modifiedInScope(Variable var) = getOperand().isVariable(var);
091      eq PostDecExpr.modifiedInScope(Variable var) = getOperand().isVariable(var);
092      eq PreIncExpr.modifiedInScope(Variable var) = getOperand().isVariable(var);
093      eq PreDecExpr.modifiedInScope(Variable var) = getOperand().isVariable(var);
094    
095      refine PreciseRethrow
096      eq ClassInstanceExpr.modifiedInScope(Variable var) {
097        for (int i = 0; i < getNumArg(); ++i) {
098          if (getArg(i).modifiedInScope(var)) {
099            return true;
100          }
101        }
102        if (hasTypeDecl()) {
103          return getTypeDecl().modifiedInScope(var);
104        } else {
105          return false;
106        }
107      }
108    
109      refine PreciseRethrow
110      eq ConstructorDecl.getParameter().inhModifiedInScope(Variable var) {
111        return getBlock().modifiedInScope(var) || getConstructorInvocation().modifiedInScope(var);
112      }
113    
114      refine PreciseRethrow
115      eq AssignExpr.modifiedInScope(Variable var) {
116        boolean isLeft = getDest().isVariable(var);
117        if (isLeft && var instanceof VariableDeclaration) {
118          VariableDeclaration decl = (VariableDeclaration) var;
119          if (!decl.hasInit()) {
120            // Variable is being written to in an inner class.
121            if (decl.hostType() != hostType()) {
122              return true;
123            }
124            // 4.12.4;
125            return !getSource().isDUafter(var);
126          }
127          return true;
128        } else {
129          return isLeft || getSource().modifiedInScope(var);
130        }
131      }
132    }
133    
134    aspect EffectivelyFinal {
135      //4.12.4
136      syn lazy boolean InferredParameterDeclaration.isEffectivelyFinal() =
137          isFinal() || !inhModifiedInScope(this);
138      syn lazy boolean FieldDeclaration.isEffectivelyFinal() = isFinal();
139    
140      //14.20
141      // CatchParameterDeclaration is only used in a multi-catch, and multi-catch parameters are
142      // always implicitly final.
143      syn lazy boolean CatchParameterDeclaration.isEffectivelyFinal() = true;
144    
145      /**
146       * Note: this attribute deviates from what the JLS says about effectively finalness,
147       * simply because the attribute name would be confusing if it did not return true
148       * when the variable was explicitly declared final. The JLS considers declared final
149       * and effectively final to be mutually exclusive, we don't.
150       */
151      syn lazy boolean VariableDeclaration.isEffectivelyFinal() =
152          isFinal() || !inhModifiedInScope(this);
153    }