View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.rules.imports;
    5
    6   import java.util.HashSet;
    7   import java.util.Set;
    8
    9   import net.sourceforge.pmd.AbstractRule;
    10  import net.sourceforge.pmd.ast.ASTCompilationUnit;
    11  import net.sourceforge.pmd.ast.ASTImportDeclaration;
    12  import net.sourceforge.pmd.rules.ImportWrapper;
    13
    14  public class DuplicateImportsRule extends AbstractRule {
    15
    16      private Set<ImportWrapper> singleTypeImports;
    17      private Set<ImportWrapper> importOnDemandImports;
    18
    19      public Object visit(ASTCompilationUnit node, Object data) {
    20          singleTypeImports = new HashSet<ImportWrapper>();
    21          importOnDemandImports = new HashSet<ImportWrapper>();
    22          super.visit(node, data);
    23
    24          // this checks for things like:
    25          // import java.io.*;
    26          // import java.io.File;
    27          for (ImportWrapper thisImportOnDemand : importOnDemandImports) {
    28              for (ImportWrapper thisSingleTypeImport : singleTypeImports) {
    29                  String singleTypeFullName = thisSingleTypeImport.getName();	//java.io.File
    30
    31                  int lastDot = singleTypeFullName.lastIndexOf('.');
    32  				String singleTypePkg = singleTypeFullName.substring(0, lastDot);	//java.io
    33                  String singleTypeName = singleTypeFullName.substring(lastDot + 1);	//File
    34
    35                  if (thisImportOnDemand.getName().equals(singleTypePkg) &&
    36                  		!isDisambiguationImport(node, singleTypePkg, singleTypeName)) {
    37                      addViolation(data, thisSingleTypeImport.getNode(), singleTypeFullName);
    38                  }
    39              }
    40          }
    41          singleTypeImports.clear();
    42          importOnDemandImports.clear();
    43          return data;
    44      }
    45
    46      /**
    47       * Check whether this seemingly duplicate import is actually a disambiguation import.
    48       *
    49       * Example:
    50       * import java.awt.*;
    51  	 * import java.util.*;
    52  	 * import java.util.List;	//Needed because java.awt.List exists
    53       */
    54      private boolean isDisambiguationImport(ASTCompilationUnit node, String singleTypePkg, String singleTypeName) {
    55      	for (ImportWrapper thisImportOnDemand : importOnDemandImports) {	//Loop over .* imports
    56      		if (!thisImportOnDemand.getName().equals(singleTypePkg)) {		//Skip same package
    57      			String fullyQualifiedClassName = thisImportOnDemand.getName() + "." + singleTypeName;
    58      			if (node.getClassTypeResolver().classNameExists(fullyQualifiedClassName)) {
    59      				return true;	//Class exists in another imported package
    60      			}
    61      		}
    62      	}
    63
    64      	String fullyQualifiedClassName = "java.lang." + singleTypeName;
    65      	if (node.getClassTypeResolver().classNameExists(fullyQualifiedClassName)) {
    66  			return true;	//Class exists in another imported package
    67  		}
    68
    69      	return false;	//This really is a duplicate import
    70  	}
    71
    72  	public Object visit(ASTImportDeclaration node, Object data) {
    73          ImportWrapper wrapper = new ImportWrapper(node.getImportedName(), node.getImportedName(), node.getImportedNameNode());
    74
    75          // blahhhh... this really wants to be ASTImportDeclaration to be polymorphic...
    76          if (node.isImportOnDemand()) {
    77              if (importOnDemandImports.contains(wrapper)) {
    78                  addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage());
    79              } else {
    80                  importOnDemandImports.add(wrapper);
    81              }
    82          } else {
    83              if (singleTypeImports.contains(wrapper)) {
    84                  addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage());
    85              } else {
    86                  singleTypeImports.add(wrapper);
    87              }
    88          }
    89          return data;
    90      }
    91
    92  }