You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2014/08/27 00:43:47 UTC
[16/51] [partial] Refactored the PMD Maven build - Adjusted the
directory structure - Fixed a lot of compile problems - Fixed the maven setup
- Made PMD build with Flexmojos 7.1.0 and Apache Flex 4.13.0 - Fixed a few
UnitTests
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRule.java
new file mode 100644
index 0000000..6d0da0f
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRule.java
@@ -0,0 +1,1164 @@
+/*
+ * 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).
+ *
+ * @author xagnetti
+ */
+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;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRuleTest.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRuleTest.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRuleTest.java
new file mode 100644
index 0000000..35aa5e6
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractAstFlexRuleTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.adobe.ac.pmd.IFlexViolation;
+import com.adobe.ac.pmd.files.IAs3File;
+import com.adobe.ac.pmd.files.IFlexFile;
+import com.adobe.ac.pmd.files.IMxmlFile;
+import com.adobe.ac.pmd.nodes.IPackage;
+import com.adobe.ac.pmd.nodes.impl.NodeFactory;
+import com.adobe.ac.pmd.parser.IAS3Parser;
+import com.adobe.ac.pmd.parser.exceptions.TokenException;
+
+import de.bokelberg.flex.parser.AS3Parser;
+
+public abstract class AbstractAstFlexRuleTest extends AbstractFlexRuleTest
+{
+ @Override
+ protected List< IFlexViolation > processFile( final String resourcePath ) throws IOException,
+ TokenException
+ {
+ if ( !getIgnoreFiles().contains( resourcePath ) )
+ {
+ final IAS3Parser parser = new AS3Parser();
+ final IFlexFile file = getTestFiles().get( resourcePath );
+
+ IPackage rootNode = null;
+
+ if ( file == null )
+ {
+ throw new IOException( resourcePath
+ + " is not found" );
+ }
+ if ( file instanceof IAs3File )
+ {
+ rootNode = NodeFactory.createPackage( parser.buildAst( file.getFilePath() ) );
+ }
+ else
+ {
+ rootNode = NodeFactory.createPackage( parser.buildAst( file.getFilePath(),
+ ( ( IMxmlFile ) file ).getScriptBlock() ) );
+ }
+ return getRule().processFile( file,
+ rootNode,
+ getTestFiles() );
+ }
+ return new ArrayList< IFlexViolation >();
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexMetaDataRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexMetaDataRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexMetaDataRule.java
new file mode 100644
index 0000000..a1f0552
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexMetaDataRule.java
@@ -0,0 +1,111 @@
+/*
+ * 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.List;
+
+import com.adobe.ac.pmd.nodes.IAttribute;
+import com.adobe.ac.pmd.nodes.IClass;
+import com.adobe.ac.pmd.nodes.IFunction;
+import com.adobe.ac.pmd.nodes.IMetaDataListHolder;
+
+/**
+ * @author xagnetti
+ */
+public abstract class AbstractFlexMetaDataRule extends AbstractAstFlexRule
+{
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractAstFlexRule#findViolations(com.adobe
+ * .ac.pmd.nodes.IClass)
+ */
+ @Override
+ protected final void findViolations( final IClass classNode )
+ {
+ super.findViolations( classNode );
+
+ if ( classNode.getMetaDataCount() > 0 )
+ {
+ findViolationsFromMetaDataList( classNode );
+ findViolationsFromClassMetaData( classNode );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractAstFlexRule#findViolations(com.adobe
+ * .ac.pmd.nodes.IFunction)
+ */
+ @Override
+ protected final void findViolations( final IFunction function )
+ {
+ if ( function.getMetaDataCount() > 0 )
+ {
+ findViolationsFromMetaDataList( function );
+ findViolationsFromFunctionMetaData( function );
+ }
+ }
+
+ /**
+ * @param function
+ */
+ protected void findViolationsFromAttributeMetaData( final IAttribute attribute )
+ {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractAstFlexRule#findViolationsFromAttributes
+ * (java.util.List)
+ */
+ @Override
+ protected final void findViolationsFromAttributes( final List< IAttribute > variables )
+ {
+ for ( final IAttribute attribute : variables )
+ {
+ if ( attribute.getMetaDataCount() > 0 )
+ {
+ findViolationsFromMetaDataList( attribute );
+ findViolationsFromAttributeMetaData( attribute );
+ }
+ }
+ }
+
+ /**
+ * @param classNode
+ */
+ protected void findViolationsFromClassMetaData( final IClass classNode )
+ {
+ }
+
+ /**
+ * @param function
+ */
+ protected void findViolationsFromFunctionMetaData( final IFunction function )
+ {
+ }
+
+ /**
+ * @param holder
+ */
+ protected void findViolationsFromMetaDataList( final IMetaDataListHolder holder )
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRule.java
new file mode 100644
index 0000000..2611ccf
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRule.java
@@ -0,0 +1,354 @@
+/*
+ * 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.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import net.sourceforge.pmd.CommonAbstractRule;
+import net.sourceforge.pmd.PropertyDescriptor;
+import net.sourceforge.pmd.RuleContext;
+import net.sourceforge.pmd.properties.IntegerProperty;
+import net.sourceforge.pmd.rules.regex.RegexHelper;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.adobe.ac.pmd.IFlexViolation;
+import com.adobe.ac.pmd.files.IFlexFile;
+import com.adobe.ac.pmd.nodes.IPackage;
+import com.adobe.ac.pmd.rules.core.thresholded.IThresholdedRule;
+
+/**
+ * Abstract FlexPMD rule. Extends this class if you want to find violations at a
+ * very low level. Otherwise extends AbstractAstFlexRule, or
+ * AbstractRegexpBasedRule.
+ *
+ * @author xagnetti
+ */
+public abstract class AbstractFlexRule extends CommonAbstractRule implements IFlexRule
+{
+ protected static final String MAXIMUM = "maximum";
+ protected static final String MINIMUM = "minimum";
+ private static final String AS3_COMMENT_TOKEN = "//";
+ private static final Logger LOGGER = Logger.getLogger( AbstractFlexRule.class.getName() );
+ private static final String MXML_COMMENT_TOKEN = "<!--";
+ private IFlexFile currentFile;
+ private IPackage currentPackageNode;
+ private Set< String > excludes;
+ private Map< String, IFlexFile > filesInSourcePath;
+
+ /**
+ *
+ */
+ public AbstractFlexRule()
+ {
+ super();
+
+ setDefaultPriority();
+ }
+
+ /**
+ * not used in FlexPMD
+ */
+ public final void apply( final List< ? > astCompilationUnits,
+ final RuleContext ctx )
+ {
+ }
+
+ /**
+ * @return Extracts the rulename from the qualified name of the underlying
+ * class
+ */
+ public final String getRuleName()
+ {
+ final String qualifiedClassName = this.getClass().getName();
+ final String className = StringUtils.substringAfter( qualifiedClassName,
+ "." );
+
+ return className.replace( "Rule",
+ "" );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.IFlexRule#processFile(com.adobe.ac.pmd.files
+ * .IFlexFile, com.adobe.ac.pmd.nodes.IPackage, java.util.Map)
+ */
+ public final List< IFlexViolation > processFile( final IFlexFile file,
+ final IPackage packageNode,
+ final Map< String, IFlexFile > files )
+ {
+ List< IFlexViolation > violations = new ArrayList< IFlexViolation >();
+
+ currentFile = file;
+ filesInSourcePath = files;
+ currentPackageNode = packageNode;
+
+ if ( isConcernedByTheCurrentFile()
+ && !isFileExcluded( file ) )
+ {
+ onRuleStart();
+ violations = findViolationsInCurrentFile();
+ }
+
+ return violations;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.adobe.ac.pmd.rules.core.IFlexRule#setExcludes(java.util.Set)
+ */
+ public void setExcludes( final Set< String > excludesToBeSet )
+ {
+ excludes = excludesToBeSet;
+ }
+
+ /**
+ * @param violatedLine
+ * @return
+ */
+ boolean isViolationIgnored( final String violatedLine )
+ {
+ final boolean containsNoPmd = lineContainsNoPmd( violatedLine,
+ MXML_COMMENT_TOKEN )
+ || lineContainsNoPmd( violatedLine,
+ AS3_COMMENT_TOKEN );
+
+ if ( !containsNoPmd )
+ {
+ return false;
+ }
+ final String name = getRuleName().replaceAll( "Rule",
+ "" );
+ final String ruleName = name.contains( "." ) ? StringUtils.substringAfterLast( name,
+ "." )
+ : name;
+ final String strippedLine = computeStrippedLine( violatedLine );
+ return strippedLineContainsNoPmdAndRuleName( MXML_COMMENT_TOKEN,
+ ruleName,
+ strippedLine )
+ || strippedLineContainsNoPmdAndRuleName( AS3_COMMENT_TOKEN,
+ ruleName,
+ strippedLine );
+ }
+
+ /**
+ * @param violations
+ * @param position
+ * @return
+ */
+ protected final IFlexViolation addViolation( final List< IFlexViolation > violations,
+ final ViolationPosition position )
+ {
+ final IFlexViolation violation = new Violation( position, this, getCurrentFile() );
+ final int beginLine = position.getBeginLine();
+
+ prettyPrintMessage( violation );
+
+ if ( beginLine == -1
+ || beginLine == 0 )
+ {
+ violations.add( violation );
+ }
+ else if ( beginLine <= getCurrentFile().getLinesNb() )
+ {
+ if ( isViolationIgnored( getCurrentFile().getLineAt( beginLine ) ) )
+ {
+ LOGGER.info( getRuleName()
+ + " has been ignored in " + getCurrentFile().getFilename() + " (" + beginLine + ")" );
+ }
+ else
+ {
+ violations.add( violation );
+ }
+ }
+
+ return violation;
+ }
+
+ protected final IFlexViolation addViolation( final List< IFlexViolation > violations,
+ final ViolationPosition position,
+ final String... messageToReplace )
+ {
+ final IFlexViolation violation = addViolation( violations,
+ position );
+
+ for ( int i = 0; i < messageToReplace.length; i++ )
+ {
+ violation.replacePlaceholderInMessage( messageToReplace[ i ],
+ i );
+ }
+
+ return violation;
+ }
+
+ /**
+ * @return
+ */
+ protected abstract List< IFlexViolation > findViolationsInCurrentFile();
+
+ /**
+ * @return the current file under investigation
+ */
+ protected IFlexFile getCurrentFile()
+ {
+ return currentFile;
+ }
+
+ /**
+ * @return
+ */
+ protected final IPackage getCurrentPackageNode()
+ {
+ return currentPackageNode;
+ }
+
+ /**
+ * @return
+ */
+ protected abstract ViolationPriority getDefaultPriority();
+
+ /**
+ * @return
+ */
+ protected final Map< String, IFlexFile > getFilesInSourcePath()
+ {
+ return filesInSourcePath;
+ }
+
+ /**
+ * @param rule
+ * @return
+ */
+ protected final Map< String, PropertyDescriptor > getThresholdedRuleProperties( final IThresholdedRule rule )
+ {
+ final Map< String, PropertyDescriptor > properties = new LinkedHashMap< String, PropertyDescriptor >();
+
+ properties.put( rule.getThresholdName(),
+ new IntegerProperty( rule.getThresholdName(),
+ "",
+ rule.getDefaultThreshold(),
+ properties.size() ) );
+
+ return properties;
+ }
+
+ /**
+ * @return is this rule concerned by the current file
+ */
+ protected abstract boolean isConcernedByTheCurrentFile();
+
+ /**
+ * Called when the rule is started on the current file
+ */
+ protected void onRuleStart()
+ {
+ }
+
+ private String computeStrippedLine( final String violatedLine )
+ {
+ final String comment_token = getCurrentFile().isMxml() ? MXML_COMMENT_TOKEN
+ : AS3_COMMENT_TOKEN;
+ String strippedLine = violatedLine;
+
+ if ( violatedLine.indexOf( comment_token
+ + " N" ) > 0 )
+ {
+ strippedLine = StringUtils.strip( violatedLine.substring( violatedLine.indexOf( comment_token
+ + " N" ) ) );
+ }
+ else if ( violatedLine.indexOf( comment_token
+ + "N" ) > 0 )
+ {
+ strippedLine = StringUtils.strip( violatedLine.substring( violatedLine.indexOf( comment_token
+ + "N" ) ) );
+ }
+ return strippedLine;
+ }
+
+ private boolean isFileExcluded( final IFlexFile file )
+ {
+ if ( excludes != null )
+ {
+ for ( final String exclusion : excludes )
+ {
+ final Pattern pattern = Pattern.compile( exclusion );
+
+ if ( RegexHelper.isMatch( pattern,
+ file.getFilePath() ) )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean lineContainsNoPmd( final String violatedLine,
+ final String comment_token )
+ {
+ return violatedLine.contains( comment_token
+ + " No PMD" )
+ || violatedLine.contains( comment_token
+ + " NO PMD" ) || violatedLine.contains( comment_token
+ + " NOPMD" ) || violatedLine.contains( comment_token
+ + "NOPMD" );
+ }
+
+ private void prettyPrintMessage( final IFlexViolation violation )
+ {
+ final int nbOfBraces = violation.getRuleMessage().split( "\\{" ).length - 1;
+
+ if ( this instanceof IThresholdedRule )
+ {
+ final IThresholdedRule thresholdeRule = ( IThresholdedRule ) this;
+
+ violation.replacePlaceholderInMessage( String.valueOf( thresholdeRule.getThreshold() ),
+ nbOfBraces - 2 );
+ violation.replacePlaceholderInMessage( String.valueOf( thresholdeRule.getActualValueForTheCurrentViolation() ),
+ nbOfBraces - 1 );
+ }
+ if ( getDescription() != null )
+ {
+ violation.appendToMessage( ". " );
+ violation.appendToMessage( getDescription() );
+ }
+ }
+
+ private void setDefaultPriority()
+ {
+ setPriority( Integer.valueOf( getDefaultPriority().toString() ) );
+ }
+
+ private boolean strippedLineContainsNoPmdAndRuleName( final String comment_token,
+ final String ruleName,
+ final String strippedLine )
+ {
+ return strippedLine.endsWith( comment_token
+ + " No PMD" )
+ || strippedLine.endsWith( comment_token
+ + " NO PMD" ) || strippedLine.endsWith( comment_token
+ + " NOPMD" ) || strippedLine.endsWith( comment_token
+ + "NOPMD" ) || strippedLine.contains( ruleName );
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRuleTest.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRuleTest.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRuleTest.java
new file mode 100644
index 0000000..ac44b0c
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractFlexRuleTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.adobe.ac.pmd.FlexPmdTestBase;
+import com.adobe.ac.pmd.IFlexViolation;
+import com.adobe.ac.pmd.files.IFlexFile;
+import com.adobe.ac.pmd.parser.exceptions.TokenException;
+
+public abstract class AbstractFlexRuleTest extends FlexPmdTestBase
+{
+ final static class AssertPosition
+ {
+ public static AssertPosition create( final String message,
+ final int expectedLine,
+ final int actualLine )
+ {
+ return new AssertPosition( message, expectedLine, actualLine );
+ }
+
+ public int actualLine;
+ public int expectedLine;
+ public String message;
+
+ private AssertPosition( final String messageToBeSet,
+ final int expectedLineToBeSet,
+ final int actualLineToBeSet )
+ {
+ super();
+ message = messageToBeSet;
+ expectedLine = expectedLineToBeSet;
+ actualLine = actualLineToBeSet;
+ }
+ }
+
+ protected final static class ExpectedViolation
+ {
+ protected String file;
+ protected ViolationPosition[] positions;
+
+ public ExpectedViolation( final String fileToBeSet,
+ final ViolationPosition[] positionsToBeSet )
+ {
+ super();
+ file = fileToBeSet;
+ positions = positionsToBeSet;
+ }
+ }
+
+ protected static StringBuffer buildFailuresMessage( final List< AssertPosition > failures )
+ {
+ final StringBuffer message = new StringBuffer( 42 );
+
+ for ( final AssertPosition assertPosition : failures )
+ {
+ message.append( assertPosition.message
+ + ": expected <" + assertPosition.expectedLine + "> but actually <"
+ + assertPosition.actualLine + ">\n" );
+ }
+ return message;
+ }
+
+ protected static List< AssertPosition > buildFailureViolations( final String resourcePath,
+ final ViolationPosition[] expectedPositions,
+ final List< IFlexViolation > violations )
+ {
+ List< AssertPosition > failures;
+ failures = new ArrayList< AssertPosition >();
+
+ for ( int i = 0; i < expectedPositions.length; i++ )
+ {
+ final IFlexViolation violation = violations.get( i );
+ final ViolationPosition expectedPosition = expectedPositions[ i ];
+
+ if ( expectedPosition.getBeginLine() != violation.getBeginLine() )
+ {
+ failures.add( AssertPosition.create( BEGIN_LINE_NOT_CORRECT
+ + " at " + i + "th violation on " + resourcePath,
+ expectedPosition.getBeginLine(),
+ violation.getBeginLine() ) );
+ }
+ if ( expectedPosition.getEndLine() != violation.getEndLine() )
+ {
+ failures.add( AssertPosition.create( END_LINE_NOT_CORRECT
+ + " at " + i + "th violation on " + resourcePath,
+ expectedPosition.getEndLine(),
+ violation.getEndLine() ) );
+ }
+ }
+ return failures;
+ }
+
+ protected static StringBuffer buildMessageName( final Map< String, List< IFlexViolation >> violatedFiles )
+ {
+ final StringBuffer buffer = new StringBuffer( 100 );
+
+ for ( final String violatedFileName : violatedFiles.keySet() )
+ {
+ final List< IFlexViolation > violations = violatedFiles.get( violatedFileName );
+
+ buffer.append( violatedFileName
+ + " should not contain any violations " + " (" + violations.size() + " found" );
+
+ if ( violations.size() == 1 )
+ {
+ buffer.append( " at "
+ + violations.get( 0 ).getBeginLine() + ":" + violations.get( 0 ).getEndLine() );
+ }
+ buffer.append( ")\n" );
+ }
+ return buffer;
+ }
+
+ /**
+ * Test case which contains non-concerned files by the given rule
+ *
+ * @throws TokenException
+ * @throws IOException
+ */
+ @Test
+ public final void testProcessNonViolatingFiles() throws IOException,
+ TokenException
+ {
+ final Map< String, List< IFlexViolation >> violatedFiles = extractActualViolatedFiles();
+ final StringBuffer buffer = buildMessageName( violatedFiles );
+
+ if ( !violatedFiles.isEmpty() )
+ {
+ fail( buffer.toString() );
+ }
+ }
+
+ /**
+ * Test case which contains violating files
+ */
+ @Test
+ public final void testProcessViolatingFiles()
+ {
+ final Map< String, ViolationPosition[] > expectedPositions = computeExpectedViolations( getExpectedViolatingFiles() );
+
+ for ( final String fileName : expectedPositions.keySet() )
+ {
+ assertViolations( fileName,
+ expectedPositions.get( fileName ) );
+ }
+ }
+
+ protected abstract ExpectedViolation[] getExpectedViolatingFiles();
+
+ protected List< String > getIgnoreFiles()
+ {
+ return new ArrayList< String >();
+ }
+
+ protected abstract AbstractFlexRule getRule();
+
+ protected List< IFlexViolation > processFile( final String resourcePath ) throws IOException,
+ TokenException
+ {
+ if ( !getIgnoreFiles().contains( resourcePath ) )
+ {
+ return getRule().processFile( getTestFiles().get( resourcePath ),
+ null,
+ getTestFiles() );
+ }
+ return new ArrayList< IFlexViolation >();
+ }
+
+ private void assertViolations( final String resourcePath,
+ final ViolationPosition[] expectedPositions )
+ {
+ try
+ {
+ final List< IFlexViolation > violations = processFile( resourcePath );
+
+ assertEquals( VIOLATIONS_NUMBER_NOT_CORRECT
+ + " for " + resourcePath,
+ expectedPositions.length,
+ violations.size() );
+
+ if ( expectedPositions.length != 0 )
+ {
+ printFailures( buildFailureViolations( resourcePath,
+ expectedPositions,
+ violations ) );
+ }
+ }
+ catch ( final IOException e )
+ {
+ fail( e.getMessage() );
+ }
+ catch ( final TokenException e )
+ {
+ fail( e.getMessage() );
+ }
+ }
+
+ private Map< String, ViolationPosition[] > computeExpectedViolations( final ExpectedViolation[] expectedViolatingFiles )
+ {
+ final Map< String, ViolationPosition[] > expectedViolations = new LinkedHashMap< String, ViolationPosition[] >();
+
+ for ( final ExpectedViolation expectedViolatingFile : expectedViolatingFiles )
+ {
+ expectedViolations.put( expectedViolatingFile.file,
+ expectedViolatingFile.positions );
+ }
+ return expectedViolations;
+ }
+
+ private Map< String, List< IFlexViolation >> extractActualViolatedFiles() throws IOException,
+ TokenException
+ {
+ final Map< String, List< IFlexViolation > > violatedFiles = new LinkedHashMap< String, List< IFlexViolation > >();
+ final Map< String, ViolationPosition[] > expectedPositions = computeExpectedViolations( getExpectedViolatingFiles() );
+
+ for ( final Map.Entry< String, IFlexFile > fileNameEntry : getTestFiles().entrySet() )
+ {
+ if ( !expectedPositions.containsKey( fileNameEntry.getKey() ) )
+ {
+ final List< IFlexViolation > violations = processFile( fileNameEntry.getKey() );
+
+ if ( !violations.isEmpty() )
+ {
+ violatedFiles.put( fileNameEntry.getKey(),
+ violations );
+ }
+ }
+ }
+ return violatedFiles;
+ }
+
+ private void printFailures( final List< AssertPosition > failures )
+ {
+ if ( !failures.isEmpty() )
+ {
+ fail( buildFailuresMessage( failures ).toString() );
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractForbiddenImportRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractForbiddenImportRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractForbiddenImportRule.java
new file mode 100644
index 0000000..5c54876
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractForbiddenImportRule.java
@@ -0,0 +1,58 @@
+/*
+ * 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 com.adobe.ac.pmd.nodes.IPackage;
+import com.adobe.ac.pmd.parser.IParserNode;
+
+/**
+ * @author xagnetti
+ */
+public abstract class AbstractForbiddenImportRule extends AbstractAstFlexRule
+{
+
+ /**
+ *
+ */
+ public AbstractForbiddenImportRule()
+ {
+ super();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractAstFlexRule#findViolations(com.adobe
+ * .ac.pmd.nodes.IPackage)
+ */
+ @Override
+ protected final void findViolations( final IPackage packageNode )
+ {
+ for ( final IParserNode importNode : packageNode.getImports() )
+ {
+ if ( importNode.getStringValue().contains( getForbiddenImport() ) )
+ {
+ addViolation( importNode );
+ }
+ }
+ }
+
+ /**
+ * @return
+ */
+ protected abstract String getForbiddenImport();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractPrimaryAstRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractPrimaryAstRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractPrimaryAstRule.java
new file mode 100644
index 0000000..7479a2a
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractPrimaryAstRule.java
@@ -0,0 +1,86 @@
+/*
+ * 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.List;
+
+import com.adobe.ac.pmd.nodes.IFunction;
+import com.adobe.ac.pmd.parser.IParserNode;
+
+/**
+ * Abstract rule which find a primary (or a couple of primaries) in a body
+ * function.
+ *
+ * @author xagnetti
+ */
+public abstract class AbstractPrimaryAstRule extends AbstractAstFlexRule
+{
+ /**
+ * @param statement
+ * @param function
+ */
+ protected abstract void addViolation( IParserNode statement,
+ IFunction function );
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractAstFlexRule#findViolations(com.adobe
+ * .ac.pmd.nodes.IFunction)
+ */
+ @Override
+ protected final void findViolations( final IFunction function )
+ {
+ final List< IParserNode > firstStatements = function.findPrimaryStatementsInBody( getFirstPrimaryToFind() );
+ if ( !firstStatements.isEmpty() )
+ {
+ for ( final IParserNode firstStatement : firstStatements )
+ {
+ if ( getSecondPrimaryToFind() == null )
+ {
+ addViolation( firstStatement,
+ function );
+ }
+ else
+ {
+ final List< IParserNode > secondStatements = function.findPrimaryStatementsInBody( getSecondPrimaryToFind() );
+ if ( !secondStatements.isEmpty() )
+ {
+ for ( final IParserNode secondStatement : secondStatements )
+ {
+ addViolation( secondStatement,
+ function );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return
+ */
+ protected abstract String getFirstPrimaryToFind();
+
+ /**
+ * @return
+ */
+ protected String getSecondPrimaryToFind()
+ {
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegExpBasedRuleTest.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegExpBasedRuleTest.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegExpBasedRuleTest.java
new file mode 100644
index 0000000..527e1cf
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegExpBasedRuleTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public abstract class AbstractRegExpBasedRuleTest extends AbstractFlexRuleTest
+{
+ @Test
+ public void testDoesCurrentLineMacthCorrectLine()
+ {
+ final AbstractRegexpBasedRule rule = getRegexpBasedRule();
+
+ if ( getMatchableLines().length == 0 )
+ {
+ Assert.fail( "the getMatchableLines() is empty" );
+ }
+ for ( int i = 0; i < getMatchableLines().length; i++ )
+ {
+ final String correctLine = getMatchableLines()[ i ];
+
+ assertTrue( "This line (\""
+ + correctLine + "\") should be matched",
+ rule.doesCurrentLineMacthes( correctLine ) );
+ }
+ }
+
+ @Test
+ public void testDoesCurrentLineMacthIncorrectLine()
+ {
+ final AbstractRegexpBasedRule rule = getRegexpBasedRule();
+
+ if ( getUnmatchableLines().length == 0 )
+ {
+ Assert.fail( "the getUnmatchableLines() is empty" );
+ }
+ for ( int i = 0; i < getUnmatchableLines().length; i++ )
+ {
+ final String incorrectLine = getUnmatchableLines()[ i ];
+
+ assertFalse( "This line (\""
+ + incorrectLine + "\") should not be matched",
+ rule.doesCurrentLineMacthes( incorrectLine ) );
+ }
+ }
+
+ protected abstract String[] getMatchableLines();
+
+ protected abstract AbstractRegexpBasedRule getRegexpBasedRule();
+
+ @Override
+ protected AbstractFlexRule getRule()
+ {
+ return getRegexpBasedRule();
+ }
+
+ protected abstract String[] getUnmatchableLines();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegexpBasedRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegexpBasedRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegexpBasedRule.java
new file mode 100644
index 0000000..cfc71de
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractRegexpBasedRule.java
@@ -0,0 +1,116 @@
+/*
+ * 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.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.adobe.ac.pmd.IFlexViolation;
+
+/**
+ * @author xagnetti
+ */
+public abstract class AbstractRegexpBasedRule extends AbstractFlexRule
+{
+ private Pattern pattern;
+
+ /**
+ *
+ */
+ public AbstractRegexpBasedRule()
+ {
+ super();
+ compilePattern();
+ }
+
+ /**
+ *
+ */
+ public final void compilePattern()
+ {
+ pattern = Pattern.compile( getRegexp() );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractFlexRule#findViolationsInCurrentFile()
+ */
+ @Override
+ public final List< IFlexViolation > findViolationsInCurrentFile()
+ {
+ final List< IFlexViolation > violations = new ArrayList< IFlexViolation >();
+
+ if ( "".compareTo( getRegexp() ) != 0 )
+ {
+ for ( int i = 1; i <= getCurrentFile().getLinesNb(); i++ )
+ {
+ final String line = getCurrentFile().getLineAt( i );
+
+ if ( isCurrentLineConcerned( line )
+ && doesCurrentLineMacthes( line ) && isViolationDetectedOnThisMatchingLine( line )
+ && !line.contains( "/*" ) && !line.contains( "//" ) )
+ {
+ addViolation( violations,
+ ViolationPosition.create( i,
+ i,
+ 0,
+ line.length() ) );
+ }
+ }
+ }
+ return violations;
+ }
+
+ /**
+ * @param line
+ * @return
+ */
+ final boolean doesCurrentLineMacthes( final String line )
+ {
+ return getMatcher( line ).matches();
+ }
+
+ /**
+ * @param line
+ * @return
+ */
+ protected final Matcher getMatcher( final String line )
+ {
+ final Matcher matcher = pattern.matcher( line );
+
+ return matcher;
+ }
+
+ /**
+ * @return
+ */
+ protected abstract String getRegexp();
+
+ protected boolean isCurrentLineConcerned( final String line )
+ {
+ return true;
+ }
+
+ /**
+ * @param line
+ * @return
+ */
+ protected abstract boolean isViolationDetectedOnThisMatchingLine( final String line );
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractXpathRelatedRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractXpathRelatedRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractXpathRelatedRule.java
new file mode 100644
index 0000000..72dadfb
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/AbstractXpathRelatedRule.java
@@ -0,0 +1,244 @@
+/*
+ * 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.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import com.adobe.ac.pmd.IFlexViolation;
+import com.adobe.ac.utils.StackTraceUtils;
+
+/**
+ * @author xagnetti
+ */
+public abstract class AbstractXpathRelatedRule extends AbstractFlexRule
+{
+ /**
+ * @author xagnetti
+ */
+ public class NamespaceContextMap implements NamespaceContext
+ {
+ private final Map< String, String > prefixMap;
+
+ /**
+ * Constructor that takes a map of XML prefix-namespaceURI values. A
+ * defensive copy is made of the map. An IllegalArgumentException will be
+ * thrown if the map attempts to remap the standard prefixes defined in
+ * the NamespaceContext contract.
+ *
+ * @param prefixMappings a map of prefix:namespaceURI values
+ */
+ public NamespaceContextMap( final Map< String, String > prefixMappings )
+ {
+ prefixMap = createPrefixMap( prefixMappings );
+ }
+
+ /**
+ * Convenience constructor.
+ *
+ * @param mappingPairs pairs of prefix-namespaceURI values
+ */
+ public NamespaceContextMap( final String... mappingPairs )
+ {
+ this( toMap( mappingPairs ) );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * javax.xml.namespace.NamespaceContext#getNamespaceURI(java.lang.String)
+ */
+ public String getNamespaceURI( final String prefix )
+ {
+ prefixMap.get( prefix );
+ return prefixMap.get( prefix );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see javax.xml.namespace.NamespaceContext#getPrefix(java.lang.String)
+ */
+ public String getPrefix( final String namespaceURI )
+ {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String)
+ */
+ public Iterator< String > getPrefixes( final String namespaceURI )
+ {
+ return null;
+ }
+
+ private void addConstant( final Map< String, String > map,
+ final String prefix,
+ final String nsURI )
+ {
+ map.put( prefix,
+ nsURI );
+ }
+
+ private Map< String, String > createPrefixMap( final Map< String, String > prefixMappings )
+ {
+ final Map< String, String > map = new LinkedHashMap< String, String >( prefixMappings );
+ addConstant( map,
+ XMLConstants.XML_NS_PREFIX,
+ XMLConstants.XML_NS_URI );
+ addConstant( map,
+ XMLConstants.XMLNS_ATTRIBUTE,
+ XMLConstants.XMLNS_ATTRIBUTE_NS_URI );
+ return Collections.unmodifiableMap( map );
+ }
+
+ }
+
+ protected static final Logger LOGGER = Logger.getLogger( AbstractXpathRelatedRule.class.getName() );
+
+ private static Map< String, String > toMap( final String... mappingPairs )
+ {
+ final Map< String, String > prefixMappings = new LinkedHashMap< String, String >( mappingPairs.length / 2 );
+ for ( int i = 0; i < mappingPairs.length; i++ )
+ {
+ prefixMappings.put( mappingPairs[ i ],
+ mappingPairs[ ++i ] );
+ }
+ return prefixMappings;
+ }
+
+ /**
+ * @param doc
+ * @param xPath
+ * @return
+ * @throws XPathExpressionException
+ */
+ protected abstract Object evaluate( final Document doc,
+ final XPath xPath ) throws XPathExpressionException;
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractFlexRule#findViolationsInCurrentFile()
+ */
+ @Override
+ protected List< IFlexViolation > findViolationsInCurrentFile()
+ {
+ final ArrayList< IFlexViolation > violations = new ArrayList< IFlexViolation >();
+
+ try
+ {
+ final Document doc = buildDocument();
+ final XPath xPath = buildXPath();
+
+ onEvaluated( violations,
+ doc,
+ xPath );
+ }
+ catch ( final XPathExpressionException e )
+ {
+ LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(),
+ e ) );
+ }
+ catch ( final FileNotFoundException e )
+ {
+ LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(),
+ e ) );
+ }
+ catch ( final ParserConfigurationException e )
+ {
+ LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(),
+ e ) );
+ }
+ catch ( final SAXException e )
+ {
+ LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(),
+ e ) );
+ }
+ catch ( final IOException e )
+ {
+ LOGGER.warning( StackTraceUtils.print( getCurrentFile().getFilename(),
+ e ) );
+ }
+
+ return violations;
+ }
+
+ /**
+ * @return
+ */
+ protected abstract String getXPathExpression();
+
+ /*
+ * (non-Javadoc)
+ * @see
+ * com.adobe.ac.pmd.rules.core.AbstractFlexRule#isConcernedByTheCurrentFile()
+ */
+ @Override
+ protected boolean isConcernedByTheCurrentFile()
+ {
+ return getCurrentFile().isMxml();
+ }
+
+ /**
+ * @param violations
+ * @param doc
+ * @param xPath
+ * @throws XPathExpressionException
+ */
+ protected abstract void onEvaluated( final List< IFlexViolation > violations,
+ final Document doc,
+ final XPath xPath ) throws XPathExpressionException;
+
+ private Document buildDocument() throws ParserConfigurationException,
+ SAXException,
+ IOException
+ {
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware( true );
+ final DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse( getCurrentFile().getFilePath() );
+ }
+
+ private XPath buildXPath()
+ {
+ final XPathFactory xPathFactory = XPathFactory.newInstance();
+ final XPath xPath = xPathFactory.newXPath();
+ xPath.setNamespaceContext( new NamespaceContextMap( "mx", "http://www.adobe.com/2006/mxml" ) );
+ return xPath;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexAstRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexAstRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexAstRule.java
new file mode 100644
index 0000000..7cfcee4
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexAstRule.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+/**
+ * @author xagnetti
+ */
+public interface IFlexAstRule extends IFlexRule
+{
+ /**
+ * @return true if the current file is concerned
+ */
+ boolean isConcernedByTheCurrentFile();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/e43b7a87/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexRule.java
----------------------------------------------------------------------
diff --git a/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexRule.java b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexRule.java
new file mode 100644
index 0000000..3eb94e4
--- /dev/null
+++ b/FlexPMD/flex-pmd-java/flex-pmd-ruleset-api/src/main/java/com/adobe/ac/pmd/rules/core/IFlexRule.java
@@ -0,0 +1,53 @@
+/*
+ * 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.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.sourceforge.pmd.Rule;
+
+import com.adobe.ac.pmd.IFlexViolation;
+import com.adobe.ac.pmd.files.IFlexFile;
+import com.adobe.ac.pmd.nodes.IPackage;
+
+/**
+ * @author xagnetti
+ */
+public interface IFlexRule extends Rule
+{
+ /**
+ * @return ruleName
+ */
+ String getRuleName();
+
+ /**
+ * @param file
+ * @param rootNode
+ * @param files
+ * @return
+ */
+ List< IFlexViolation > processFile( final IFlexFile file,
+ final IPackage rootNode,
+ final Map< String, IFlexFile > files );
+
+ /**
+ * @param excludes
+ */
+ void setExcludes( final Set< String > excludes );
+}
\ No newline at end of file