| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.adobe.ac.pmd.rules.core; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| import java.util.logging.Logger; |
| |
| import com.adobe.ac.pmd.IFlexViolation; |
| import com.adobe.ac.pmd.nodes.IAttribute; |
| import com.adobe.ac.pmd.nodes.IClass; |
| import com.adobe.ac.pmd.nodes.IConstant; |
| import com.adobe.ac.pmd.nodes.IFunction; |
| import com.adobe.ac.pmd.nodes.INode; |
| import com.adobe.ac.pmd.nodes.IPackage; |
| import com.adobe.ac.pmd.parser.IParserNode; |
| import com.adobe.ac.pmd.parser.NodeKind; |
| import com.adobe.ac.utils.StackTraceUtils; |
| |
| /** |
| * Abstract class for AST-based rule Extends this class if your rule is only |
| * detectable in an AS script block, which can be converted into an Abstract |
| * Syntax Tree. Then you will be able to either use the visitor pattern, or to |
| * iterate from the package node, in order to find your violation(s). |
| */ |
| public abstract class AbstractAstFlexRule extends AbstractFlexRule implements IFlexAstRule |
| { |
| /** |
| * |
| */ |
| protected enum FunctionType |
| { |
| GETTER, NORMAL, SETTER |
| } |
| |
| /** |
| * |
| */ |
| protected enum VariableOrConstant |
| { |
| CONSTANT, VARIABLE |
| } |
| |
| /** |
| * |
| */ |
| protected enum VariableScope |
| { |
| IN_CLASS, IN_FUNCTION |
| } |
| |
| private interface ExpressionVisitor |
| { |
| void visitExpression( final IParserNode ast ); |
| } |
| |
| private static final Logger LOGGER = Logger.getLogger( AbstractAstFlexRule.class.getName() ); |
| |
| /** |
| * @param functionNode |
| * @return |
| */ |
| /** |
| * @param functionNode |
| * @return |
| */ |
| protected static IParserNode getNameFromFunctionDeclaration( final IParserNode functionNode ) |
| { |
| IParserNode nameChild = null; |
| |
| for ( final IParserNode child : functionNode.getChildren() ) |
| { |
| if ( child.is( NodeKind.NAME ) ) |
| { |
| nameChild = child; |
| break; |
| } |
| } |
| return nameChild; |
| } |
| |
| /** |
| * @param fieldNode |
| * @return |
| */ |
| protected static IParserNode getTypeFromFieldDeclaration( final IParserNode fieldNode ) |
| { |
| return fieldNode.getChild( 0 ).getChild( 1 ); |
| } |
| |
| private final List< IFlexViolation > violations; |
| |
| /** |
| * |
| */ |
| public AbstractAstFlexRule() |
| { |
| super(); |
| |
| violations = new ArrayList< IFlexViolation >(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see |
| * com.adobe.ac.pmd.rules.core.AbstractFlexRule#isConcernedByTheCurrentFile |
| * () |
| */ |
| @Override |
| public boolean isConcernedByTheCurrentFile() |
| { |
| return true; |
| } |
| |
| /** |
| * @param function |
| * @return the added violation positioned on the given function node |
| */ |
| protected final IFlexViolation addViolation( final IFunction function ) |
| { |
| final IParserNode name = getNameFromFunctionDeclaration( function.getInternalNode() ); |
| |
| return addViolation( name, |
| name, |
| name.getStringValue() ); |
| } |
| |
| /** |
| * @param function |
| * @param messageToReplace |
| * @return |
| */ |
| protected final IFlexViolation addViolation( final IFunction function, |
| final String messageToReplace ) |
| { |
| final IParserNode name = getNameFromFunctionDeclaration( function.getInternalNode() ); |
| |
| return addViolation( name, |
| name, |
| messageToReplace ); |
| } |
| |
| /** |
| * @param violatingNode |
| * @return the added violation replacing the threshold value in the message |
| * if any. |
| */ |
| protected final IFlexViolation addViolation( final INode violatingNode ) |
| { |
| return addViolation( violatingNode.getInternalNode(), |
| violatingNode.getInternalNode() ); |
| } |
| |
| /** |
| * @param violatingNode |
| * @return the added violation replacing the threshold value in the message |
| * if any. |
| */ |
| protected final IFlexViolation addViolation( final INode violatingNode, |
| final String... messageToReplace ) |
| { |
| return addViolation( violatingNode.getInternalNode(), |
| violatingNode.getInternalNode(), |
| messageToReplace ); |
| } |
| |
| /** |
| * @param violatingNode |
| * @param endNode |
| * @return the added violation replacing the threshold value in the message |
| * if any. |
| */ |
| protected final IFlexViolation addViolation( final IParserNode violatingNode ) |
| { |
| return addViolation( violatingNode, |
| violatingNode ); |
| } |
| |
| /** |
| * @param beginningNode |
| * @param endNode |
| * @param messageToReplace |
| * @return the add violation replacing the {0} token by the specified message |
| */ |
| protected final IFlexViolation addViolation( final IParserNode beginningNode, |
| final IParserNode endNode, |
| final String... messageToReplace ) |
| { |
| if ( isAlreadyViolationAdded( beginningNode ) ) |
| { |
| return null; |
| } |
| final IFlexViolation violation = addViolation( ViolationPosition.create( beginningNode.getLine(), |
| endNode.getLine(), |
| beginningNode.getColumn(), |
| endNode.getColumn() ) ); |
| |
| for ( int i = 0; i < messageToReplace.length; i++ ) |
| { |
| violation.replacePlaceholderInMessage( messageToReplace[ i ], |
| i ); |
| } |
| |
| return violation; |
| } |
| |
| /** |
| * @param violatingNode |
| * @param endNode |
| * @param messageToReplace |
| * @return the add violation replacing the {0} token by the specified message |
| */ |
| protected final IFlexViolation addViolation( final IParserNode violatingNode, |
| final String... messageToReplace ) |
| { |
| return addViolation( violatingNode, |
| violatingNode, |
| messageToReplace ); |
| } |
| |
| /** |
| * @param violationPosition |
| * @return the added violation positioned at the given position |
| */ |
| protected final IFlexViolation addViolation( final ViolationPosition violationPosition ) |
| { |
| return addViolation( violations, |
| violationPosition ); |
| } |
| |
| /** |
| * find the violations list from the given class node |
| * |
| * @param classNode |
| */ |
| protected void findViolations( final IClass classNode ) |
| { |
| findViolationsFromAttributes( classNode.getAttributes() ); |
| findViolationsFromConstants( classNode.getConstants() ); |
| findViolations( classNode.getFunctions() ); |
| if ( classNode.getConstructor() != null ) |
| { |
| findViolationsFromConstructor( classNode.getConstructor() ); |
| } |
| } |
| |
| /** |
| * find violations in every function in a class |
| * |
| * @param function |
| */ |
| protected void findViolations( final IFunction function ) |
| { |
| } |
| |
| /** |
| * Override this method if you need to find violations from the package ( or |
| * any subsequent node like class or function) |
| * |
| * @param packageNode |
| */ |
| protected void findViolations( final IPackage packageNode ) |
| { |
| final IClass classNode = packageNode.getClassNode(); |
| |
| if ( classNode != null ) |
| { |
| findViolations( classNode ); |
| } |
| } |
| |
| /** |
| * find the violations list from the given functions list |
| * |
| * @param functions |
| */ |
| protected void findViolations( final List< IFunction > functions ) |
| { |
| for ( final IFunction function : functions ) |
| { |
| findViolations( function ); |
| } |
| } |
| |
| /** |
| * find the violations list from the given class variables list |
| * |
| * @param variables |
| */ |
| protected void findViolationsFromAttributes( final List< IAttribute > variables ) |
| { |
| } |
| |
| /** |
| * find the violations list from the given class constants list |
| * |
| * @param constants |
| */ |
| protected void findViolationsFromConstants( final List< IConstant > constants ) |
| { |
| } |
| |
| /** |
| * find the violations list from the given class constructor node |
| * |
| * @param constructor |
| */ |
| protected void findViolationsFromConstructor( final IFunction constructor ) |
| { |
| } |
| |
| /** |
| * Find violations in the current file |
| */ |
| @Override |
| protected final List< IFlexViolation > findViolationsInCurrentFile() |
| { |
| try |
| { |
| if ( getCurrentPackageNode() != null ) |
| { |
| visitCompilationUnit( getCurrentPackageNode().getInternalNode() ); |
| findViolations( getCurrentPackageNode() ); |
| } |
| } |
| catch ( final Exception e ) |
| { |
| LOGGER.warning( "on " |
| + getCurrentFile().getFilePath() ); |
| LOGGER.warning( StackTraceUtils.print( e ) ); |
| } |
| final List< IFlexViolation > copy = new ArrayList< IFlexViolation >( violations ); |
| |
| violations.clear(); |
| |
| return copy; |
| } |
| |
| /** |
| * @param statementNode |
| */ |
| protected void visitAs( final IParserNode statementNode ) |
| { |
| } |
| |
| /** |
| * @param catchNode |
| */ |
| protected void visitCatch( final IParserNode catchNode ) |
| { |
| visitNameTypeInit( catchNode.getChild( 0 ) ); |
| visitBlock( catchNode.getChild( 1 ) ); |
| } |
| |
| /** |
| * @param classNode |
| */ |
| protected void visitClass( final IParserNode classNode ) |
| { |
| IParserNode content = null; |
| for ( final IParserNode node : classNode.getChildren() ) |
| { |
| if ( node.is( NodeKind.CONTENT ) ) |
| { |
| content = node; |
| break; |
| } |
| } |
| visitClassContent( content ); |
| } |
| |
| /** |
| * Visit the condition of a if, while, ... |
| * |
| * @param condition |
| */ |
| protected void visitCondition( final IParserNode condition ) |
| { |
| visitExpression( condition ); |
| } |
| |
| /** |
| * @param doNode |
| */ |
| protected void visitDo( final IParserNode doNode ) |
| { |
| visitBlock( doNode.getChild( 0 ) ); |
| visitCondition( doNode.getChild( 1 ) ); |
| } |
| |
| /** |
| * @param ifNode |
| */ |
| protected void visitElse( final IParserNode ifNode ) |
| { |
| visitBlock( ifNode.getChild( 2 ) ); |
| } |
| |
| /** |
| * Visit empty statement |
| * |
| * @param statementNode |
| */ |
| protected void visitEmptyStatetement( final IParserNode statementNode ) |
| { |
| } |
| |
| /** |
| * @param finallyNode |
| */ |
| protected void visitFinally( final IParserNode finallyNode ) |
| { |
| if ( isNodeNavigable( finallyNode ) ) |
| { |
| visitBlock( finallyNode.getChild( 0 ) ); |
| } |
| } |
| |
| /** |
| * @param forNode |
| */ |
| protected void visitFor( final IParserNode forNode ) |
| { |
| visitBlock( forNode.getChild( 3 ) ); |
| } |
| |
| /** |
| * @param foreachNode |
| */ |
| protected void visitForEach( final IParserNode foreachNode ) |
| { |
| visitBlock( foreachNode.getChild( 2 ) ); |
| } |
| |
| /** |
| * @param functionNode |
| * @param type |
| */ |
| protected void visitFunction( final IParserNode functionNode, |
| final FunctionType type ) |
| { |
| final Iterator< IParserNode > iterator = functionNode.getChildren().iterator(); |
| IParserNode currentNode = iterator.next(); |
| |
| while ( currentNode.is( NodeKind.META_LIST ) |
| || currentNode.is( NodeKind.MOD_LIST ) || currentNode.is( NodeKind.AS_DOC ) |
| || currentNode.is( NodeKind.MULTI_LINE_COMMENT ) ) |
| { |
| currentNode = iterator.next(); |
| } |
| currentNode = iterator.next(); |
| visitParameters( currentNode ); |
| currentNode = iterator.next(); |
| visitFunctionReturnType( currentNode ); |
| try |
| { |
| // Intrinsic functions in AS2 |
| currentNode = iterator.next(); |
| visitFunctionBody( currentNode ); |
| } |
| catch ( final NoSuchElementException e ) |
| { |
| } |
| } |
| |
| /** |
| * @param functionReturnTypeNode |
| */ |
| protected void visitFunctionReturnType( final IParserNode functionReturnTypeNode ) |
| { |
| visitBlock( functionReturnTypeNode ); |
| } |
| |
| /** |
| * @param ifNode |
| */ |
| protected void visitIf( final IParserNode ifNode ) |
| { |
| visitCondition( ifNode.getChild( 0 ) ); |
| visitThen( ifNode ); |
| if ( ifNode.numChildren() == 3 ) |
| { |
| visitElse( ifNode ); |
| } |
| } |
| |
| /** |
| * @param interfaceNode |
| */ |
| protected void visitInterface( final IParserNode interfaceNode ) |
| { |
| } |
| |
| /** |
| * @param methodCallNode |
| */ |
| protected void visitMethodCall( final IParserNode methodCallNode ) |
| { |
| final Iterator< IParserNode > iterator = methodCallNode.getChildren().iterator(); |
| visitExpression( iterator.next() ); |
| do |
| { |
| visitExpressionList( iterator.next() ); |
| } |
| while ( iterator.hasNext() ); |
| } |
| |
| /** |
| * @param newExpression |
| */ |
| protected void visitNewExpression( final IParserNode newExpression ) |
| { |
| visitExpression( newExpression.getChild( 0 ) ); |
| visitExpressionList( newExpression.getChild( 1 ) ); |
| } |
| |
| protected void visitOperator( final IParserNode statementNode ) |
| { |
| } |
| |
| /** |
| * @param functionParametersNode |
| */ |
| protected void visitParameters( final IParserNode functionParametersNode ) |
| { |
| if ( isNodeNavigable( functionParametersNode ) ) |
| { |
| for ( final IParserNode node2 : functionParametersNode.getChildren() ) |
| { |
| visitNameTypeInit( node2.getChild( 0 ) ); |
| } |
| } |
| } |
| |
| protected void visitRelationalExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.RELATION, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitShiftExpression( ast ); |
| } |
| } ); |
| } |
| |
| /** |
| * @param ast |
| */ |
| protected void visitReturn( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| visitExpression( ast.getChild( 0 ) ); |
| } |
| } |
| |
| /** |
| * @param statementNode |
| */ |
| protected void visitStatement( final IParserNode statementNode ) |
| { |
| switch ( statementNode.getId() ) |
| { |
| case OP: |
| visitOperator( statementNode ); |
| break; |
| case AS: |
| visitAs( statementNode ); |
| break; |
| case RETURN: |
| visitReturn( statementNode ); |
| break; |
| case IF: |
| visitIf( statementNode ); |
| break; |
| case FOR: |
| visitFor( statementNode ); |
| break; |
| case FOREACH: |
| visitForEach( statementNode ); |
| break; |
| case DO: |
| visitDo( statementNode ); |
| break; |
| case WHILE: |
| visitWhile( statementNode ); |
| break; |
| case SWITCH: |
| visitSwitch( statementNode ); |
| break; |
| case TRY: |
| visitTry( statementNode ); |
| break; |
| case CATCH: |
| visitCatch( statementNode ); |
| break; |
| case FINALLY: |
| visitFinally( statementNode ); |
| break; |
| case STMT_EMPTY: |
| visitEmptyStatetement( statementNode ); |
| break; |
| case LEFT_CURLY_BRACKET: |
| visitBlock( statementNode ); |
| break; |
| default: |
| visitExpressionList( statementNode ); |
| } |
| } |
| |
| /** |
| * @param switchNode |
| */ |
| protected void visitSwitch( final IParserNode switchNode ) |
| { |
| final Iterator< IParserNode > iterator = switchNode.getChildren().iterator(); |
| |
| visitExpression( iterator.next() ); |
| |
| final IParserNode cases = iterator.next(); |
| |
| for ( final IParserNode caseNode : cases.getChildren() ) |
| { |
| final IParserNode child = caseNode.getChild( 0 ); |
| |
| if ( child.is( NodeKind.DEFAULT ) ) |
| { |
| visitSwitchDefaultCase( caseNode.getChild( 1 ) ); |
| } |
| else |
| { |
| visitSwitchCase( caseNode.getChild( 1 ) ); |
| visitExpression( child ); |
| } |
| } |
| } |
| |
| /** |
| * @param switchCaseNode |
| */ |
| protected void visitSwitchCase( final IParserNode switchCaseNode ) |
| { |
| visitBlock( switchCaseNode ); |
| } |
| |
| /** |
| * @param defaultCaseNode |
| */ |
| protected void visitSwitchDefaultCase( final IParserNode defaultCaseNode ) |
| { |
| visitBlock( defaultCaseNode ); |
| } |
| |
| /** |
| * @param ifNode |
| */ |
| protected void visitThen( final IParserNode ifNode ) |
| { |
| visitBlock( ifNode.getChild( 1 ) ); |
| } |
| |
| /** |
| * @param ast |
| */ |
| protected void visitTry( final IParserNode ast ) |
| { |
| visitBlock( ast.getChild( 0 ) ); |
| } |
| |
| /** |
| * @param node |
| */ |
| protected void visitVariableInitialization( final IParserNode node ) |
| { |
| visitExpression( node ); |
| } |
| |
| /** |
| * @param variableNode |
| * @param varOrConst |
| * @param scope |
| */ |
| protected void visitVarOrConstList( final IParserNode variableNode, |
| final VariableOrConstant varOrConst, |
| final VariableScope scope ) |
| { |
| final Iterator< IParserNode > iterator = variableNode.getChildren().iterator(); |
| |
| IParserNode node = iterator.next(); |
| while ( node.is( NodeKind.META_LIST ) |
| || node.is( NodeKind.MOD_LIST ) ) |
| { |
| node = iterator.next(); |
| } |
| while ( node != null ) |
| { |
| visitNameTypeInit( node ); |
| node = iterator.hasNext() ? iterator.next() |
| : null; |
| } |
| } |
| |
| /** |
| * @param whileNode |
| */ |
| protected void visitWhile( final IParserNode whileNode ) |
| { |
| visitCondition( whileNode.getChild( 0 ) ); |
| visitBlock( whileNode.getChild( 1 ) ); |
| } |
| |
| private boolean isAlreadyViolationAdded( final IParserNode nodeToBeAdded ) |
| { |
| for ( final IFlexViolation violation : violations ) |
| { |
| if ( violation.getBeginLine() == nodeToBeAdded.getLine() |
| && violation.getBeginColumn() == nodeToBeAdded.getColumn() ) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean isNodeNavigable( final IParserNode node ) |
| { |
| return node != null |
| && node.numChildren() != 0; |
| } |
| |
| private void visitAdditiveExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.ADD, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitMultiplicativeExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitAndExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.AND, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitBitwiseOrExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitArrayAccessor( final IParserNode ast ) |
| { |
| final Iterator< IParserNode > iterator = ast.getChildren().iterator(); |
| visitExpression( iterator.next() ); |
| do |
| { |
| visitExpression( iterator.next() ); |
| } |
| while ( iterator.hasNext() ); |
| } |
| |
| private void visitBitwiseAndExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.B_AND, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitEqualityExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitBitwiseOrExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.B_OR, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitBitwiseXorExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitBitwiseXorExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.B_XOR, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitBitwiseAndExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitBlock( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| visitStatement( node ); |
| } |
| } |
| else if ( ast != null ) |
| { |
| visitStatement( ast ); |
| } |
| } |
| |
| private void visitClassContent( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| if ( node.is( NodeKind.VAR_LIST ) ) |
| { |
| visitVarOrConstList( node, |
| VariableOrConstant.VARIABLE, |
| VariableScope.IN_CLASS ); |
| } |
| else if ( node.is( NodeKind.CONST_LIST ) ) |
| { |
| visitVarOrConstList( node, |
| VariableOrConstant.CONSTANT, |
| VariableScope.IN_CLASS ); |
| } |
| } |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| if ( node.is( NodeKind.FUNCTION ) ) |
| { |
| visitFunction( node, |
| FunctionType.NORMAL ); |
| } |
| else if ( node.is( NodeKind.SET ) ) |
| { |
| visitFunction( node, |
| FunctionType.SETTER ); |
| } |
| else if ( node.is( NodeKind.GET ) ) |
| { |
| visitFunction( node, |
| FunctionType.GETTER ); |
| } |
| } |
| } |
| } |
| |
| private void visitCompilationUnit( final IParserNode ast ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| if ( node.is( NodeKind.PACKAGE ) |
| && node.numChildren() >= 2 ) |
| { |
| visitPackageContent( node.getChild( 1 ) ); |
| } |
| if ( !node.is( NodeKind.PACKAGE ) |
| && node.numChildren() > 0 ) |
| { |
| visitPackageContent( node ); |
| } |
| } |
| } |
| |
| private void visitConditionalExpression( final IParserNode ast ) |
| { |
| if ( ast != null ) |
| { |
| if ( ast.is( NodeKind.CONDITIONAL ) ) |
| { |
| final Iterator< IParserNode > iterator = ast.getChildren().iterator(); |
| final IParserNode node = iterator.next(); |
| |
| visitOrExpression( node ); |
| |
| while ( iterator.hasNext() ) |
| { |
| visitExpression( iterator.next() ); |
| visitExpression( iterator.next() ); |
| } |
| } |
| else |
| { |
| visitOrExpression( ast ); |
| } |
| } |
| } |
| |
| private void visitEqualityExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.EQUALITY, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitRelationalExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.ASSIGN, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitConditionalExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitExpression( final IParserNode ast, |
| final NodeKind kind, |
| final ExpressionVisitor visitor ) |
| { |
| if ( ast.is( kind ) ) |
| { |
| final Iterator< IParserNode > iterator = ast.getChildren().iterator(); |
| final IParserNode node = iterator.next(); |
| |
| visitor.visitExpression( node ); |
| |
| while ( iterator.hasNext() ) |
| { |
| iterator.next(); |
| visitor.visitExpression( iterator.next() ); |
| } |
| } |
| else |
| { |
| visitor.visitExpression( ast ); |
| } |
| } |
| |
| private void visitExpressionList( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| visitExpression( node ); |
| } |
| } |
| } |
| |
| private void visitFunctionBody( final IParserNode node ) |
| { |
| visitBlock( node ); |
| } |
| |
| private void visitMultiplicativeExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.MULTIPLICATION, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitUnaryExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitNameTypeInit( final IParserNode ast ) |
| { |
| if ( ast != null |
| && ast.numChildren() != 0 ) |
| { |
| final Iterator< IParserNode > iterator = ast.getChildren().iterator(); |
| IParserNode node; |
| |
| iterator.next(); |
| iterator.next(); |
| |
| if ( iterator.hasNext() ) |
| { |
| node = iterator.next(); |
| visitVariableInitialization( node ); |
| } |
| } |
| } |
| |
| private void visitObjectInitialization( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| visitExpression( node.getChild( 1 ) ); |
| } |
| } |
| } |
| |
| private void visitOrExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.OR, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitAndExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitPackageContent( final IParserNode ast ) |
| { |
| if ( isNodeNavigable( ast ) ) |
| { |
| for ( final IParserNode node : ast.getChildren() ) |
| { |
| if ( node.is( NodeKind.CLASS ) ) |
| { |
| visitClass( node ); |
| } |
| else if ( node.is( NodeKind.INTERFACE ) ) |
| { |
| visitInterface( node ); |
| } |
| } |
| } |
| } |
| |
| private void visitPrimaryExpression( final IParserNode ast ) |
| { |
| if ( ast.is( NodeKind.NEW ) ) |
| { |
| visitNewExpression( ast ); |
| } |
| else if ( ast.numChildren() != 0 |
| && ast.is( NodeKind.ARRAY ) ) |
| { |
| visitExpressionList( ast ); |
| } |
| else if ( ast.is( NodeKind.OBJECT ) ) |
| { |
| visitObjectInitialization( ast ); |
| } |
| else if ( ast.is( NodeKind.E4X_ATTR ) ) |
| { |
| final IParserNode node = ast.getChild( 0 ); |
| |
| if ( !node.is( NodeKind.NAME ) |
| && !node.is( NodeKind.STAR ) ) |
| { |
| visitExpression( node ); |
| } |
| } |
| else |
| { |
| visitExpressionList( ast ); |
| } |
| } |
| |
| private void visitShiftExpression( final IParserNode ast ) |
| { |
| visitExpression( ast, |
| NodeKind.SHIFT, |
| new ExpressionVisitor() |
| { |
| public void visitExpression( final IParserNode ast ) |
| { |
| visitAdditiveExpression( ast ); |
| } |
| } ); |
| } |
| |
| private void visitUnaryExpression( final IParserNode ast ) |
| { |
| switch ( ast.getId() ) |
| { |
| case PRE_INC: |
| case PRE_DEC: |
| case MINUS: |
| case PLUS: |
| visitUnaryExpression( ast.getChild( 0 ) ); |
| break; |
| default: |
| visitUnaryExpressionNotPlusMinus( ast ); |
| } |
| } |
| |
| private void visitUnaryExpressionNotPlusMinus( final IParserNode ast ) |
| { |
| switch ( ast.getId() ) |
| { |
| case DELETE: |
| case VOID: |
| case TYPEOF: |
| case NOT: |
| case B_NOT: |
| visitExpression( ast.getChild( 0 ) ); |
| break; |
| default: |
| visitUnaryPostfixExpression( ast ); |
| } |
| } |
| |
| private void visitUnaryPostfixExpression( final IParserNode ast ) |
| { |
| switch ( ast.getId() ) |
| { |
| case ARRAY_ACCESSOR: |
| visitArrayAccessor( ast ); |
| break; |
| case DOT: |
| case E4X_FILTER: |
| visitExpression( ast.getChild( 0 ) ); |
| visitExpression( ast.getChild( 1 ) ); |
| break; |
| case POST_INC: |
| case POST_DEC: |
| visitPrimaryExpression( ast.getChild( 0 ) ); |
| break; |
| case CALL: |
| visitMethodCall( ast ); |
| break; |
| case E4X_STAR: |
| visitExpression( ast.getChild( 0 ) ); |
| break; |
| default: |
| visitPrimaryExpression( ast ); |
| break; |
| } |
| } |
| } |