use of org.gradle.internal.reflect.validation.TypeValidationContext in project gradle by gradle.
the class DefaultNodeValidator method hasValidationProblems.
@Override
public boolean hasValidationProblems(Node node) {
if (node instanceof LocalTaskNode) {
LocalTaskNode taskNode = (LocalTaskNode) node;
WorkValidationContext validationContext = taskNode.getValidationContext();
Class<?> taskType = GeneratedSubclasses.unpackType(taskNode.getTask());
// We don't know whether the task is cacheable or not, so we ignore cacheability problems for scheduling
TypeValidationContext taskValidationContext = validationContext.forType(taskType, false);
taskNode.getTaskProperties().validateType(taskValidationContext);
List<TypeValidationProblem> problems = validationContext.getProblems();
problems.stream().filter(problem -> problem.getSeverity().isWarning()).forEach(problem -> {
Optional<UserManualReference> userManualReference = problem.getUserManualReference();
String docId = "more_about_tasks";
String section = "sec:up_to_date_checks";
if (userManualReference.isPresent()) {
UserManualReference docref = userManualReference.get();
docId = docref.getId();
section = docref.getSection();
}
// Because our deprecation warning system doesn't support multiline strings (bummer!) both in rendering
// **and** testing (no way to capture multiline deprecation warnings), we have to resort to removing details
// and rendering
String warning = convertToSingleLine(renderMinimalInformationAbout(problem, false, false));
DeprecationLogger.deprecateBehaviour(warning).withContext("Execution optimizations are disabled to ensure correctness.").willBeRemovedInGradle8().withUserManual(docId, section).nagUser();
});
return !problems.isEmpty();
} else {
return false;
}
}
use of org.gradle.internal.reflect.validation.TypeValidationContext in project gradle by gradle.
the class TaskExecution method validate.
@Override
public void validate(WorkValidationContext validationContext) {
Class<?> taskType = GeneratedSubclasses.unpackType(task);
// TODO This should probably use the task class info store
boolean cacheable = taskType.isAnnotationPresent(CacheableTask.class);
TypeValidationContext typeValidationContext = validationContext.forType(taskType, cacheable);
context.getTaskProperties().validateType(typeValidationContext);
context.getTaskProperties().validate(new DefaultTaskValidationContext(fileOperations, reservedFileSystemLocationRegistry, typeValidationContext));
context.getValidationAction().validate(context.getTaskExecutionMode().isTaskHistoryMaintained(), typeValidationContext);
}
use of org.gradle.internal.reflect.validation.TypeValidationContext in project gradle by gradle.
the class DefaultTypeAnnotationMetadataStore method mergePropertiesAndFieldMetadata.
private ImmutableSortedSet<PropertyAnnotationMetadata> mergePropertiesAndFieldMetadata(Class<?> type, ImmutableList<PropertyAnnotationMetadataBuilder> propertyBuilders, ImmutableMap<String, ImmutableMap<Class<? extends Annotation>, Annotation>> fieldAnnotationsByPropertyName, TypeValidationContext validationContext) {
ImmutableSortedSet.Builder<PropertyAnnotationMetadata> propertiesMetadataBuilder = ImmutableSortedSet.naturalOrder();
ImmutableSet.Builder<String> fieldsSeenBuilder = ImmutableSet.builderWithExpectedSize(fieldAnnotationsByPropertyName.size());
for (PropertyAnnotationMetadataBuilder metadataBuilder : propertyBuilders) {
String propertyName = metadataBuilder.getPropertyName();
ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = fieldAnnotationsByPropertyName.get(propertyName);
if (fieldAnnotations != null) {
fieldsSeenBuilder.add(propertyName);
for (Annotation annotation : fieldAnnotations.values()) {
metadataBuilder.declareAnnotation(annotation);
}
}
propertiesMetadataBuilder.add(metadataBuilder.build());
}
ImmutableSortedSet<PropertyAnnotationMetadata> propertiesMetadata = propertiesMetadataBuilder.build();
// Report fields with annotations that have not been seen while processing properties
ImmutableSet<String> fieldsSeen = fieldsSeenBuilder.build();
if (fieldsSeen.size() != fieldAnnotationsByPropertyName.size()) {
fieldAnnotationsByPropertyName.entrySet().stream().filter(entry -> {
String fieldName = entry.getKey();
ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = entry.getValue();
return !fieldAnnotations.isEmpty() && !fieldsSeen.contains(fieldName) && // @Inject is allowed on fields only
!fieldAnnotations.containsKey(Inject.class);
}).forEach(entry -> {
String fieldName = entry.getKey();
ImmutableMap<Class<? extends Annotation>, Annotation> fieldAnnotations = entry.getValue();
validationContext.visitTypeProblem(problem -> problem.withId(ValidationProblemId.IGNORED_ANNOTATIONS_ON_FIELD).forType(type).reportAs(ERROR).withDescription(() -> String.format("field '%s' without corresponding getter has been annotated with %s", fieldName, simpleAnnotationNames(fieldAnnotations.keySet().stream()))).happensBecause("Annotations on fields are only used if there's a corresponding getter for the field").withLongDescription("If a field is annotated but there's no corresponding getter, then the annotations are ignored").addPossibleSolution(() -> "Add a getter for field '" + fieldName + "'").addPossibleSolution(() -> "Remove the annotations on '" + fieldName + "'").documentedAt("validation_problems", "ignored_annotations_on_field"));
});
}
return propertiesMetadata;
}
use of org.gradle.internal.reflect.validation.TypeValidationContext in project gradle by gradle.
the class ValidateStep method validateImplementations.
private void validateImplementations(UnitOfWork work, BeforeExecutionState beforeExecutionState, WorkValidationContext validationContext) {
MutableReference<Class<?>> workClass = MutableReference.empty();
work.visitImplementations(new UnitOfWork.ImplementationVisitor() {
@Override
public void visitImplementation(Class<?> implementation) {
workClass.set(GeneratedSubclasses.unpack(implementation));
}
@Override
public void visitImplementation(ImplementationSnapshot implementation) {
}
});
// It doesn't matter whether we use cacheable true or false, since none of the warnings depends on the cacheability of the task.
Class<?> workType = workClass.get();
TypeValidationContext workValidationContext = validationContext.forType(workType, true);
validateImplementation(workValidationContext, beforeExecutionState.getImplementation(), "Implementation of ", work);
beforeExecutionState.getAdditionalImplementations().forEach(additionalImplementation -> validateImplementation(workValidationContext, additionalImplementation, "Additional action of ", work));
beforeExecutionState.getInputProperties().forEach((propertyName, valueSnapshot) -> {
if (valueSnapshot instanceof ImplementationSnapshot) {
ImplementationSnapshot implementationSnapshot = (ImplementationSnapshot) valueSnapshot;
validateNestedInput(workValidationContext, propertyName, implementationSnapshot);
}
});
}
use of org.gradle.internal.reflect.validation.TypeValidationContext in project gradle by gradle.
the class LocalTaskNodeExecutor method detectMissingDependencies.
private void detectMissingDependencies(LocalTaskNode node, boolean historyMaintained, ExecutionNodeAccessHierarchies.InputNodeAccessHierarchy inputHierarchy, TypeValidationContext validationContext) {
for (String outputPath : node.getMutationInfo().outputPaths) {
inputHierarchy.getNodesAccessing(outputPath).stream().filter(consumerNode -> hasNoSpecifiedOrder(node, consumerNode)).filter(LocalTaskNodeExecutor::isEnabled).forEach(consumerWithoutDependency -> collectValidationProblem(node, consumerWithoutDependency, validationContext, outputPath));
}
Set<String> taskInputs = new LinkedHashSet<>();
Set<FilteredTree> filteredFileTreeTaskInputs = new LinkedHashSet<>();
node.getTaskProperties().getInputFileProperties().forEach(spec -> {
try {
spec.getPropertyFiles().visitStructure(new FileCollectionStructureVisitor() {
@Override
public void visitCollection(FileCollectionInternal.Source source, Iterable<File> contents) {
contents.forEach(location -> taskInputs.add(location.getAbsolutePath()));
}
@Override
public void visitGenericFileTree(FileTreeInternal fileTree, FileSystemMirroringFileTree sourceTree) {
fileTree.forEach(location -> taskInputs.add(location.getAbsolutePath()));
}
@Override
public void visitFileTree(File root, PatternSet patterns, FileTreeInternal fileTree) {
if (patterns.isEmpty()) {
taskInputs.add(root.getAbsolutePath());
} else {
filteredFileTreeTaskInputs.add(new FilteredTree(root.getAbsolutePath(), patterns));
}
}
@Override
public void visitFileTreeBackedByFile(File file, FileTreeInternal fileTree, FileSystemMirroringFileTree sourceTree) {
taskInputs.add(file.getAbsolutePath());
}
});
} catch (Exception e) {
if (historyMaintained) {
// We would later try to snapshot the inputs anyway, no need to suppress the exception
throw e;
} else {
validationContext.visitPropertyProblem(problem -> problem.withId(ValidationProblemId.UNRESOLVABLE_INPUT).forProperty(spec.getPropertyName()).reportAs(Severity.WARNING).withDescription(() -> String.format("cannot be resolved:%n%s%n", TextUtil.indent(e.getMessage(), " "))).happensBecause("An input file collection couldn't be resolved, making it impossible to determine task inputs").addPossibleSolution("Consider using Task.dependsOn instead").documentedAt("validation_problems", "unresolvable_input"));
}
}
});
inputHierarchy.recordNodeAccessingLocations(node, taskInputs);
for (String locationConsumedByThisTask : taskInputs) {
collectValidationProblemsForConsumer(node, validationContext, locationConsumedByThisTask, outputHierarchy.getNodesAccessing(locationConsumedByThisTask));
}
for (FilteredTree filteredFileTreeInput : filteredFileTreeTaskInputs) {
Spec<FileTreeElement> spec = filteredFileTreeInput.getPatterns().getAsSpec();
inputHierarchy.recordNodeAccessingFileTree(node, filteredFileTreeInput.getRoot(), spec);
collectValidationProblemsForConsumer(node, validationContext, filteredFileTreeInput.getRoot(), outputHierarchy.getNodesAccessing(filteredFileTreeInput.getRoot(), spec));
}
}
Aggregations