diff --git a/javac-plugin/src/main/java/org/moditect/deptective/internal/DeptectiveTreeVisitor.java b/javac-plugin/src/main/java/org/moditect/deptective/internal/DeptectiveTreeVisitor.java index fa419d9..98fd2ef 100644 --- a/javac-plugin/src/main/java/org/moditect/deptective/internal/DeptectiveTreeVisitor.java +++ b/javac-plugin/src/main/java/org/moditect/deptective/internal/DeptectiveTreeVisitor.java @@ -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; @@ -64,25 +70,100 @@ public Void visitCompilationUnit(CompilationUnitTree tree, Void p) { return super.visitCompilationUnit(tree, p); } - - @Override + + + +// @Override +// public Void visitImport(ImportTree node, Void p) { +// System.out.println("QI: " + node.getQualifiedIdentifier().getKind() + " -> " + node.getQualifiedIdentifier()); +// node.getQualifiedIdentifier().accept(new TreeScanner() { +// @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 (!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)); + + 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()+")"); + } + System.out.println("TX: " + type.asElement()); + 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); + } + } } diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/DependenciesTest.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/DependenciesTest.java new file mode 100644 index 0000000..72e490c --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/DependenciesTest.java @@ -0,0 +1,73 @@ +package org.moditect.deptective.plugintest.deps; + +import static com.google.testing.compile.CompilationSubject.assertThat; + +import org.junit.Test; +import org.moditect.deptective.plugintest.PluginTestBase; +import org.moditect.deptective.plugintest.deps.model.Model; +import org.moditect.deptective.plugintest.deps.service.Service; +import org.moditect.deptective.plugintest.deps.ui.InvalidAnnotation; +import org.moditect.deptective.plugintest.deps.ui.InvalidAnnotationParameter; +import org.moditect.deptective.plugintest.deps.ui.InvalidGenericUIView; +import org.moditect.deptective.plugintest.deps.ui.InvalidGenericView; +import org.moditect.deptective.plugintest.deps.ui.InvalidTypeView; +import org.moditect.deptective.plugintest.deps.ui.InvalidView; + +import com.google.testing.compile.Compilation; +import com.google.testing.compile.Compiler; + +public class DependenciesTest extends PluginTestBase { + + protected Compilation compileWithModelAndService(Class testClass) { + Compilation compilation = Compiler.javac().withOptions("-Xplugin:Deptective", getConfigFileOption()) + .compile(forTestClass(Model.class), forTestClass(Service.class), forTestClass(testClass)); + + return compilation; + } + + @Test + public void shouldDetectInvalidRefrencesInMethodParameters() { + Compilation compilation = compileWithModelAndService(InvalidView.class); + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining( + "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" + ); + } + + @Test + public void shouldDetectInvalidRefrencesInTypeArguments() { + Compilation compilation = compileWithModelAndService(InvalidGenericView.class); + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining( + "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" + ); + + compilation = compileWithModelAndService(InvalidGenericUIView.class); + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining( + "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" + ); + + compilation = compileWithModelAndService(InvalidTypeView.class); + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining( + "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" + ); + } + + + @Test + public void shouldDetectInvalidRefrencesInAnnotations() { +// Compilation compilation = compileWithModelAndService(InvalidAnnotation.class); +// assertThat(compilation).failed(); +// assertThat(compilation).hadErrorContaining( +// "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" +// ); + + Compilation compilation = compileWithModelAndService(InvalidAnnotationParameter.class); + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining( + "package org.moditect.deptective.plugintest.deps.ui does not read org.moditect.deptective.plugintest.deps.model" + ); + } +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/Model.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/Model.java new file mode 100644 index 0000000..ba98387 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/Model.java @@ -0,0 +1,5 @@ +package org.moditect.deptective.plugintest.deps.model; + +public class Model { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/ModelAnnotation.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/ModelAnnotation.java new file mode 100644 index 0000000..19ffaed --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/model/ModelAnnotation.java @@ -0,0 +1,23 @@ +package org.moditect.deptective.plugintest.deps.model; + +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 ModelAnnotation { +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/service/Service.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/service/Service.java new file mode 100644 index 0000000..2e443af --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/service/Service.java @@ -0,0 +1,5 @@ +package org.moditect.deptective.plugintest.deps.service; + +public class Service { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericUI.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericUI.java new file mode 100644 index 0000000..2ad1f78 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericUI.java @@ -0,0 +1,5 @@ +package org.moditect.deptective.plugintest.deps.ui; + +public class GenericUI { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericView.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericView.java new file mode 100644 index 0000000..80d8fdd --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/GenericView.java @@ -0,0 +1,5 @@ +package org.moditect.deptective.plugintest.deps.ui; + +public class GenericView { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotation.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotation.java new file mode 100644 index 0000000..52dfb9c --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotation.java @@ -0,0 +1,8 @@ +package org.moditect.deptective.plugintest.deps.ui; + +import org.moditect.deptective.plugintest.deps.model.ModelAnnotation; + +@ModelAnnotation +public class InvalidAnnotation { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotationParameter.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotationParameter.java new file mode 100644 index 0000000..95daf06 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidAnnotationParameter.java @@ -0,0 +1,6 @@ +package org.moditect.deptective.plugintest.deps.ui; + +@UIAnnotation(uiClass=org.moditect.deptective.plugintest.deps.model.Model.class) +public class InvalidAnnotationParameter { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericUIView.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericUIView.java new file mode 100644 index 0000000..dbfe689 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericUIView.java @@ -0,0 +1,9 @@ +package org.moditect.deptective.plugintest.deps.ui; + +import org.moditect.deptective.plugintest.deps.model.Model; + +// Access to GenericUI is allowed, +// Access to Mdeol via GenericUI NOT +public class InvalidGenericUIView extends GenericView>{ + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericView.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericView.java new file mode 100644 index 0000000..f175213 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidGenericView.java @@ -0,0 +1,7 @@ +package org.moditect.deptective.plugintest.deps.ui; + +import org.moditect.deptective.plugintest.deps.model.Model; + +public class InvalidGenericView extends GenericView{ + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidModel.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidModel.java new file mode 100644 index 0000000..82bedea --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidModel.java @@ -0,0 +1,7 @@ +package org.moditect.deptective.plugintest.deps.ui; + + +public class InvalidModel extends org.moditect.deptective.plugintest.deps.model.Model{ + + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidTypeView.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidTypeView.java new file mode 100644 index 0000000..a9898b7 --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidTypeView.java @@ -0,0 +1,8 @@ +package org.moditect.deptective.plugintest.deps.ui; + +import org.moditect.deptective.plugintest.deps.model.Model; + +// Acess to Model forbidden +public class InvalidTypeView { + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidView.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidView.java new file mode 100644 index 0000000..e7a66eb --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/InvalidView.java @@ -0,0 +1,13 @@ +package org.moditect.deptective.plugintest.deps.ui; + +import org.moditect.deptective.plugintest.deps.model.Model; + +public class InvalidView { + + public void invalidModelUsage(Model m) { + // + } + + + +} diff --git a/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/UIAnnotation.java b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/UIAnnotation.java new file mode 100644 index 0000000..834590f --- /dev/null +++ b/javac-plugin/src/test/java/org/moditect/deptective/plugintest/deps/ui/UIAnnotation.java @@ -0,0 +1,24 @@ +package org.moditect.deptective.plugintest.deps.ui; + +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 UIAnnotation { + Class uiClass() default String.class; +} diff --git a/javac-plugin/src/test/resources/org/moditect/deptective/plugintest/deps/deptective.json b/javac-plugin/src/test/resources/org/moditect/deptective/plugintest/deps/deptective.json new file mode 100644 index 0000000..5f660ad --- /dev/null +++ b/javac-plugin/src/test/resources/org/moditect/deptective/plugintest/deps/deptective.json @@ -0,0 +1,19 @@ +{ + "packages" : [ + { + "name" : "org.moditect.deptective.plugintest.deps.model" + }, + { + "name" : "org.moditect.deptective.plugintest.deps.service", + "reads" : [ + "org.moditect.deptective.plugintest.deps.model" + ] + }, + { + "name" : "org.moditect.deptective.plugintest.deps.ui", + "reads" : [ + "org.moditect.deptective.plugintest.deps.service" + ] + } + ] +}