Skip to content

Commit

Permalink
moditect#7 Find more kinds of references (Annotations, Type Parameter…
Browse files Browse the repository at this point in the history
…s) WIP
  • Loading branch information
nilshartmann committed Jan 2, 2019
1 parent 692e24c commit 9b036df
Show file tree
Hide file tree
Showing 9 changed files with 293 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@
import org.moditect.deptective.internal.model.Package;
import org.moditect.deptective.internal.model.PackageDependencies;

import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;

Expand Down Expand Up @@ -59,31 +65,105 @@ public Void visitCompilationUnit(CompilationUnitTree tree, Void p) {
}

if (packageOfCurrentCompilationUnit == null) {
throw new IllegalArgumentException("Package " + packageName + " is not configured.");
throw new IllegalArgumentException("Package " +packageName + " is not configured.");
}

return super.visitCompilationUnit(tree, p);
}

@Override


// @Override
// public Void visitImport(ImportTree node, Void p) {
// TODO: Deal with "on-demand-imports" (com.foo.*)
// node.getQualifiedIdentifier().accept(new TreeScanner<Void, Void>() {
// @Override
// public Void visitMemberSelect(MemberSelectTree n, Void p) {
// return super.visitMemberSelect(n, p);
// }
// }, null);
//
// checkPackageAccess(node, getQualifiedName(node.getQualifiedIdentifier()));
// return super.visitImport(node, p);
// }

@Override
public Void visitVariable(VariableTree node, Void p) {
com.sun.tools.javac.tree.JCTree jcTree = (com.sun.tools.javac.tree.JCTree)node;
com.sun.tools.javac.tree.JCTree jcTree = (com.sun.tools.javac.tree.JCTree)node;

PackageElement pakkage = elements.getPackageOf(jcTree.type.asElement());
String qualifiedName = pakkage.getQualifiedName().toString();

if (!packageOfCurrentCompilationUnit.getName().equals(qualifiedName) &&
!packageDependencies.isWhitelisted(qualifiedName)) {
if (!qualifiedName.isEmpty() && !packageOfCurrentCompilationUnit.reads(qualifiedName)) {
if (reportingPolicy == ReportingPolicy.ERROR) {
log.error(jcTree.pos, DeptectiveMessages.ILLEGAL_PACKAGE_DEPENDENCY, packageOfCurrentCompilationUnit, qualifiedName);
}
else {
log.strictWarning(jcTree, DeptectiveMessages.ILLEGAL_PACKAGE_DEPENDENCY, packageOfCurrentCompilationUnit, qualifiedName);
}
}
}
checkPackageAccess(node, qualifiedName);

return super.visitVariable(node, p);
}

@Override
public Void visitTypeParameter(TypeParameterTree node, Void p) {
node.getBounds().forEach(s -> {
checkPackageAccess(s, getQualifiedName(s));
});

return super.visitTypeParameter(node, p);
}

@Override
public Void visitParameterizedType(ParameterizedTypeTree node, Void p) {
node.getTypeArguments().forEach(s -> {
checkPackageAccess(s, getQualifiedName(s));
});
return super.visitParameterizedType(node, p);
}

@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
checkPackageAccess(node.getAnnotationType(), getQualifiedName(node));

// TODO: find Types that are references from Annotation Arguments
// node.getArguments().forEach(expr -> {
//
// System.out.println("expr" + expr + "(" + expr.getClass().getName() + ")");
// if (expr instanceof AssignmentTree) {
// AssignmentTree assignmentTree = (AssignmentTree)expr;
// System.out.println("expr" + expr);
// System.out.println("qn => " + getQualifiedName(assignmentTree.getExpression()));
// checkPackageAccess(assignmentTree.getExpression(), getQualifiedName(assignmentTree.getExpression()));
// }
// });
return super.visitAnnotation(node, p);
}

protected String getQualifiedName(Tree tree) {
com.sun.tools.javac.tree.JCTree jcTree = (com.sun.tools.javac.tree.JCTree)tree;
Type type = jcTree.type;
if (type == null) {
throw new IllegalArgumentException("Could not determine type for tree object " + tree + " (" + tree.getClass()+")");
}
PackageElement pakkage = elements.getPackageOf(type.asElement());
return pakkage.getQualifiedName().toString();
}

