![]() |
|
Navigation |
Examples First we import the basic data types for representing Java. The model is called M3, and its definition is split acros a generic
language independent module called Rascal:analysis/m3/Core and a Java specific part called Rascal:lang/java/m3/Core. Have a look at the documentation
of these modules later. For now we will go through using them in a few examples.
rascal>import lang::java::m3::Core;
ok
Then we import the API for extracting an M3 model from an Eclipse project.
rascal>import lang::java::jdt::m3::Core;
ok
Calling the following function generates an enormous value representing everything the Eclipse Java compiler knows about this project:
rascal>myModel = createM3FromEclipseProject(|project://example-project|);
M3: m3(|project://example-project|)[
@annotations={
<|java+method:///Apple/edible()|,|java+interface:///java/lang/Override|>,
<|java+method:///Fruit/edible()|,|java+interface:///java/lang/Override|>
},
@typeDependency={
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+class:///java/io/PrintStream|>,
<|java+method:///Apple/edible()|,|java+primitiveType:///boolean|>,
<|java+method:///Apple/edible()|,|java+interface:///java/lang/Override|>,
<|java+method:///Fruit/edible()|,|java+primitiveType:///boolean|>,
<|java+method:///Fruit/edible()|,|java+interface:///java/lang/Override|>,
<|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|,|java+array:///java/lang/String%5B%5D|>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+class:///java/lang/System|>,
<|java+class:///Apple|,|java+class:///Fruit|>,
<|java+method:///IFruit/edible()|,|java+primitiveType:///boolean|>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+primitiveType:///void|>,
<|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|,|java+class:///java/lang/String|>,
<|java+class:///Fruit|,|java+interface:///IFruit|>
},
@methodOverrides={
<|java+method:///Apple/edible()|,|java+method:///IFruit/edible()|>,
<|java+method:///Fruit/edible()|,|java+method:///IFruit/edible()|>,
<|java+method:///Apple/edible()|,|java+method:///Fruit/edible()|>
},
@names={
<"IFruit",|java+interface:///IFruit|>,
<"HelloWorld",|java+class:///HelloWorld|>,
<"args",|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|>,
<"edible",|java+method:///Fruit/edible()|>,
<"out",|java+field:///java/lang/System/out|>,
<"edible",|java+method:///Apple/edible()|>,
<"main",|java+method:///HelloWorld/main(java.lang.String%5B%5D)|>,
<"String",|java+class:///java/lang/String|>,
<"edible",|java+method:///IFruit/edible()|>,
<"println",|java+method:///java/io/PrintStream/println(java.lang.String)|>,
<"Override",|java+interface:///java/lang/Override|>,
<"System",|java+class:///java/lang/System|>,
<"Apple",|java+class:///Apple|>,
<"Fruit",|java+class:///Fruit|>
},
@implements={<|java+class:///Fruit|,|java+interface:///IFruit|>},
@methodInvocation={<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+method:///java/io/PrintStream/println(java.lang.String)|>},
@containment={
<|java+compilationUnit:///src/IFruit.java|,|java+interface:///IFruit|>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|>,
<|java+class:///Fruit|,|java+method:///Fruit/edible()|>,
<|java+class:///HelloWorld|,|java+method:///HelloWorld/main(java.lang.String%5B%5D)|>,
<|java+compilationUnit:///src/Fruit.java|,|java+class:///Fruit|>,
<|java+compilationUnit:///src/HelloWorld.java|,|java+class:///HelloWorld|>,
<|java+class:///Apple|,|java+method:///Apple/edible()|>,
<|java+interface:///IFruit|,|java+method:///IFruit/edible()|>,
<|java+compilationUnit:///src/Apple.java|,|java+class:///Apple|>
},
@documentation={},
@modifiers={
<|java+interface:///IFruit|,public()>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,static()>,
<|java+class:///Fruit|,abstract()>,
<|java+method:///Apple/edible()|,public()>,
<|java+method:///Fruit/edible()|,public()>,
<|java+class:///Apple|,public()>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,public()>,
<|java+class:///HelloWorld|,public()>,
<|java+method:///Fruit/edible()|,abstract()>,
<|java+class:///Fruit|,public()>
},
@fieldAccess={<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+field:///java/lang/System/out|>},
@messages=[],
@uses={
<|project://example-project/src/Apple.java|(28,5,<2,27>,<2,32>),|java+class:///Fruit|>,
<|project://example-project/src/HelloWorld.java|(71,6,<4,2>,<4,8>),|java+class:///java/lang/System|>,
<|project://example-project/src/HelloWorld.java|(82,7,<4,13>,<4,20>),|java+method:///java/io/PrintStream/println(java.lang.String)|>,
<|project://example-project/src/Fruit.java|(51,8,<3,2>,<3,10>),|java+interface:///java/lang/Override|>,
<|project://example-project/src/Apple.java|(39,8,<4,2>,<4,10>),|java+interface:///java/lang/Override|>,
<|project://example-project/src/HelloWorld.java|(78,3,<4,9>,<4,12>),|java+field:///java/lang/System/out|>,
<|project://example-project/src/Fruit.java|(40,6,<2,39>,<2,45>),|java+interface:///IFruit|>,
<|project://example-project/src/HelloWorld.java|(52,6,<3,25>,<3,31>),|java+class:///java/lang/String|>
},
@types={
<|java+class:///HelloWorld|,class(
|java+class:///HelloWorld|,
[])>,
<|java+class:///Fruit|,class(
|java+class:///Fruit|,
[])>,
<|java+class:///Apple|,class(
|java+class:///Apple|,
[])>,
<|java+method:///IFruit/edible()|,method(
|java+method:///IFruit/edible()|,
[],
boolean(),
[])>,
<|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|,array(
class(
|java+class:///java/lang/String|,
[]),
1)>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,method(
|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,
[],
void(),
[array(
class(
|java+class:///java/lang/String|,
[]),
1)])>,
<|java+method:///Apple/edible()|,method(
|java+method:///Apple/edible()|,
[],
boolean(),
[])>,
<|java+method:///Fruit/edible()|,method(
|java+method:///Fruit/edible()|,
[],
boolean(),
[])>,
<|java+interface:///IFruit|,interface(
|java+interface:///IFruit|,
[])>
},
@extends={<|java+class:///Apple|,|java+class:///Fruit|>},
@declarations={
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|project://example-project/src/HelloWorld.java|(28,82,<3,1>,<6,2>)>,
<|java+compilationUnit:///src/IFruit.java|,|project://example-project/src/IFruit.java|(0,48,<1,0>,<4,2>)>,
<|java+method:///Apple/edible()|,|project://example-project/src/Apple.java|(38,54,<4,1>,<7,2>)>,
<|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|,|project://example-project/src/HelloWorld.java|(52,13,<3,25>,<3,38>)>,
<|java+compilationUnit:///src/HelloWorld.java|,|project://example-project/src/HelloWorld.java|(0,113,<1,0>,<7,2>)>,
<|java+class:///HelloWorld|,|project://example-project/src/HelloWorld.java|(1,111,<2,0>,<7,1>)>,
<|java+compilationUnit:///src/Apple.java|,|project://example-project/src/Apple.java|(0,96,<1,0>,<9,2>)>,
<|java+class:///Apple|,|project://example-project/src/Apple.java|(1,94,<2,0>,<9,1>)>,
<|java+class:///Fruit|,|project://example-project/src/Fruit.java|(1,95,<2,0>,<5,1>)>,
<|java+interface:///IFruit|,|project://example-project/src/IFruit.java|(1,46,<2,0>,<4,1>)>,
<|java+compilationUnit:///src/Fruit.java|,|project://example-project/src/Fruit.java|(0,97,<1,0>,<5,2>)>,
<|java+method:///IFruit/edible()|,|project://example-project/src/IFruit.java|(28,17,<3,1>,<3,18>)>,
<|java+method:///Fruit/edible()|,|project://example-project/src/Fruit.java|(50,44,<3,1>,<4,34>)>
}
]
Next, let's focus on the containment relation. This defines what parts of the source code are parts of which other parts:
rascal>myModel@containment
rel[loc from,loc to]: {
<|java+compilationUnit:///src/IFruit.java|,|java+interface:///IFruit|>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,|java+parameter:///HelloWorld/main(java.lang.String%5B%5D)/args|>,
<|java+class:///Fruit|,|java+method:///Fruit/edible()|>,
<|java+class:///HelloWorld|,|java+method:///HelloWorld/main(java.lang.String%5B%5D)|>,
<|java+compilationUnit:///src/Fruit.java|,|java+class:///Fruit|>,
<|java+compilationUnit:///src/HelloWorld.java|,|java+class:///HelloWorld|>,
<|java+class:///Apple|,|java+method:///Apple/edible()|>,
<|java+interface:///IFruit|,|java+method:///IFruit/edible()|>,
<|java+compilationUnit:///src/Apple.java|,|java+class:///Apple|>
}
As you can read, classes contain methods, methods contain variables, etc. Classes could also contain other classes (nested classes), and methods can even contain classes (anonymous classes). Let's focus on a specific class, and project what it contains from the relation:
rascal>myModel@containment[|java+class:///HelloWorld|]
set[loc]: {|java+method:///HelloWorld/main(java.lang.String%5B%5D)|}
Let's filter the methods:
rascal>helloWorldMethods = [ e | e <- myModel@containment[|java+class:///HelloWorld|], e.scheme == "java+method"];
list[loc]: [|java+method:///HelloWorld/main(java.lang.String%5B%5D)|]
And we are ready to compute our first metric. How many methods does this class contain?
rascal>import List; ok rascal>size(helloWorldMethods) int: 1No magic applied! It is just a little query on a model that knows everything about the code. Let's generalize and compute the number of methods for all classes in one big expression. First a function to compute the number for a given class: rascal>int numberOfMethods(loc cl, M3 model) = size([ m | m <- model@containment[cl], isMethod(m)]);
int (loc, M3): int numberOfMethods(loc, M3);
then we apply this new function to give us a map from classes to integers:
rascal>map[loc class, int methodCount] numberOfMethodsPerClass = (cl:numberOfMethods(cl, myModel) | <cl,_> <- myModel@containment, isClass(cl));
map[loc class, int methodCount]: (
|java+class:///Fruit|:1,
|java+class:///Apple|:1,
|java+class:///HelloWorld|:1
)
how about the number of fields?
rascal>int numberOfFields(loc cl, M3 model) = size([ m | m <- model@containment[cl], isField(m)]); int (loc, M3): int numberOfFields(loc, M3); rascal>map[loc class, int fieldCount] numberOfFieldsPerClass = (cl:numberOfFields(cl, myModel) | <cl,_> <- myModel@containment, isClass(cl)); map[loc class, int fieldCount]: ( |java+class:///Fruit|:0, |java+class:///Apple|:0, |java+class:///HelloWorld|:0 )what is the ratio between fields and methods for each class? rascal>(cl : (numberOfFieldsPerClass[cl] * 1.0) / (numberOfMethodsPerClass[cl] * 1.0) | cl <- classes(myModel))
map[loc, real]: (
|java+class:///Fruit|:0.,
|java+class:///Apple|:0.,
|java+class:///HelloWorld|:0.
)
![]() |