diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/Dependency.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/Dependency.java index 7f086eb307..4bbbd26d1f 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/Dependency.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/Dependency.java @@ -132,6 +132,12 @@ static Set tryCreateFromReferencedClassObject(ReferencedClassObject referencedClassObject.getRawType(), referencedClassObject.getSourceCodeLocation()); } + static Set tryCreateFromTypeCast(TypeCast typeCast) { + return tryCreateDependency( + typeCast.getOwner(), "checks TypeCast", + typeCast.getRawType(), typeCast.getSourceCodeLocation()); + } + static Set tryCreateFromAnnotation(JavaAnnotation target) { Origin origin = findSuitableOrigin(target, target.getAnnotatedElement()); return tryCreateDependency(origin, "is annotated with", target.getRawType()); diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/DomainObjectCreationContext.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/DomainObjectCreationContext.java index 2eb7b065a0..ba42a13bfd 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/DomainObjectCreationContext.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/DomainObjectCreationContext.java @@ -179,6 +179,10 @@ public static InstanceofCheck createInstanceofCheck(JavaCodeUnit codeUnit, JavaC return InstanceofCheck.from(codeUnit, target, lineNumber); } + public static TypeCast createTypeCast(JavaCodeUnit codeUnit, JavaClass javaClass, int lineNumber) { + return TypeCast.from(codeUnit, javaClass, lineNumber); + } + public static JavaTypeVariable createTypeVariable(String name, OWNER owner, JavaClass erasure) { return new JavaTypeVariable<>(name, owner, erasure); } diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java index a0a303b15d..f237f63d83 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java @@ -659,6 +659,11 @@ public Set getReferencedClassObjects() { return members.getReferencedClassObjects(); } + @PublicAPI(usage = ACCESS) + public Set getypeCast() { + return members.getTypeCast(); + } + @Override @PublicAPI(usage = ACCESS) public JavaClass toErasure() { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassDependencies.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassDependencies.java index 667d3a3fc5..0212539efa 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassDependencies.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassDependencies.java @@ -54,6 +54,7 @@ public Set get() { result.addAll(annotationDependenciesFromSelf()); result.addAll(instanceofCheckDependenciesFromSelf()); result.addAll(referencedClassObjectDependenciesFromSelf()); + result.addAll(typeCastDependenciesFromSelf()); result.addAll(typeParameterDependenciesFromSelf()); return result.build(); } @@ -218,6 +219,14 @@ private Set referencedClassObjectDependenciesFromSelf() { return result.build(); } + private Set typeCastDependenciesFromSelf() { + ImmutableSet.Builder result = ImmutableSet.builder(); + for (TypeCast typeCast : javaClass.getypeCast()) { + result.addAll(Dependency.tryCreateFromTypeCast(typeCast)); + } + return result.build(); + } + private Set typeParameterDependenciesFromSelf() { ImmutableSet.Builder result = ImmutableSet.builder(); result.addAll(classTypeParameterDependenciesFromSelf()); diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassMembers.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassMembers.java index ab7b959c38..b8402b33e7 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassMembers.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClassMembers.java @@ -212,6 +212,14 @@ Set getReferencedClassObjects() { return result.build(); } + Set getTypeCast() { + ImmutableSet.Builder result = ImmutableSet.builder(); + for (JavaCodeUnit codeUnit : codeUnits) { + result.addAll(codeUnit.getTypeCast()); + } + return result.build(); + } + Set getFieldAccessesFromSelf() { ImmutableSet.Builder result = ImmutableSet.builder(); for (JavaCodeUnit codeUnit : codeUnits) { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java index 3cde461bab..c3d6f835c6 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/JavaCodeUnit.java @@ -61,6 +61,7 @@ public abstract class JavaCodeUnit private final List> typeParameters; private final Set referencedClassObjects; private final Set instanceofChecks; + private final Set typeCast; private Set fieldAccesses = Collections.emptySet(); private Set methodCalls = Collections.emptySet(); @@ -76,6 +77,7 @@ public abstract class JavaCodeUnit fullName = formatMethod(getOwner().getName(), getName(), namesOf(getRawParameterTypes())); referencedClassObjects = ImmutableSet.copyOf(builder.getReferencedClassObjects(this)); instanceofChecks = ImmutableSet.copyOf(builder.getInstanceofChecks(this)); + typeCast = ImmutableSet.copyOf(builder.getRawTypeCasts(this)); } /** @@ -201,6 +203,11 @@ public Set getInstanceofChecks() { return instanceofChecks; } + @PublicAPI(usage = ACCESS) + public Set getTypeCast() { + return typeCast; + } + @PublicAPI(usage = ACCESS) public Set> getCallsFromSelf() { return union(getMethodCallsFromSelf(), getConstructorCallsFromSelf()); diff --git a/archunit/src/main/java/com/tngtech/archunit/core/domain/TypeCast.java b/archunit/src/main/java/com/tngtech/archunit/core/domain/TypeCast.java new file mode 100644 index 0000000000..24cf83f46f --- /dev/null +++ b/archunit/src/main/java/com/tngtech/archunit/core/domain/TypeCast.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014-2022 TNG Technology Consulting GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tngtech.archunit.core.domain; + +import com.tngtech.archunit.PublicAPI; +import com.tngtech.archunit.core.domain.properties.HasOwner; +import com.tngtech.archunit.core.domain.properties.HasSourceCodeLocation; +import com.tngtech.archunit.core.domain.properties.HasType; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.tngtech.archunit.PublicAPI.Usage.ACCESS; + +@PublicAPI(usage = ACCESS) +public final class TypeCast implements HasType, HasOwner, HasSourceCodeLocation { + + private final JavaCodeUnit owner; + private final JavaClass value; + private final int lineNumber; + private final SourceCodeLocation sourceCodeLocation; + + private TypeCast(JavaCodeUnit owner, JavaClass value, int lineNumber) { + this.owner = checkNotNull(owner); + this.value = checkNotNull(value); + this.lineNumber = lineNumber; + sourceCodeLocation = SourceCodeLocation.of(owner.getOwner(), lineNumber); + } + + @Override + @PublicAPI(usage = ACCESS) + public JavaClass getRawType() { + return value; + } + + @Override + @PublicAPI(usage = ACCESS) + public JavaType getType() { + return value; + } + + @Override + @PublicAPI(usage = ACCESS) + public JavaCodeUnit getOwner() { + return owner; + } + + @PublicAPI(usage = ACCESS) + public int getLineNumber() { + return lineNumber; + } + + @Override + public SourceCodeLocation getSourceCodeLocation() { + return sourceCodeLocation; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("owner", owner) + .add("target", value) + .add("lineNumber", lineNumber) + .toString(); + } + + static TypeCast from(JavaCodeUnit owner, JavaClass target, int lineNumber) { + return new TypeCast(owner, target, lineNumber); + } +} diff --git a/archunit/src/main/java/com/tngtech/archunit/core/importer/DomainBuilders.java b/archunit/src/main/java/com/tngtech/archunit/core/importer/DomainBuilders.java index fabd004a71..cec0d13d4a 100644 --- a/archunit/src/main/java/com/tngtech/archunit/core/importer/DomainBuilders.java +++ b/archunit/src/main/java/com/tngtech/archunit/core/importer/DomainBuilders.java @@ -34,54 +34,20 @@ import com.tngtech.archunit.base.Function; import com.tngtech.archunit.base.HasDescription; import com.tngtech.archunit.base.Optional; -import com.tngtech.archunit.core.domain.AccessTarget; +import com.tngtech.archunit.core.domain.*; import com.tngtech.archunit.core.domain.AccessTarget.CodeUnitAccessTarget; import com.tngtech.archunit.core.domain.AccessTarget.ConstructorCallTarget; import com.tngtech.archunit.core.domain.AccessTarget.ConstructorReferenceTarget; import com.tngtech.archunit.core.domain.AccessTarget.FieldAccessTarget; import com.tngtech.archunit.core.domain.AccessTarget.MethodCallTarget; import com.tngtech.archunit.core.domain.AccessTarget.MethodReferenceTarget; -import com.tngtech.archunit.core.domain.DomainObjectCreationContext; -import com.tngtech.archunit.core.domain.Formatters; -import com.tngtech.archunit.core.domain.InstanceofCheck; -import com.tngtech.archunit.core.domain.JavaAnnotation; -import com.tngtech.archunit.core.domain.JavaClass; -import com.tngtech.archunit.core.domain.JavaClassDescriptor; -import com.tngtech.archunit.core.domain.JavaCodeUnit; -import com.tngtech.archunit.core.domain.JavaConstructor; -import com.tngtech.archunit.core.domain.JavaConstructorCall; -import com.tngtech.archunit.core.domain.JavaConstructorReference; -import com.tngtech.archunit.core.domain.JavaEnumConstant; -import com.tngtech.archunit.core.domain.JavaField; -import com.tngtech.archunit.core.domain.JavaFieldAccess; import com.tngtech.archunit.core.domain.JavaFieldAccess.AccessType; -import com.tngtech.archunit.core.domain.JavaMember; -import com.tngtech.archunit.core.domain.JavaMethod; -import com.tngtech.archunit.core.domain.JavaMethodCall; -import com.tngtech.archunit.core.domain.JavaMethodReference; -import com.tngtech.archunit.core.domain.JavaModifier; -import com.tngtech.archunit.core.domain.JavaParameter; -import com.tngtech.archunit.core.domain.JavaParameterizedType; -import com.tngtech.archunit.core.domain.JavaStaticInitializer; -import com.tngtech.archunit.core.domain.JavaType; -import com.tngtech.archunit.core.domain.JavaTypeVariable; -import com.tngtech.archunit.core.domain.JavaWildcardType; -import com.tngtech.archunit.core.domain.ReferencedClassObject; -import com.tngtech.archunit.core.domain.Source; -import com.tngtech.archunit.core.domain.ThrowsClause; import com.tngtech.archunit.core.domain.properties.HasTypeParameters; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Sets.union; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completeTypeVariable; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createGenericArrayType; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createInstanceofCheck; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createReferencedClassObject; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createSource; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createThrowsClause; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createTypeVariable; -import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createWildcardType; +import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.*; import static com.tngtech.archunit.core.domain.Formatters.ensureCanonicalArrayTypeName; import static com.tngtech.archunit.core.domain.JavaConstructor.CONSTRUCTOR_NAME; import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf; @@ -248,6 +214,7 @@ public abstract static class JavaCodeUnitBuilder throwsDeclarations; private final Set rawReferencedClassObjects = new HashSet<>(); private final List instanceOfChecks = new ArrayList<>(); + private final List rawTypeCasts = new ArrayList<>(); private JavaCodeUnitBuilder() { } @@ -289,6 +256,11 @@ SELF addInstanceOfCheck(RawInstanceofCheck rawInstanceOfChecks) { return self(); } + SELF addRawTypeCast(RawTypeCast rawTypeCast) { + this.rawTypeCasts.add(rawTypeCast); + return self(); + } + List getParameterTypeNames() { ImmutableList.Builder result = ImmutableList.builder(); for (JavaClassDescriptor parameter : rawParameterTypes) { @@ -359,6 +331,14 @@ public Set getInstanceofChecks(JavaCodeUnit codeUnit) { return result.build(); } + public Set getRawTypeCasts(JavaCodeUnit codeUnit) { + ImmutableSet.Builder result = ImmutableSet.builder(); + for (RawTypeCast rawTypeCast : this.rawTypeCasts) { + result.add(createTypeCast(codeUnit, get(rawTypeCast.getTarget().getFullyQualifiedClassName()), rawTypeCast.getLineNumber())); + } + return result.build(); + } + private List asJavaClasses(List descriptors) { ImmutableList.Builder result = ImmutableList.builder(); for (JavaClassDescriptor javaClassDescriptor : descriptors) { diff --git a/archunit/src/main/java/com/tngtech/archunit/core/importer/RawTypeCast.java b/archunit/src/main/java/com/tngtech/archunit/core/importer/RawTypeCast.java new file mode 100644 index 0000000000..dd4400b15e --- /dev/null +++ b/archunit/src/main/java/com/tngtech/archunit/core/importer/RawTypeCast.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2022 TNG Technology Consulting GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.tngtech.archunit.core.importer; + +import com.tngtech.archunit.core.domain.JavaClassDescriptor; + +import static com.google.common.base.MoreObjects.toStringHelper; + +class RawTypeCast { + + private final JavaClassDescriptor target; + private final int lineNumber; + + private RawTypeCast(JavaClassDescriptor target, int lineNumber) { + this.target = target; + this.lineNumber = lineNumber; + } + + static RawTypeCast from(JavaClassDescriptor target, int lineNumber) { + return new RawTypeCast(target, lineNumber); + } + + JavaClassDescriptor getTarget() { + return target; + } + + int getLineNumber() { + return lineNumber; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("target", target) + .add("lineNumber", lineNumber) + .toString(); + } +}