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
nilshartmann committed Jan 2, 2019

Verified

This commit was signed with the committer’s verified signature.
ohmykreee Kre³
1 parent 692e24c commit 9b036df
Showing 9 changed files with 293 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -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;

@@ -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
@@ -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
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
@@ -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();

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

static class InvalidFooGeneric<T extends BarGeneric> {}

static class InvalidFooImplementation extends FooContainer<BarGenType> {}




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

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 FooAnnotation {
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.foo;

public class FooContainer<T> {

}

0 comments on commit 9b036df

Please sign in to comment.