protected void checkPackageAccess(Tree node, String qualifiedName) {
com.sun.tools.javac.tree.JCTree jcTree = (com.sun.tools.javac.tree.JCTree)node;

if (packageDependencies.isWhitelisted(qualifiedName)) {
return;
}

if (packageOfCurrentCompilationUnit.getName().equals(qualifiedName)) {
return;
}

if (qualifiedName.isEmpty() || packageOfCurrentCompilationUnit.reads(qualifiedName)) {
return;
}


if (reportingPolicy == ReportingPolicy.ERROR) {
log.error(jcTree.pos, DeptectiveMessages.ILLEGAL_PACKAGE_DEPENDENCY, packageOfCurrentCompilationUnit, qualifiedName);
}
else {
log.strictWarning(jcTree, DeptectiveMessages.ILLEGAL_PACKAGE_DEPENDENCY, packageOfCurrentCompilationUnit, qualifiedName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,50 +33,122 @@

public class BasicPluginTest extends PluginTestBase {

@Test
public void shouldDetectDisallowedPackageDependence() {
Compilation compilation = Compiler.javac()
.withOptions(
"-Xplugin:Deptective",
getConfigFileOption()
)
.compile(
forTestClass(BarCtorCall.class),
forTestClass(BarField.class),
forTestClass(BarLocalVar.class),
forTestClass(BarLoopVar.class),
forTestClass(BarParameter.class),
forTestClass(BarRetVal.class),
forTestClass(BarTypeArg.class),
forTestClass(Foo.class)
);
private Compilation compile() {
Compilation compilation = Compiler.javac()
.withOptions(
"-Xplugin:Deptective",
getConfigFileOption()
)
.compile(
forTestClass(BarCtorCall.class),
forTestClass(BarField.class),
forTestClass(BarLocalVar.class),
forTestClass(BarLoopVar.class),
forTestClass(BarParameter.class),
forTestClass(BarRetVal.class),
forTestClass(BarTypeArg.class),
forTestClass(Foo.class)
);


assertThat(compilation).failed();
return compilation;
}

// TODO https://github.com/moditect/deptective/issues/7
// @Test
// public void shouldDetectInvalidConstructorParameters() {
// Compilation compilation = compile();
// assertThat(compilation).failed();
//
// // TODO https://github.com/moditect/deptective/issues/7
// assertThat(compilation).hadErrorContaining(
// "package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barctorcall"
// );
// }

@Test
public void shouldDetectInvalidFieldReferences() {
Compilation compilation = compile();
assertThat(compilation).failed();

assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barfield"
);
}

@Test
public void shouldDetectInvalidLocalVariableReferences() {
Compilation compilation = compile();
assertThat(compilation).failed();

assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barlocalvar"
);
}

@Test
public void shouldDetectInvalidLoopVariableReferences() {
Compilation compilation = compile();
assertThat(compilation).failed();

assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barloopvar"
);
}

@Test
public void shouldDetectInvalidMethodParameterReferences() {
Compilation compilation = compile();
assertThat(compilation).failed();

assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barparameter"
);
}

// TODO https://github.com/moditect/deptective/issues/7
// assertThat(compilation).hadErrorContaining(
// "package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barretval"
// );
// assertThat(compilation).hadErrorContaining(
// "package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.bartypearg"
// );
@Test
public void shouldDetectInvalidAnnotationReferences() {
Compilation compilation = compile();
assertThat(compilation).failed();

assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barclazzan"
);
assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barfieldan"
);
}

// @Test
// public void shouldDetectInvalidReturnValueReferences() {
// Compilation compilation = compile();
// assertThat(compilation).failed();
//
// // TODO https://github.com/moditect/deptective/issues/7
// assertThat(compilation).hadErrorContaining(
// "package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.barretval"
// );
//
// }

@Test
public void shouldDetectInvalidTypeArguments() {
Compilation compilation = compile();
assertThat(compilation).failed();

// in type argument
assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.bartypearg"
);

// in class definition type argument bound
assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.bargen"
);

// in 'extends' class definition type argument
assertThat(compilation).hadErrorContaining(
"package org.moditect.deptective.plugintest.basic.foo does not read org.moditect.deptective.plugintest.basic.bargentype"
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.moditect.deptective.plugintest.basic.barclazzan;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.MODULE;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.TYPE_PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER,
TYPE_USE, MODULE })
public @interface BarClazzAnnotation {
Class<?> classParameter() default String.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.moditect.deptective.plugintest.basic.barfieldan;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.MODULE;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.TYPE_PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER,
TYPE_USE, MODULE })
public @interface BarFieldAnnotation {
Class<?> classParameter() default String.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.moditect.deptective.plugintest.basic.bargen;

public class BarGeneric {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.moditect.deptective.plugintest.basic.bargentype;

public class BarGenType {

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,23 @@
import java.util.ArrayList;
import java.util.List;

import org.moditect.deptective.plugintest.basic.barclazzan.BarClazzAnnotation;
import org.moditect.deptective.plugintest.basic.barctorcall.BarCtorCall;
import org.moditect.deptective.plugintest.basic.barfield.BarField;
import org.moditect.deptective.plugintest.basic.barfieldan.BarFieldAnnotation;
import org.moditect.deptective.plugintest.basic.bargen.BarGeneric;
import org.moditect.deptective.plugintest.basic.bargentype.BarGenType;
import org.moditect.deptective.plugintest.basic.barlocalvar.BarLocalVar;
import org.moditect.deptective.plugintest.basic.barloopvar.BarLoopVar;
import org.moditect.deptective.plugintest.basic.barparameter.BarParameter;
import org.moditect.deptective.plugintest.basic.barretval.BarRetVal;
import org.moditect.deptective.plugintest.basic.bartypearg.BarTypeArg;

@FooAnnotation
@BarClazzAnnotation
public class Foo {

@BarFieldAnnotation
private String s;
private final BarField bar = new BarField();

Expand All @@ -47,5 +54,11 @@ public BarRetVal doSomething(BarParameter bar) {
return null;
}

static class InvalidFooGeneric<T extends BarGeneric> {}

static class InvalidFooImplementation extends FooContainer<BarGenType> {}




}
Loading

0 comments on commit 9b036df

Please sign in to comment.