Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Podgursky committed Jun 30, 2014
0 parents commit 4078d83
Show file tree
Hide file tree
Showing 8 changed files with 518 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
54 changes: 54 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.liveramp</groupId>
<artifactId>pmd_extensions</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>pmd_extensions</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<repository>
<id>liveramp-repositories</id>
<name>Liveramp Repositories</name>
<url>http://repository.liveramp.com/artifactory/liveramp-repositories</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>

<distributionManagement>
<snapshotRepository>
<id>artifactory.liveramp.net</id>
<name>artifactory.liveramp.net-snapshots</name>
<url>http://repository.liveramp.com/artifactory/libs-snapshot-local</url>
</snapshotRepository>
<repository>
<id>repository.liveramp.com</id>
<name>repository.liveramp.com-releases</name>
<url>http://repository.liveramp.com/artifactory/libs-release-local</url>
</repository>
</distributionManagement>

<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>5.0.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>13.0.1</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.liveramp.pmd_extensions;

import java.util.List;

import com.google.common.collect.Lists;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;

/**
* Prevent a class from being instantiated or imported. See example usage in example_ruleset.xml
*
* TODO prevent it from being used statically fully qualified
*/
public class BlacklistClassUsages extends AbstractJavaRule {
private static final String LIST_NAME = "BlacklistedClasses";

public BlacklistClassUsages(){
definePropertyDescriptor(new StringProperty(LIST_NAME, "List of classes to blacklist", "", 0));
}

@Override
public void start(RuleContext ctx) {
List<String> blacklistedClasses = Lists.newArrayList();
Object prop = getProperty(getPropertyDescriptor(LIST_NAME));
for (String className : prop.toString().split(",")) {
blacklistedClasses.add(className.trim());
}
ctx.setAttribute(LIST_NAME, blacklistedClasses);
}

private static List<String> getFromContext(Object data){
RuleContext ctx = (RuleContext)data;
return (List<String>)ctx.getAttribute(LIST_NAME);
}

/**
* Check whether the class was imported
*/
@Override
public Object visit(ASTImportDeclaration node, Object data) {

String img = node.jjtGetChild(0).getImage();
for (String blacklistedClass : getFromContext(data)) {
if (img.startsWith(blacklistedClass)) {
addViolation(data, node);
}
}
return data;
}

/**
* Check if the class was instantiated
*/
@Override
public Object visit(ASTAllocationExpression node, Object data) {

if (!(node.jjtGetChild(0) instanceof ASTClassOrInterfaceType)) {
return data;
}

for (String blockedClass : getFromContext(data)) {
if (PmdHelper.isSubclass((ASTClassOrInterfaceType) node.jjtGetChild(0), blockedClass)){
addViolation(data, node);
}
}

return data;
}
}
127 changes: 127 additions & 0 deletions src/main/java/com/liveramp/pmd_extensions/BlacklistMethods.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.liveramp.pmd_extensions;

import java.util.List;

import com.google.common.collect.Lists;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;

