Commit 3f79b8e3 authored by Gerson SUNYE's avatar Gerson SUNYE
Browse files

Merge branch 'fix/770-CommentRequired' into 'master'

Fix #770 comment required

Closes #770

See merge request naomod/mde/projet-2019!31
parents 4910a210 d5c398c2
......@@ -11,6 +11,7 @@
<mapEntry key="bestPractices" value="/projet-2019/src/main/atl/bestPractices.asm"/>
<mapEntry key="codestyle" value="/projet-2019/src/main/atl/codestyle.asm"/>
<mapEntry key="design" value="/projet-2019/src/main/atl/design.asm"/>
<mapEntry key="documentation" value="/projet-2019/src/main/atl/documentation.asm"/>
<mapEntry key="errorProne" value="/projet-2019/src/main/atl/errorProne.asm"/>
<mapEntry key="multithreading" value="/projet-2019/src/main/atl/multithreading.asm"/>
<mapEntry key="performance" value="/projet-2019/src/main/atl/performance.asm"/>
......@@ -44,7 +45,7 @@
<mapEntry key="OUT" value="smm"/>
</mapAttribute>
<mapAttribute key="Path">
<mapEntry key="IN" value="/projet-2019/input/use-notify-all-instead-of-notify.xmi"/>
<mapEntry key="IN" value="/projet-2019/input/comment-required.xmi"/>
<mapEntry key="OUT" value="/projet-2019/output/metrics.xmi"/>
<mapEntry key="java" value="uri:http://www.eclipse.org/MoDisco/Java/0.2.incubation/java"/>
<mapEntry key="smm" value="uri:http://www.eclipse.org/MoDisco/SMM/1.0.Beta2/smm"/>
......
This diff is collapsed.
......@@ -10,8 +10,10 @@ uses codestyle;
uses multithreading;
uses performance;
uses bestPractices;
uses documentation;
uses errorProne;
rule Java2SMM {
from
project: java!Model
......@@ -59,9 +61,14 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.useIndexOfChar(),
thisModule.avoidPrintStackTrace(),
-- Documentation rules
--
thisModule.commentRequired(),
-- Error prone rules
--
thisModule.missingBreakInSwitch()
};
......@@ -420,3 +427,43 @@ rule MeasureUseNotifyAllInsteadOfNotify(method: java!MethodInvocation) {
useNotifyAllInsteadOfNotify;
}
}
-- Creates a measure instance for each element that violates the rule : CommentRequired
rule MeasureCommentRequired(element: java!BodyDeclaration, violatedProperties: Set(String)) {
to
om: smm!ObservedMeasure (
measure <- commentRequired,
measurements <- measurement
),
commentRequired: smm!DimensionalMeasure (
name <- 'CommentRequired',
shortDescription <- 'Denotes whether comments are required (or unwanted) for specific language elements.'
),
measurement: smm!DirectMeasurement (
error <- 'Violated the properties {' + violatedProperties + '} in Class: ' + element.originalCompilationUnit.name + ' -> ' + element.oclType().name + ': ' + element.modifier.visibility + ' ' + thisModule.getBodyDeclarationName(element)
)
do {
commentRequired;
}
}
-- Returns the declaration name of a BodyDeclaration
-- In FielDeclaration, the attribute 'name' is NULL, this information is contained in "fragments" instead
helper def: getBodyDeclarationName(elem: java!BodyDeclaration): String =
if (elem.oclIsTypeOf(java!FieldDeclaration))
then elem.fragments.first().name
else elem.name
endif
;
-- Returns the AnnotationTypeDeclaration corresponding to the given BodyDeclaration
-- This is necessary because BodyDeclaration.annotations returns Sequence(!IN<unamed>)
helper def: getAnnotationTypeDeclarationsFromBodyDeclaration(elem: java!BodyDeclaration): Set(java!AnnotationTypeDeclaration) =
java!AnnotationTypeDeclaration.allInstances()
->select(annotTypeDec |
annotTypeDec.usagesInTypeAccess->exists(usage |
(usage.eContainer().eContainer().name = elem.name)
.and(usage.eContainer().eContainer().modifier.visibility = elem.modifier.visibility)
.and(usage.eContainer().eContainer().originalCompilationUnit.name = elem.originalCompilationUnit.name))
)
;
library documentation;
--------------------------------------------- CommentRequired ---------------------------------------------
-- Returs a set of measures for each element that violates the rule : CommentRequired
helper def: commentRequired() : Set(smm!Measure) =
java!BodyDeclaration.allInstances()
-> select (elem | elem.proxy = false)
-- Get only elements concerned by the CommentRequired properties
-> select (elem | thisModule.commentRequiredPropertyDefinitions().getKeys().contains(elem.oclType().name))
-> select (elem | thisModule.violatesCommentRequired(elem))
-> collect (elem | thisModule.MeasureCommentRequired(elem, thisModule.violatedCommentRequiredProperties(elem)))
;
-- Returns true if the given elem violates any of the CommentRequired rule properties
helper def: violatesCommentRequired(elem: java!BodyDeclaration): Boolean =
-- An element violates a property if there's at least one that's violated,
(thisModule.commentRequiredPropertyDefinitions().get(elem.oclType().name)
->exists(propertyTuple | thisModule.matchesCommentRequiredProperty('Required',elem, propertyTuple)))
-- AND IF it doesn't match any 'Ignored' properties
.and(
not thisModule.commentRequiredPropertyDefinitions().get(elem.oclType().name)
->exists(propertyTuple | thisModule.matchesCommentRequiredProperty('Ignored',elem, propertyTuple))
)
;
-- Returns the list of violated CommentRequired properties as a string
helper def: violatedCommentRequiredProperties(elem: java!BodyDeclaration): String =
-- Get the set of property tuples associated to elem by using elem data type as key to the Map
thisModule.commentRequiredPropertyDefinitions().get(elem.oclType().name)
-- Concatenate to propertyNames : the name of each property rules that matches requirements for elem
->select(propertyTuple | thisModule.matchesCommentRequiredProperty('Required',elem, propertyTuple))
->iterate (tuple; propertyNames: String = '' |
propertyNames.concat(tuple.property+';')
)
;
-- Returns true if the given property tuple applies to the given elem, false otherwise
helper def: matchesCommentRequiredProperty(
value:String, -- is either 'Required' or 'Ignore'
elem: java!BodyDeclaration,
tuple: TupleType(property:String, value:Boolean, modifier: String, annotation: String)): Boolean =
-- Check whether this rule is required
(tuple.value=value)
-- Check the given element has comments
.and(not thisModule.hasComments(elem))
-- Check correspondance with modifier vibility
.and(
if (tuple.modifier.isEmpty()) then true
else
if (tuple.modifier = elem.modifier.visibility.name) then true else false endif
endif)
-- Check correspondance with annotation
.and(
if (tuple.annotation.isEmpty()) then true
else
if (thisModule.getAnnotationTypeDeclarationsFromBodyDeclaration(elem)
->exists(annotation | annotation.name = tuple.annotation)
) then true else false endif
endif)
-- Check correspondance with prefixes
.and(
if (tuple.prefixes.isEmpty()) then true
else
if (tuple.prefixes->exists(p |
-- If elem is of type FieldDeclaration, name field is null so we have to use fragments
if (elem.oclIsTypeOf(java!FieldDeclaration))
then elem.fragments.first().name.startsWith(p)
else elem.name.startsWith(p)
endif)
) then true else false endif
endif)
;
-- Returns true if the elem has comments, false otherwise
helper def: hasComments(elem: java!BodyDeclaration): Boolean =
not elem.comments.isEmpty()
;
-- Contains the default configuration for the CommentRequired rule
-- Can add, delete or modify properties here to customize them just like in PMD
helper def: commentRequiredPropertyDefinitions() :
Map(
String, -- Key -> the name of java element data type
Set( -- Value -> set of property tuples associated to a java element data type
TupleType(
property:String, -- Name of the property
value:String, -- Possible values ['Required','Ignored']
modifier: String, -- Indicates whether the property concerns 'private', 'protected' or 'public' elements
annotation: String, -- Indicates whether the property concerns elements with annotations (e.g Override)
prefixes: Set(String))) -- Filters concerned elements by their prefixes (usefull for getting accesssors or serialVersionUID fields)
) =
Map {
-- Configure comment requirement properties for method declarations
('MethodDeclaration',
Set {
Tuple{property='methodWithOverrideCommentRequirement', value='Ignored', modifier='', annotation='Override', prefixes=Set{}},
Tuple{property='publicMethodCommentRequirement', value='Required', modifier='public', annotation='', prefixes=Set{}},
Tuple{property='protectedMethodCommentRequirement', value='Required', modifier='protected', annotation='', prefixes=Set{}},
Tuple{property='protectedMethodCommentRequirement', value='Required', modifier='none', annotation='', prefixes=Set{}}, -- protected is also defined as 'none' in the java model
Tuple{property='accessorCommentRequirement', value='Ignored', modifier='', annotation='', prefixes=Set{'get','set'}}
}
),
-- Configure comment requirement properties for field declarations
('FieldDeclaration',
Set{
Tuple{property='fieldCommentRequirement', value='Required', modifier='', annotation='', prefixes=Set{}},
Tuple{property = 'serialVersionUIDCommentRequired', value='Ignored', modifier='', annotation='', prefixes=Set{'serialVersionUID'}},
Tuple{property = 'serialPersistentFieldsCommentRequired', value='Ignored', modifier='', annotation='', prefixes=Set{'serialPersistentFields'}}
-- Not by default in PMD but just to test genericity of rule customization :
-- Tuple{property='protectedFieldCommentRequirement', value='Ignored', modifier='protected', annotation='', prefixes=Set{}},
-- Tuple{property='protectedFieldCommentRequirement', value='Ignored', modifier='none', annotation='', prefixes=Set{}}
}
),
-- Configure comment requirement properties for class declarations
('ClassDeclaration',
Set{
Tuple{property='headerCommentRequirement', value='Required', modifier='', annotation='', prefixes=Set{}}
}
),
-- Configure comment requirement properties for enums
('EnumDeclaration',
Set{
Tuple{property='enumCommentRequirement', value=true, modifier='', annotation='', prefixes=Set{}}
}
)
};
-------------------------------------------------------------------------------------------------------------------
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment