Skip to content

Commit 866a17e

Browse files
author
Dominik Helm
committed
Merge branch 'develop' into feature/TAC2BC
2 parents 3172def + 66ff767 commit 866a17e

File tree

2 files changed

+77
-45
lines changed

2 files changed

+77
-45
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
2+
package org.opalj
3+
package fpcf
4+
package properties
5+
6+
import org.opalj.br.AnnotationLike
7+
import org.opalj.br.ObjectType
8+
import org.opalj.br.analyses.Project
9+
10+
/**
11+
* Basic property matcher for repeatable annotations.
12+
*
13+
* @author Robin Körkemeier
14+
*/
15+
abstract class AbstractRepeatablePropertyMatcher extends AbstractPropertyMatcher {
16+
/**
17+
* Type for identifying the single annotation
18+
*/
19+
val singleAnnotationType: ObjectType
20+
/**
21+
* Type for identifying the container annotation
22+
*/
23+
val containerAnnotationType: ObjectType
24+
25+
/**
26+
* The name of the field of the container annotation that holds the single annotations
27+
*/
28+
val containerAnnotationFieldName: String = "value"
29+
30+
override def validateProperty(
31+
p: Project[?],
32+
as: Set[ObjectType],
33+
entity: Any,
34+
a: AnnotationLike,
35+
properties: Iterable[Property]
36+
): Option[String] = {
37+
if (a.annotationType == singleAnnotationType) {
38+
validateSingleProperty(p, as, entity, a, properties)
39+
} else if (a.annotationType == containerAnnotationType) {
40+
val subAnnotations =
41+
getValue(p, containerAnnotationType, a.elementValuePairs, containerAnnotationFieldName)
42+
.asArrayValue.values.map { a => a.asAnnotationValue.annotation }
43+
44+
val errors = subAnnotations
45+
.map { a => validateSingleProperty(p, as, entity, a, properties) }
46+
.filter { result => result.isDefined }
47+
.map { result => result.get }
48+
49+
if (errors.nonEmpty) {
50+
Some(errors.mkString(" "))
51+
} else {
52+
None
53+
}
54+
} else {
55+
Some(s"Invalid annotation '${a.annotationType}' for ${this.getClass.getName}!")
56+
}
57+
}
58+
59+
/**
60+
* Test if the computed properties are matched by this matcher. Called for each single annotation of a container
61+
* annotation once.
62+
*/
63+
def validateSingleProperty(
64+
p: Project[?],
65+
as: Set[ObjectType],
66+
entity: Any,
67+
a: AnnotationLike,
68+
properties: Iterable[Property]
69+
): Option[String]
70+
}

DEVELOPING_OPAL/validate/src/test/scala/org/opalj/fpcf/properties/callgraph/DirectCallMatcher.scala

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,58 +23,20 @@ import org.opalj.br.fpcf.PropertyStoreKey
2323
import org.opalj.br.fpcf.analyses.ContextProvider
2424
import org.opalj.br.fpcf.properties.cg.Callees
2525

26-
class DirectCallMatcher extends AbstractPropertyMatcher {
26+
class DirectCallMatcher extends AbstractRepeatablePropertyMatcher {
27+
override val singleAnnotationType: ObjectType = ObjectType("org/opalj/fpcf/properties/callgraph/DirectCall")
28+
override val containerAnnotationType: ObjectType = ObjectType("org/opalj/fpcf/properties/callgraph/DirectCalls")
2729

28-
override def validateProperty(
30+
override def validateSingleProperty(
2931
p: Project[_],
3032
as: Set[ObjectType],
3133
entity: Any,
3234
a: AnnotationLike,
3335
properties: Iterable[Property]
3436
): Option[String] = {
35-
// If the entity is annotated with a single annotation, we receive a DirectCall annotation.
36-
// If it is annotated with multiple DirectCall annotations, we receive a single DirectCalls
37-
// container annotation.
38-
val singleAnnotation = ObjectType("org/opalj/fpcf/properties/callgraph/DirectCall")
39-
val containerAnnotation = ObjectType("org/opalj/fpcf/properties/callgraph/DirectCalls")
40-
41-
if (a.annotationType == singleAnnotation) {
42-
validateSingleAnnotation(p, as, entity, a, properties)
43-
44-
} else if (a.annotationType == containerAnnotation) {
45-
// Get sub-annotations from the container annotation.
46-
val subAnnotations: ArraySeq[AnnotationLike] =
47-
getValue(p, containerAnnotation, a.elementValuePairs, "value")
48-
.asArrayValue.values.map(a => a.asAnnotationValue.annotation)
49-
50-
// Validate each sub-annotation individually.
51-
val validationResults =
52-
subAnnotations.map(validateSingleAnnotation(p, as, entity, _, properties))
53-
val errors = validationResults.filter(_.isDefined)
54-
55-
if (errors.nonEmpty) {
56-
Some(errors.mkString(", "))
57-
} else {
58-
None
59-
}
60-
61-
} else {
62-
Some("Invalid annotation.")
63-
}
64-
}
65-
66-
private def validateSingleAnnotation(
67-
p: Project[_],
68-
as: Set[ObjectType],
69-
entity: Any,
70-
a: AnnotationLike,
71-
properties: Iterable[Property]
72-
): Option[String] = {
73-
val annotationType = a.annotationType.asObjectType
74-
7537
// Get call graph analyses for which this annotation applies.
7638
val analysesElementValues: Seq[ElementValue] =
77-
getValue(p, annotationType, a.elementValuePairs, "analyses").asArrayValue.values
39+
getValue(p, singleAnnotationType, a.elementValuePairs, "analyses").asArrayValue.values
7840
val analyses = analysesElementValues.map(ev => ev.asClassValue.value.asObjectType)
7941

8042
// If none of the annotated analyses match the executed ones, return...
@@ -119,8 +81,8 @@ class DirectCallMatcher extends AbstractPropertyMatcher {
11981
// Fetch values from the annotation.
12082
// TODO clean these up and move them into some helper?
12183
// note: there is a helper class in JCG that does something similar
122-
val lineNumber = getValue(p, annotationType, a.elementValuePairs, "line").asIntValue.value
123-
val methodName = getValue(p, annotationType, a.elementValuePairs, "name").asStringValue.value
84+
val lineNumber = getValue(p, singleAnnotationType, a.elementValuePairs, "line").asIntValue.value
85+
val methodName = getValue(p, singleAnnotationType, a.elementValuePairs, "name").asStringValue.value
12486
val resolvedTargets = {
12587
val av = a.elementValuePairs collectFirst {
12688
case ElementValuePair("resolvedTargets", ArrayValue(ab)) =>

0 commit comments

Comments
 (0)