diff --git a/src/main/groovy/com/netflix/nebula/lint/plugin/LintRuleRegistry.groovy b/src/main/groovy/com/netflix/nebula/lint/plugin/LintRuleRegistry.groovy index d67b4d79..6fbee6aa 100644 --- a/src/main/groovy/com/netflix/nebula/lint/plugin/LintRuleRegistry.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/plugin/LintRuleRegistry.groovy @@ -17,7 +17,7 @@ package com.netflix.nebula.lint.plugin import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codenarc.rule.Rule import org.gradle.api.Project @@ -62,8 +62,8 @@ class LintRuleRegistry { if(implClassName) { try { Rule r = (Rule) classLoader.loadClass(implClassName).newInstance() - if(r instanceof GradleModelAware) { - (r as GradleModelAware).project = project + if(r instanceof ModelAwareGradleLintRule) { + (r as ModelAwareGradleLintRule).project = project } if(r instanceof GradleLintRule) { diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/GradleModelAware.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/GradleModelAware.groovy index cc5f3dce..16a6e860 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/GradleModelAware.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/GradleModelAware.groovy @@ -30,6 +30,7 @@ import javax.annotation.Nullable * Decorate lint rule visitors with this interface in order to use the * evaluated Gradle project model in the rule */ +@Deprecated // We suggest using ModelAwareGradleLintRule instead trait GradleModelAware { Project project Map> projectDefaultImports = null @@ -189,21 +190,4 @@ trait GradleModelAware { } return null } -} - -class TypeInformation { - @Nullable - Class clazz - @Nullable - Object object - - TypeInformation(Object object) { - this.object = object - this.clazz = object.class - } - - TypeInformation(Object object, Class clazz) { - this.object = object - this.clazz = clazz - } } \ No newline at end of file diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/ModelAwareGradleLintRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/ModelAwareGradleLintRule.groovy index fcf4eec4..e0df24d5 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/ModelAwareGradleLintRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/ModelAwareGradleLintRule.groovy @@ -16,6 +16,196 @@ package com.netflix.nebula.lint.rule -abstract class ModelAwareGradleLintRule extends GradleLintRule implements GradleModelAware { +import org.codehaus.groovy.ast.expr.ClosureExpression +import org.codehaus.groovy.ast.expr.ConstantExpression +import org.codehaus.groovy.ast.expr.Expression +import org.codehaus.groovy.ast.expr.MapExpression +import org.codehaus.groovy.ast.expr.MethodCallExpression +import org.codehaus.groovy.ast.expr.PropertyExpression +import org.codehaus.groovy.ast.expr.VariableExpression +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.internal.DefaultDomainObjectCollection +import org.gradle.api.plugins.ExtensionAware +import org.gradle.configuration.ImportsReader +import javax.annotation.Nullable + +abstract class ModelAwareGradleLintRule extends GradleLintRule { + Project project + Map> projectDefaultImports = null + + TypeInformation receiver(MethodCallExpression call) { + List fullCallStack = typedDslStack(callStack + call) + List typedStack = [] + for (Expression currentMethod in fullCallStack) { + if (typedStack.empty) { + typedStack.add(new TypeInformation(project)) + } + while (!typedStack.empty) { + def current = typedStack.last() + def candidate = findDirectCandidate(current, currentMethod) + if (candidate != null) { + typedStack.add(candidate) + break + } + typedStack.removeLast() + } + } + if (typedStack.size() >= 2) { //there should be the method return type and the receiver at least + return typedStack[-2] + } else { + return null + } + } + + private findDirectCandidate(TypeInformation current, Expression currentExpression) { + String methodName + switch (currentExpression) { + case MethodCallExpression: + methodName = currentExpression.methodAsString + break + case PropertyExpression: + methodName = currentExpression.propertyAsString + break + case VariableExpression: + methodName = currentExpression.text + break + case ConstantExpression: + methodName = currentExpression.text + break + default: + return null + } + def getter = current.clazz.getMethods().find { it.name == "get${methodName.capitalize()}" } + if (getter != null) { + if (current.object != null) { + try { + return new TypeInformation(getter.invoke(current.object)) + } catch (ignored) { + // ignore and fallback to the return type + } + } + return new TypeInformation(null, getter.returnType) + } + + // there is no public API for DomainObjectCollection.type + if (current.object != null && DefaultDomainObjectCollection.class.isAssignableFrom(current.clazz)) { + def collectionItemType = ((DefaultDomainObjectCollection) current.object).type + + if (methodName == "withType" && currentExpression instanceof MethodCallExpression && currentExpression.arguments.size() >= 1) { + def className = currentExpression.arguments[0] + def candidate = findSuitableClass(className.text, collectionItemType) + if (candidate != null) { + collectionItemType = candidate + } + } + + if ((methodName == "create" || methodName == "register") && currentExpression instanceof MethodCallExpression && currentExpression.arguments.size() >= 2 && currentExpression.arguments[1] !instanceof ClosureExpression) { + def className = currentExpression.arguments[1] + def candidate = findSuitableClass(className.text, collectionItemType) + if (candidate != null) { + collectionItemType = candidate + } + } + + def transformationOrFactoryMethod = current.clazz.getMethods().find { it.name == methodName && it.parameterTypes[-1] == Action.class } + if (transformationOrFactoryMethod != null) { + if (collectionItemType.isAssignableFrom(transformationOrFactoryMethod.returnType)) { + return new TypeInformation(null, transformationOrFactoryMethod.returnType) + } else { + // assume that all actions are done on the collection type + return new TypeInformation(null, collectionItemType) + } + } + } + + // note that we can't use tasks.findByName because it may lead to unwanted side effects because of potential task creation + if (Project.class.isAssignableFrom(current.clazz) && methodName == "task" && currentExpression instanceof MethodCallExpression) { + def taskType = extractTaskType(currentExpression) + if (taskType != null) { + return new TypeInformation(null, taskType) + } + return new TypeInformation(null, Task.class) + } + + def factoryMethod = current.clazz.getMethods().find { it.name == methodName && it.parameterTypes[-1] == Action.class } + if (factoryMethod != null) { + // assume that this is a factory method that returns the created type + return new TypeInformation(null, factoryMethod.returnType) + } + + if (current.object != null && current.object instanceof ExtensionAware) { + def extension = current.object.extensions.findByName(methodName) + if (extension != null) { + return new TypeInformation(extension) + } + } + return null; + } + + private List findClassInScope(String name) { + if (this.projectDefaultImports == null) { + this.projectDefaultImports = project.services.get(ImportsReader.class).getSimpleNameToFullClassNamesMapping() + } + return this.projectDefaultImports.get(name); + } + + @Nullable + private Class findSuitableClass(String className, Class parentClass) { + def candidates = (findClassInScope(className) ?: []) + [className] + for (String candidate in candidates) { + try { + def candidateClass = Class.forName(candidate) + if (parentClass.isAssignableFrom(candidateClass)) { + return candidateClass + } + } catch (ignored) { + // ignore and try the next candidate + } + } + return null + } + + @Nullable + private Class extractTaskType(MethodCallExpression currentExpression) { + for (Expression arg in currentExpression.arguments) { + if (arg instanceof VariableExpression || arg instanceof ConstantExpression) { + def candidate = findSuitableClass(arg.text, Task.class) + if (candidate != null) { + return candidate + } + } else if (arg instanceof MapExpression) { + def type = arg + .mapEntryExpressions + .find { it.keyExpression.text == "type" } + ?.valueExpression?.text + if (type != null) { + def candidate = findSuitableClass(type, Task.class) + if (candidate != null) { + return candidate + } + } + } + } + return null + } } + +class TypeInformation { + @Nullable + Class clazz + @Nullable + Object object + + TypeInformation(Object object) { + this.object = object + this.clazz = object.class + } + + TypeInformation(Object object, Class clazz) { + this.object = object + this.clazz = clazz + } +} \ No newline at end of file diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/AbstractDuplicateDependencyClassRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/AbstractDuplicateDependencyClassRule.groovy index d1e5bb63..dea11261 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/AbstractDuplicateDependencyClassRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/AbstractDuplicateDependencyClassRule.groovy @@ -1,14 +1,13 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.ast.expr.MethodCallExpression import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ModuleVersionIdentifier -abstract class AbstractDuplicateDependencyClassRule extends GradleLintRule implements GradleModelAware { +abstract class AbstractDuplicateDependencyClassRule extends ModelAwareGradleLintRule { String description = 'classpaths with duplicate classes may break unpredictably depending on the order in which dependencies are provided to the classpath' Set directlyUsedConfigurations = [] as Set diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/BypassedForcesRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/BypassedForcesRule.groovy index c9a1ba35..5f2d996d 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/BypassedForcesRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/BypassedForcesRule.groovy @@ -1,8 +1,7 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileStatic import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.ast.expr.ArgumentListExpression @@ -24,7 +23,7 @@ import org.slf4j.LoggerFactory import java.util.stream.Collectors -class BypassedForcesRule extends GradleLintRule implements GradleModelAware { +class BypassedForcesRule extends ModelAwareGradleLintRule { String description = 'remove bypassed forces and strict constraints. Works for static and ranged declarations' Map> forcedDependenciesPerProject = new HashMap>() private final DefaultVersionComparator VERSIONED_COMPARATOR = new DefaultVersionComparator() diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyParenthesesRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyParenthesesRule.groovy index 5e8b4968..dbec0cf3 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyParenthesesRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyParenthesesRule.groovy @@ -17,12 +17,11 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.expr.ClosureExpression import org.codehaus.groovy.ast.expr.MethodCallExpression -class DependencyParenthesesRule extends GradleLintRule implements GradleModelAware { +class DependencyParenthesesRule extends ModelAwareGradleLintRule { String description = "don't put parentheses around dependency definitions unless it is necessary" @Override diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyTupleExpressionRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyTupleExpressionRule.groovy index c1671043..3ec7da58 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyTupleExpressionRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyTupleExpressionRule.groovy @@ -18,13 +18,12 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleAstUtil import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileStatic import org.codehaus.groovy.ast.expr.MethodCallExpression @CompileStatic -class DependencyTupleExpressionRule extends GradleLintRule implements GradleModelAware { +class DependencyTupleExpressionRule extends ModelAwareGradleLintRule { String description = "use the more compact string representation of a dependency when possible" @Override diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DeprecatedDependencyConfigurationRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DeprecatedDependencyConfigurationRule.groovy index 7223814a..04c4b99e 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DeprecatedDependencyConfigurationRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/DeprecatedDependencyConfigurationRule.groovy @@ -3,8 +3,7 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.interop.GradleKt import com.netflix.nebula.lint.GradleViolation import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.codehaus.groovy.ast.expr.ConstantExpression @@ -12,7 +11,7 @@ import org.codehaus.groovy.ast.expr.Expression import org.codehaus.groovy.ast.expr.MethodCallExpression @CompileStatic -class DeprecatedDependencyConfigurationRule extends GradleLintRule implements GradleModelAware { +class DeprecatedDependencyConfigurationRule extends ModelAwareGradleLintRule { String description = 'Replace deprecated configurations in dependencies' private final Map CONFIGURATION_REPLACEMENTS = [ diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MinimumDependencyVersionRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MinimumDependencyVersionRule.groovy index d2470b9d..40aaedbb 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MinimumDependencyVersionRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MinimumDependencyVersionRule.groovy @@ -2,8 +2,7 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.VersionNumber import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileStatic import org.codehaus.groovy.ast.ASTNode import org.codehaus.groovy.ast.ClassNode @@ -20,7 +19,7 @@ import org.gradle.api.artifacts.Configuration */ @Incubating @CompileStatic -class MinimumDependencyVersionRule extends GradleLintRule implements GradleModelAware { +class MinimumDependencyVersionRule extends ModelAwareGradleLintRule { String description = 'pull up dependencies to a minimum version if necessary' Set alreadyAdded = [] as Set Set resolvableAndResolvedConfigurations diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MultiProjectCircularDependencyRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MultiProjectCircularDependencyRule.groovy index b6f3064e..d58bf80b 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MultiProjectCircularDependencyRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/MultiProjectCircularDependencyRule.groovy @@ -1,7 +1,6 @@ package com.netflix.nebula.lint.rule.dependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import groovy.transform.TupleConstructor @@ -11,7 +10,7 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression @CompileStatic -class MultiProjectCircularDependencyRule extends GradleLintRule implements GradleModelAware { +class MultiProjectCircularDependencyRule extends ModelAwareGradleLintRule { String description = 'Detect circular dependencies in multi projects' private final String PROJECT_METHOD_NAME = 'project' diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/RecommendedVersionsRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/RecommendedVersionsRule.groovy index 9b14a29b..dac947a5 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/RecommendedVersionsRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/RecommendedVersionsRule.groovy @@ -19,13 +19,12 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import com.netflix.nebula.lint.rule.dependency.provider.MavenBomRecommendationProvider import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.ast.expr.MethodCallExpression -class RecommendedVersionsRule extends GradleLintRule implements GradleModelAware { +class RecommendedVersionsRule extends ModelAwareGradleLintRule { private static final String GRADLE_VERSION_WITH_EXPERIMENTAL_FEATURES = '4.5' private static final String GRADLE_VERSION_WITH_OPT_IN_FEATURES = '4.6' private static final String GRADLE_VERSION_WITH_DEFAULT_FEATURES = '5.0' diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UndeclaredDependencyRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UndeclaredDependencyRule.groovy index 0315f935..c99820e1 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UndeclaredDependencyRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UndeclaredDependencyRule.groovy @@ -1,8 +1,7 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.SourceSetUtils -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.codehaus.groovy.ast.ASTNode @@ -11,7 +10,7 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression import org.gradle.api.artifacts.ModuleVersionIdentifier @CompileStatic -class UndeclaredDependencyRule extends GradleLintRule implements GradleModelAware { +class UndeclaredDependencyRule extends ModelAwareGradleLintRule { private static final String DEPENDENCIES_BLOCK = 'rootDependenciesBlock' String description = 'Ensure that directly used transitives are declared as first order dependencies' DependencyService dependencyService diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyExcludeRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyExcludeRule.groovy index 0ea28c9a..3de77496 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyExcludeRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyExcludeRule.groovy @@ -18,13 +18,12 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleAstUtil import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.expr.MethodCallExpression import org.gradle.api.artifacts.Configuration import org.gradle.api.specs.Specs -class UnusedDependencyExcludeRule extends GradleLintRule implements GradleModelAware { +class UnusedDependencyExcludeRule extends ModelAwareGradleLintRule { String description = 'excludes that have no effect on the classpath should be removed for clarity' GradleDependency dependency diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyRule.groovy index 587de610..f8623e81 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedDependencyRule.groovy @@ -2,8 +2,7 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.SourceSetUtils import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.ast.expr.MethodCallExpression import org.gradle.api.artifacts.Configuration @@ -11,7 +10,7 @@ import org.gradle.api.artifacts.ModuleIdentifier import org.gradle.api.artifacts.ModuleVersionIdentifier import org.gradle.api.tasks.SourceSet -class UnusedDependencyRule extends GradleLintRule implements GradleModelAware { +class UnusedDependencyRule extends ModelAwareGradleLintRule { String description = 'remove unused dependencies, relocate dependencies to the correct configuration, and ensure that directly used transitives are declared as first order dependencies' static final List shouldBeRuntime = ['xerces', 'xercesImpl', 'xml-apis'] diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedExcludeByConfigurationRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedExcludeByConfigurationRule.groovy index 962226d2..c8129774 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedExcludeByConfigurationRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dependency/UnusedExcludeByConfigurationRule.groovy @@ -17,13 +17,12 @@ package com.netflix.nebula.lint.rule.dependency import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.expr.MethodCallExpression import org.gradle.api.artifacts.Configuration import org.gradle.api.specs.Specs -class UnusedExcludeByConfigurationRule extends GradleLintRule implements GradleModelAware { +class UnusedExcludeByConfigurationRule extends ModelAwareGradleLintRule { String description = 'excludes that have no effect on the classpath should be removed for clarity' @Override diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/dsl/SpaceAssignmentRule.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/dsl/SpaceAssignmentRule.groovy index ccc6a343..6ef333aa 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/dsl/SpaceAssignmentRule.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/dsl/SpaceAssignmentRule.groovy @@ -1,11 +1,10 @@ package com.netflix.nebula.lint.rule.dsl -import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import org.codehaus.groovy.ast.expr.ClosureExpression import org.codehaus.groovy.ast.expr.MethodCallExpression -class SpaceAssignmentRule extends GradleLintRule implements GradleModelAware { +class SpaceAssignmentRule extends ModelAwareGradleLintRule { String description = "space-assignment syntax is deprecated" diff --git a/src/main/groovy/com/netflix/nebula/lint/rule/test/AbstractRuleSpec.groovy b/src/main/groovy/com/netflix/nebula/lint/rule/test/AbstractRuleSpec.groovy index 0b15e12e..082b02c8 100644 --- a/src/main/groovy/com/netflix/nebula/lint/rule/test/AbstractRuleSpec.groovy +++ b/src/main/groovy/com/netflix/nebula/lint/rule/test/AbstractRuleSpec.groovy @@ -21,7 +21,7 @@ import com.netflix.nebula.lint.GradleLintPatchAction import com.netflix.nebula.lint.plugin.NotNecessarilyGitRepository import com.netflix.nebula.lint.rule.BuildFiles import com.netflix.nebula.lint.rule.GradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware +import com.netflix.nebula.lint.rule.ModelAwareGradleLintRule import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import nebula.test.ProjectSpec @@ -46,7 +46,7 @@ abstract class AbstractRuleSpec extends ProjectSpec { def ruleSet = new CompositeRuleSet() rules.each { ruleSet.addRule(it) - if (it instanceof GradleModelAware) { + if (it instanceof ModelAwareGradleLintRule) { it.project = project } } diff --git a/src/test/groovy/com/netflix/nebula/lint/plugin/FixGradleLintTaskCriticalRulesSpec.groovy b/src/test/groovy/com/netflix/nebula/lint/plugin/FixGradleLintTaskCriticalRulesSpec.groovy index eaf293da..6ad2fc86 100644 --- a/src/test/groovy/com/netflix/nebula/lint/plugin/FixGradleLintTaskCriticalRulesSpec.groovy +++ b/src/test/groovy/com/netflix/nebula/lint/plugin/FixGradleLintTaskCriticalRulesSpec.groovy @@ -1,13 +1,10 @@ package com.netflix.nebula.lint.plugin import com.netflix.nebula.lint.rule.AbstractExampleGradleLintRule -import com.netflix.nebula.lint.rule.GradleLintRule +import com.netflix.nebula.lint.rule.AbstractModelAwareExampleGradleLintRule import com.netflix.nebula.lint.rule.GradleModelAware import nebula.test.IntegrationSpec -import org.codehaus.groovy.ast.expr.EmptyExpression -import org.codehaus.groovy.ast.expr.LambdaExpression import org.codehaus.groovy.ast.expr.MethodCallExpression -import org.codehaus.groovy.ast.expr.MethodReferenceExpression class FixGradleLintTaskCriticalRulesSpec extends IntegrationSpec { def 'critical lint violations include cases requiring user action'() { @@ -49,7 +46,7 @@ class FixGradleLintTaskCriticalRulesSpec extends IntegrationSpec { } } -class UserActionRequiredExampleRule extends AbstractExampleGradleLintRule implements GradleModelAware { +class UserActionRequiredExampleRule extends AbstractModelAwareExampleGradleLintRule { String description = 'example rule that requires a user action' @Override diff --git a/src/test/groovy/com/netflix/nebula/lint/rule/AbstractModelAwareExampleGradleLintRule.groovy b/src/test/groovy/com/netflix/nebula/lint/rule/AbstractModelAwareExampleGradleLintRule.groovy new file mode 100644 index 00000000..1e3925d9 --- /dev/null +++ b/src/test/groovy/com/netflix/nebula/lint/rule/AbstractModelAwareExampleGradleLintRule.groovy @@ -0,0 +1,21 @@ +package com.netflix.nebula.lint.rule + +import org.codehaus.groovy.ast.expr.EmptyExpression +import org.codehaus.groovy.ast.expr.LambdaExpression +import org.codehaus.groovy.ast.expr.MethodReferenceExpression + +//tests are compiled against Groovy 3 main code against Groovy 2 +//this rule declares new methods so we don't have to declare them in every test rule in tests +abstract class AbstractModelAwareExampleGradleLintRule extends ModelAwareGradleLintRule { + @Override + void visitLambdaExpression(LambdaExpression lambdaExpression) { + } + + @Override + void visitMethodReferenceExpression(MethodReferenceExpression methodReferenceExpression) { + } + + @Override + void visitEmptyExpression(EmptyExpression expression) { + } +} diff --git a/src/test/groovy/com/netflix/nebula/lint/rule/GradleLintRuleSpec.groovy b/src/test/groovy/com/netflix/nebula/lint/rule/GradleLintRuleSpec.groovy index 01aa417b..3f5c745f 100644 --- a/src/test/groovy/com/netflix/nebula/lint/rule/GradleLintRuleSpec.groovy +++ b/src/test/groovy/com/netflix/nebula/lint/rule/GradleLintRuleSpec.groovy @@ -885,9 +885,9 @@ class GradleLintRuleSpec extends AbstractRuleSpec { noPluginsRule } - abstract class GradleProjectLintRule extends AbstractExampleGradleLintRule implements GradleModelAware {} + abstract class GradleProjectLintRule extends AbstractModelAwareExampleGradleLintRule {} - private class DependencyVisitingRule extends AbstractExampleGradleLintRule implements GradleModelAware { + private class DependencyVisitingRule extends AbstractModelAwareExampleGradleLintRule { final String description = 'visit dependencies' List deps = [] List allprojectDeps = [] diff --git a/src/test/groovy/com/netflix/nebula/lint/rule/dependency/DependencyHelperSpec.groovy b/src/test/groovy/com/netflix/nebula/lint/rule/dependency/DependencyHelperSpec.groovy index 63568c44..77fbeae4 100644 --- a/src/test/groovy/com/netflix/nebula/lint/rule/dependency/DependencyHelperSpec.groovy +++ b/src/test/groovy/com/netflix/nebula/lint/rule/dependency/DependencyHelperSpec.groovy @@ -1,8 +1,7 @@ package com.netflix.nebula.lint.rule.dependency +import com.netflix.nebula.lint.rule.AbstractModelAwareExampleGradleLintRule import com.netflix.nebula.lint.rule.GradleDependency -import com.netflix.nebula.lint.rule.AbstractExampleGradleLintRule -import com.netflix.nebula.lint.rule.GradleModelAware import nebula.test.IntegrationSpec import nebula.test.dependencies.DependencyGraphBuilder import nebula.test.dependencies.GradleDependencyGenerator @@ -178,7 +177,7 @@ class DependencyHelperSpec extends IntegrationSpec { } } -class TestDependencyRemoveVersionRule extends AbstractExampleGradleLintRule implements GradleModelAware { +class TestDependencyRemoveVersionRule extends AbstractModelAwareExampleGradleLintRule { String description = "remove all versions" @Override @@ -188,7 +187,7 @@ class TestDependencyRemoveVersionRule extends AbstractExampleGradleLintRule impl } } -class TestDependencyReplaceVersionRule extends AbstractExampleGradleLintRule implements GradleModelAware { +class TestDependencyReplaceVersionRule extends AbstractModelAwareExampleGradleLintRule { String description = "replace all versions" @Override @@ -198,7 +197,7 @@ class TestDependencyReplaceVersionRule extends AbstractExampleGradleLintRule imp } } -class TestDependencyReplaceRule extends AbstractExampleGradleLintRule implements GradleModelAware { +class TestDependencyReplaceRule extends AbstractModelAwareExampleGradleLintRule { String description = "replace dependency" @Override