-
-
Notifications
You must be signed in to change notification settings - Fork 353
/
ReAbstractRule.class.st
268 lines (190 loc) · 7.73 KB
/
ReAbstractRule.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
"
I am the root of all quality rules rules.
Each rule should provide a short name string returned from the #name method. You also have to override the #rationale method to return a detailed description about the rule. You may also put the rationale in the class comment, as by default #rationale method returns the comment of the rule's class.
The class-side methods #checksMethod, #checksClass, #checksPackage and #checksNode return true if the rule checks methods, classes or traits, packages and AST nodes respectively. Tools will pass entities of the specified type to the rule for checking.
To check the rule, while there is a default implementation which relies on #basicCheck: and creates an instance of ReTrivialCritique, it is advised to override the #check:forCritiquesDo: method.
It's a good idea to assign your rule to a specific group. For this override the #group method and return string with the name of the group. While you can use any name you want, maybe you would like to put your rule into one of the existing groups: API Change, API Hints, Architectural, Bugs, Coding Idiom Violation, Design Flaws, Optimization, Potential Bugs, Rubric, SUnit, Style, Unclassified rules.
You can also specify the severity of your rue by returning one of: #information, #warning, or #error symbols from the #severity method.
It is fairly easy to run your rule and obtain the results. Just create an instance of it an send it the #check: message with the entity you want to check. The result is a collection of critiques. For example inspecting
RBExcessiveMethodsRule new check: Object
should give you a collection with one critique (because the Object class always has many methods ;) ). Go on click on the critique item and inspect it. You will see that there is a special ""description"" tab. This is the power of critique objects, they can present themselves in a different way. Guess what: you can even visualize the critique if needed.
To have quality assistant (and maybe other tools) pick up your changes you have to reset the cache. Do this by going to System > Settings > Code Browsing > QualityAssistant > Renraku > Rule Cache
and pressing the reset button. Or simply executing ReRuleManager reset
When you load complete rules into the system, the cache will be reset automatically. But as you are creating a new rule and it is in the incomplete state you have to reset the cache once you are ready.
If you want to learn more about the features of rules or how to create your own, please read:
RenrakuRuleHelp readInHelpBrowser
"
Class {
#name : #ReAbstractRule,
#superclass : #Object,
#classInstVars : [
'enabled'
],
#category : #'Renraku-Rules'
}
{ #category : #'testing - interest' }
ReAbstractRule class >> checksClass [
"Not checking a class by default - but subclasses should return true when the receiver rule checks on class level."
^ false
]
{ #category : #'testing - interest' }
ReAbstractRule class >> checksMethod [
"Not checking a method by default - but subclasses should return true when the receiver rule checks on method level."
^ false
]
{ #category : #'testing - interest' }
ReAbstractRule class >> checksNode [
"Not checking a node by default - but subclasses should return true when the receiver rule checks on AST node level."
^ false
]
{ #category : #'testing - interest' }
ReAbstractRule class >> checksPackage [
"Not checking a package by default - but subclasses should return true when the receiver rule checks on package level."
^ false
]
{ #category : #accessing }
ReAbstractRule class >> enabled [
^ enabled ifNil: [ enabled := true ]
]
{ #category : #accessing }
ReAbstractRule class >> enabled: aBoolean [
enabled := aBoolean.
ReRuleManager reset
]
{ #category : #accessing }
ReAbstractRule class >> enabledSettingID [
^ (self name, '_enabled') asSymbol
]
{ #category : #manifest }
ReAbstractRule class >> identifierMinorVersionNumber [
"This number identifies the version of the rule definition. Each time the rule is updated and its changes invalidates previous false positives identification (and as such should be reassessed by developers) the number should be increased."
^ 1
]
{ #category : #testing }
ReAbstractRule class >> isAbstract [
^ self = ReAbstractRule
]
{ #category : #manifest }
ReAbstractRule class >> isBeginnerRule [
^ false
]
{ #category : #manifest }
ReAbstractRule class >> isDefaultRule [
^ true
]
{ #category : #testing }
ReAbstractRule class >> isUsed [
"all my sublasses are used"
^self name = 'ReAbstractRule'
ifTrue: [ super isUsed ]
ifFalse: [ true ]
]
{ #category : #testing }
ReAbstractRule class >> isVisible [
^ self methodOfInteresetSelectors anySatisfy: [ :selector |
self perform: selector ]
]
{ #category : #properties }
ReAbstractRule class >> methodOfInteresetSelectors [
^ #(checksMethod checksClass checksPackage checksNode)
]
{ #category : #manifest }
ReAbstractRule class >> uniqueIdentifierName [
"This number should be unique and should change only when the rule completely change semantics"
^ self name
]
{ #category : #manifest }
ReAbstractRule class >> uniqueIdentifierNumber [
"This number should be unique and should change only when the rule completely change semantics"
^ 0
]
{ #category : #helpers }
ReAbstractRule >> anchorFor: anEntity [
^ ReSourceAnchor entity: anEntity
]
{ #category : #running }
ReAbstractRule >> basicCheck: anEntity [
"If you end here, you should most likely implement this in a subclass"
^ self shouldBeImplemented
]
{ #category : #running }
ReAbstractRule >> check: anEntity [
| critiques |
critiques := OrderedCollection new.
self
check: anEntity
forCritiquesDo: [ :critique | critiques add: critique ].
^ critiques
]
{ #category : #running }
ReAbstractRule >> check: anEntity forCritiquesDo: aCriticBlock [
"Accepts an entity and a block which could be evaluated for each detected critique
aCriticBlock may accept one argument: the critique object"
(self basicCheck: anEntity)
ifTrue: [ aCriticBlock cull: (self critiqueFor: anEntity) ]
]
{ #category : #running }
ReAbstractRule >> check: anEntity forCritiquesDo: aCriticBlock ifNone: alternativeBlock [
| encounteredCritique |
encounteredCritique := false.
self check: anEntity forCritiquesDo: [ :crit |
encounteredCritique := true.
aCriticBlock cull: crit ].
encounteredCritique ifFalse: alternativeBlock
]
{ #category : #running }
ReAbstractRule >> check: anEntity ifNoCritiques: alternativeBlock [
| critiques |
critiques := OrderedCollection new.
self
check: anEntity
forCritiquesDo: [ :critique | critiques add: critique ]
ifNone: alternativeBlock.
^ critiques
]
{ #category : #utilities }
ReAbstractRule >> createTrivialCritiqueOn: method intervalOf: node hint: hint [
^ ReTrivialCritique
withAnchor:
(ReIntervalSourceAnchor
entity: method
interval: node sourceInterval)
by: self
hint: hint
]
{ #category : #helpers }
ReAbstractRule >> critiqueFor: anEntity [
^ ReTrivialCritique
withAnchor: (self anchorFor: anEntity)
by: self
]
{ #category : #accessing }
ReAbstractRule >> group [
^ 'Unclassified rules'
]
{ #category : #testing }
ReAbstractRule >> isComposite [
^ false
]
{ #category : #testing }
ReAbstractRule >> isRewriteRule [
^ false
]
{ #category : #accessing }
ReAbstractRule >> name [
"Answer a human readable name of the rule."
^ self subclassResponsibility
]
{ #category : #accessing }
ReAbstractRule >> rationale [
"Answer an explanation of the rule, usually in one line. Long description can be obtained using longDescription."
^ self class comment
]
{ #category : #compatibility }
ReAbstractRule >> resetResult [
]
{ #category : #accessing }
ReAbstractRule >> severity [
"Answer the severity of issues reported by this rule. This method should return one of #error, #warning, or #information."
^ #warning
]