Skip to content

Commit d40e90d

Browse files
committed
functions and messages can now be annotated with "not-used" to ignore warnings (e.g. if used from external code)
1 parent cc6c850 commit d40e90d

File tree

2 files changed

+124
-118
lines changed

2 files changed

+124
-118
lines changed

language/thingml/src/org/thingml/xtext/validation/checks/FunctionUsage.xtend

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class FunctionUsage extends ThingMLValidatorCheck {
4343

4444
@Check(NORMAL)
4545
def checkUsage(Function f) {
46+
if (AnnotatedElementHelper.isDefined(f, "ignore", "not-used")) return;
4647
val thing = ThingMLHelpers.findContainingThing(f)
4748
//Checks if the containing thing calls the function
4849
if (ActionHelper.getAllActions(thing, FunctionCallStatement).exists[call | call.function == f || call.function.name == f.name])
Lines changed: 123 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,123 @@
1-
package org.thingml.xtext.validation.checks
2-
3-
import org.eclipse.emf.common.util.EList
4-
import org.eclipse.xtext.validation.Check
5-
import org.thingml.xtext.constraints.ThingMLHelpers
6-
import org.thingml.xtext.constraints.Types
7-
import org.thingml.xtext.helpers.ActionHelper
8-
import org.thingml.xtext.helpers.StateHelper
9-
import org.thingml.xtext.helpers.TyperHelper
10-
import org.thingml.xtext.thingML.Configuration
11-
import org.thingml.xtext.thingML.ExternalConnector
12-
import org.thingml.xtext.thingML.Message
13-
import org.thingml.xtext.thingML.SendAction
14-
import org.thingml.xtext.thingML.Thing
15-
import org.thingml.xtext.thingML.ThingMLPackage
16-
import org.thingml.xtext.validation.ThingMLValidatorCheck
17-
import org.thingml.xtext.validation.TypeChecker
18-
19-
class MessageUsage extends ThingMLValidatorCheck {
20-
21-
def boolean isSerializable(Message m) {
22-
return m.parameters.forall[ p |
23-
p.typeRef !== null && p.typeRef.type !== null && TyperHelper.isSerializable(p.typeRef.type )
24-
]
25-
}
26-
27-
@Check(FAST)
28-
def checkSerialization(ExternalConnector c) {
29-
val nonSerializable = c.port.receives.filter[m | !isSerializable(m)].toSet
30-
nonSerializable.addAll(c.port.sends.filter[m | !isSerializable(m)])
31-
if (nonSerializable.size > 0) {
32-
val msg = nonSerializable.join("Message(s) ", ", ", " is/are not serializable and cannot be used on an external connector ", [name])
33-
error(msg, c.eContainer, ThingMLPackage.eINSTANCE.configuration_Connectors, (c.eContainer as Configuration).connectors.indexOf(c), "serialization")
34-
}
35-
}
36-
37-
@Check(FAST)
38-
def checkMessageNotSent(Thing thing) {
39-
if (thing.fragment) return
40-
val allSendActions = ActionHelper.getAllActions(thing, SendAction)
41-
ThingMLHelpers.allPorts(thing).forEach[p |
42-
p.sends.forEach[m, i|
43-
val isSent = allSendActions.exists[sa | sa.port === p && sa.message === m]
44-
if (!isSent) {
45-
val msg = "Message " + p.name + "." + m.name + " is never sent"
46-
val t = ThingMLHelpers.findContainingThing(p)
47-
if (t == thing)
48-
warning(msg, p, ThingMLPackage.eINSTANCE.port_Sends, i, "message-never-sent")
49-
else //FIXME: this assumes the port/message comes from a Thing directly included (which is OK for 99% of the case), but will highlight the wrong include if it comes from several levels of includes... The old implementation was also doing the same "mistale"
50-
warning(msg, thing, ThingMLPackage.eINSTANCE.thing_Includes, thing.includes.indexOf(t), "included-messages-never-sent")
51-
}
52-
]
53-
]
54-
}
55-
56-
@Check(FAST)
57-
def checkMessageNotReceived(Thing thing) {
58-
if (thing.fragment) return;
59-
val handlers = StateHelper.allMessageHandlers(thing)
60-
// Check own ports
61-
ThingMLHelpers.allPorts(thing).forEach[p |
62-
p.receives.forEach[m, i|
63-
if (handlers.get(p) === null || handlers.get(p).get(m) === null) {
64-
val msg = "Message " + p.name + "." + m.name + " is never received"
65-
val t = ThingMLHelpers.findContainingThing(p)
66-
if (t == thing)
67-
warning(msg, p, ThingMLPackage.eINSTANCE.port_Receives, i, "message-never-used")
68-
else //FIXME: this assumes the port/message comes from a Thing directly included (which is OK for 99% of the case), but will highlight the wrong include if it comes from several levels of includes... The old implementation was also doing the same "mistale"
69-
warning(msg, thing, ThingMLPackage.eINSTANCE.thing_Includes, thing.includes.indexOf(t), "included-messages-never-used")
70-
71-
}
72-
]
73-
]
74-
}
75-
76-
@Check(FAST)
77-
def checkSendAction(SendAction send) {
78-
val msg = send.message
79-
val params = send.parameters
80-
val parent = send.eContainer.eGet(send.eContainingFeature)
81-
// Check that the message is sent with the right number of parameters
82-
if (msg.parameters.size !== params.size) {
83-
val m = "Message "+msg.name+" is sent with a wrong number of parameters. Expected "+msg.parameters.size+", sent with "+params.size
84-
if (parent instanceof EList)
85-
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "message-send-wrong-number-parameters")
86-
else
87-
error(m, send.eContainer, send.eContainingFeature, "message-send-wrong-number-parameters")
88-
return;
89-
}
90-
// Check that the parameters are properly typed
91-
msg.parameters.forEach [ p, i |
92-
val e = params.get(i);
93-
val expected = TyperHelper.getBroadType(p.getTypeRef());
94-
val actual = TypeChecker.computeTypeOf(e);
95-
if (actual !== null) {
96-
if (actual.equals(Types.ERROR_TYPEREF)) {
97-
val m = "Message "+msg.name+" is sent with an erroneous parameter. Expected "+Types.toString(expected)+", sent with "+Types.toString(TyperHelper.getBroadType(actual))
98-
if (parent instanceof EList)
99-
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type")
100-
else
101-
error(m, send.eContainer, send.eContainingFeature, "type")
102-
} else if (actual.equals(Types.ANY_TYPEREF)) {
103-
val m = "Message "+msg.name+" is sent with a parameter which cannot be typed. Consider using a cast (<exp> as <type>)."
104-
if (parent instanceof EList)
105-
warning(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type-cast", p.getTypeRef().getType().name)
106-
else
107-
warning(m, send.eContainer, send.eContainingFeature, "type-cast", p.getTypeRef().getType().name)
108-
} else if (!TyperHelper.isA(actual, expected)) {
109-
val m = "Message "+msg.name+" is sent with an erroneous parameter. Expected "+Types.toString(expected)+", sent with "+Types.toString(TyperHelper.getBroadType(actual))
110-
if (parent instanceof EList)
111-
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type")
112-
else
113-
error(m, send.eContainer, send.eContainingFeature, "type")
114-
}
115-
}
116-
]
117-
}
118-
}
1+
package org.thingml.xtext.validation.checks
2+
3+
import org.eclipse.emf.common.util.EList
4+
import org.eclipse.xtext.validation.Check
5+
import org.thingml.xtext.constraints.ThingMLHelpers
6+
import org.thingml.xtext.constraints.Types
7+
import org.thingml.xtext.helpers.ActionHelper
8+
import org.thingml.xtext.helpers.AnnotatedElementHelper
9+
import org.thingml.xtext.helpers.StateHelper
10+
import org.thingml.xtext.helpers.TyperHelper
11+
import org.thingml.xtext.thingML.Configuration
12+
import org.thingml.xtext.thingML.ExternalConnector
13+
import org.thingml.xtext.thingML.Message
14+
import org.thingml.xtext.thingML.SendAction
15+
import org.thingml.xtext.thingML.Thing
16+
import org.thingml.xtext.thingML.ThingMLPackage
17+
import org.thingml.xtext.validation.ThingMLValidatorCheck
18+
import org.thingml.xtext.validation.TypeChecker
19+
20+
class MessageUsage extends ThingMLValidatorCheck {
21+
22+
def boolean isSerializable(Message m) {
23+
return m.parameters.forall[ p |
24+
p.typeRef !== null && p.typeRef.type !== null && TyperHelper.isSerializable(p.typeRef.type )
25+
]
26+
}
27+
28+
@Check(FAST)
29+
def checkSerialization(ExternalConnector c) {
30+
val nonSerializable = c.port.receives.filter[m | !isSerializable(m)].toSet
31+
nonSerializable.addAll(c.port.sends.filter[m | !isSerializable(m)])
32+
if (nonSerializable.size > 0) {
33+
val msg = nonSerializable.join("Message(s) ", ", ", " is/are not serializable and cannot be used on an external connector ", [name])
34+
error(msg, c.eContainer, ThingMLPackage.eINSTANCE.configuration_Connectors, (c.eContainer as Configuration).connectors.indexOf(c), "serialization")
35+
}
36+
}
37+
38+
@Check(FAST)
39+
def checkMessageNotSent(Thing thing) {
40+
if (thing.fragment) return
41+
val allSendActions = ActionHelper.getAllActions(thing, SendAction)
42+
ThingMLHelpers.allPorts(thing).forEach[p |
43+
p.sends.forEach[m, i|
44+
if (!AnnotatedElementHelper.isDefined(m, "ignore", "not-used")) {
45+
val isSent = allSendActions.exists[sa | sa.port === p && sa.message === m]
46+
if (!isSent) {
47+
val msg = "Message " + p.name + "." + m.name + " is never sent"
48+
val t = ThingMLHelpers.findContainingThing(p)
49+
if (t == thing)
50+
warning(msg, p, ThingMLPackage.eINSTANCE.port_Sends, i, "message-never-sent")
51+
else //FIXME: this assumes the port/message comes from a Thing directly included (which is OK for 99% of the case), but will highlight the wrong include if it comes from several levels of includes... The old implementation was also doing the same "mistale"
52+
warning(msg, thing, ThingMLPackage.eINSTANCE.thing_Includes, thing.includes.indexOf(t), "included-messages-never-sent")
53+
}
54+
}
55+
]
56+
]
57+
}
58+
59+
@Check(FAST)
60+
def checkMessageNotReceived(Thing thing) {
61+
if (thing.fragment) return;
62+
val handlers = StateHelper.allMessageHandlers(thing)
63+
// Check own ports
64+
ThingMLHelpers.allPorts(thing).forEach[p |
65+
p.receives.forEach[m, i|
66+
if (AnnotatedElementHelper.isDefined(m, "ignore", "not-used")) {
67+
if (handlers.get(p) === null || handlers.get(p).get(m) === null) {
68+
val msg = "Message " + p.name + "." + m.name + " is never received"
69+
val t = ThingMLHelpers.findContainingThing(p)
70+
if (t == thing)
71+
warning(msg, p, ThingMLPackage.eINSTANCE.port_Receives, i, "message-never-used")
72+
else //FIXME: this assumes the port/message comes from a Thing directly included (which is OK for 99% of the case), but will highlight the wrong include if it comes from several levels of includes... The old implementation was also doing the same "mistale"
73+
warning(msg, thing, ThingMLPackage.eINSTANCE.thing_Includes, thing.includes.indexOf(t), "included-messages-never-used")
74+
75+
}
76+
}
77+
]
78+
]
79+
}
80+
81+
@Check(FAST)
82+
def checkSendAction(SendAction send) {
83+
val msg = send.message
84+
val params = send.parameters
85+
val parent = send.eContainer.eGet(send.eContainingFeature)
86+
// Check that the message is sent with the right number of parameters
87+
if (msg.parameters.size !== params.size) {
88+
val m = "Message "+msg.name+" is sent with a wrong number of parameters. Expected "+msg.parameters.size+", sent with "+params.size
89+
if (parent instanceof EList)
90+
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "message-send-wrong-number-parameters")
91+
else
92+
error(m, send.eContainer, send.eContainingFeature, "message-send-wrong-number-parameters")
93+
return;
94+
}
95+
// Check that the parameters are properly typed
96+
msg.parameters.forEach [ p, i |
97+
val e = params.get(i);
98+
val expected = TyperHelper.getBroadType(p.getTypeRef());
99+
val actual = TypeChecker.computeTypeOf(e);
100+
if (actual !== null) {
101+
if (actual.equals(Types.ERROR_TYPEREF)) {
102+
val m = "Message "+msg.name+" is sent with an erroneous parameter. Expected "+Types.toString(expected)+", sent with "+Types.toString(TyperHelper.getBroadType(actual))
103+
if (parent instanceof EList)
104+
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type")
105+
else
106+
error(m, send.eContainer, send.eContainingFeature, "type")
107+
} else if (actual.equals(Types.ANY_TYPEREF)) {
108+
val m = "Message "+msg.name+" is sent with a parameter which cannot be typed. Consider using a cast (<exp> as <type>)."
109+
if (parent instanceof EList)
110+
warning(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type-cast", p.getTypeRef().getType().name)
111+
else
112+
warning(m, send.eContainer, send.eContainingFeature, "type-cast", p.getTypeRef().getType().name)
113+
} else if (!TyperHelper.isA(actual, expected)) {
114+
val m = "Message "+msg.name+" is sent with an erroneous parameter. Expected "+Types.toString(expected)+", sent with "+Types.toString(TyperHelper.getBroadType(actual))
115+
if (parent instanceof EList)
116+
error(m, send.eContainer, send.eContainingFeature, (parent as EList).indexOf(send), "type")
117+
else
118+
error(m, send.eContainer, send.eContainingFeature, "type")
119+
}
120+
}
121+
]
122+
}
123+
}

0 commit comments

Comments
 (0)