/**
* Fail any build which uses certain methods on particular classes. Example configuration in rule set:
*
<property name="BlacklistedMethods" value="
java.lang.String:getBytes:0,
java.nio.ByteBuffer:array,
"/>
* Here, the getBytes method on String with arity 0 is banned, and the array method on ByteBuffer (with any arity)
* is banned
*/
public class BlacklistMethods extends AbstractJavaRule {
private static final String LIST_NAME = "BlacklistedMethods";

public BlacklistMethods() {
definePropertyDescriptor(new StringProperty(LIST_NAME, "List of methods to blacklist", "", 0));
}

@Override
public void start(RuleContext ctx) {
List<BlacklistedCall> blockedCalls = Lists.newArrayList();
Object prop = getProperty(getPropertyDescriptor(LIST_NAME));
for (String reference : prop.toString().split(",")) {
blockedCalls.add(parseRef(reference.trim()));
}
ctx.setAttribute(LIST_NAME, blockedCalls);
}

private BlacklistedCall parseRef(String s){
String[] parts = s.split(":");
if(parts.length == 2){
return new BlacklistedCall(parts[0], parts[1]);
}
if(parts.length == 3){
return new BlacklistedCall(parts[0], parts[1], Integer.parseInt(parts[2]));
}
throw new RuntimeException("Cannot parse method reference: "+s+"!");
}

public Object visit(ASTVariableDeclaratorId node, Object data) {
List<BlacklistedCall> blockedCalls = getFromContext(data);

for (BlacklistedCall call : blockedCalls) {
String ruleClass = call.getRuleClass();

if (PmdHelper.isSubclass(node, ruleClass)) {
boolean isArray = node.isArray();
for (NameOccurrence occ : node.getUsages()) {
NameOccurrence qualifier = occ.getNameForWhichThisIsAQualifier();

if (qualifier != null) {
String ruleMethodName = call.getRuleMethodName();

if (!isArray && qualifier.getImage().equals(ruleMethodName)) {
Integer argumentCount = call.getArgumentCount();

if (argumentCount == null || argumentCount == qualifier.getArgumentCount()) {
addViolation(data, occ.getLocation(),
"Blacklisted method call: "+ ruleClass +"."+ ruleMethodName +"{"+ argumentCount +"}");
}
}
// I don't know what this case catches...
else if (isArray
&& qualifier.getLocation() != null
&& !ASTName.class.equals(qualifier.getLocation().getClass())
&& qualifier.getImage().equals(ruleMethodName)) {
addViolation(data, occ.getLocation());
}
}
}
}
}
return data;
}

private static List<BlacklistedCall> getFromContext(Object data){
RuleContext ctx = (RuleContext)data;
return (List<BlacklistedCall>)ctx.getAttribute(LIST_NAME);
}

/**
* Check for static methods
*/
@Override
public Object visit(ASTPrimaryPrefix node, Object data) {

if (node.jjtGetNumChildren() == 0) {
return data;
}

Node node1 = node.jjtGetChild(0);
String image = node1.getImage();

if(image == null){
return data;
}

for (BlacklistedCall blacklistedCall : getFromContext(data)) {
if (node1 instanceof TypeNode) {
TypeNode tn = (TypeNode) node1;
if (PmdHelper.isSubclass(tn, blacklistedCall.getRuleClass())) {
if (image.equals(blacklistedCall.getImportedStaticImage())
|| image.equals(blacklistedCall.getFullStaticImage())) {
addViolation(data, node);
}
}
}
}

return data;
}
}
56 changes: 56 additions & 0 deletions src/main/java/com/liveramp/pmd_extensions/BlacklistedCall.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.liveramp.pmd_extensions;

public class BlacklistedCall {

private final String ruleClass;
private final String ruleClassName;
private final String ruleMethodName;
private final Integer argumentCount;

private final String staticImported;
private final String staticFull;

public BlacklistedCall(String ruleClass, String ruleMethodName) {
this(ruleClass, ruleMethodName, null);
}

public BlacklistedCall(String ruleClass, String ruleMethodName, Integer argumentCount) {
this.ruleClass = ruleClass;
this.ruleMethodName = ruleMethodName;
this.argumentCount = argumentCount;

String[] parts = ruleClass.split("\\.");
if(parts.length < 1){
throw new RuntimeException("Unrecognized classname: "+ruleClass);
}
ruleClassName = parts[parts.length-1];

this.staticImported = ruleClassName+"."+ruleMethodName;
this.staticFull = ruleClass+"."+ruleMethodName;

}

public String getRuleClass() {
return ruleClass;
}

public String getRuleMethodName() {
return ruleMethodName;
}

public Integer getArgumentCount() {
return argumentCount;
}

public String getRuleClassName() {
return ruleClassName;
}

public String getImportedStaticImage() {
return staticImported;
}

public String getFullStaticImage(){
return staticFull;
}
}
Loading

0 comments on commit 4078d83

Please sign in to comment.