5. Exercise 1
• Fork
&
Clone
walkmod/walkmod-sonar-plugin
• Run:
git checkout tutorial
•
Open
from
src/test/java:
– org.walkmod.sonar.tutorial.Exercise1
• Run
the
JUNIT
test
from
Eclipse
• Create
the
HelloVisitor
in
the
same
package
that
modifies
the
class
name
“Foo”
per
“Hello”
9. Syntactic rules
Only
require
a
valid
AST
Collapsible "if" statements should be merged
[sonar:CollapsibleIfStatements]
if (file != null) {
if (file.isFile() || file.isDirectory()){
/* ... */
}
}
if (file != null &&
(file.isFile() || file.isDirectory())) {
/* ... */
}
10. Other syntactic rules
• String literals should not be duplicated
• Useless parentheses around expressions should be removed
to prevent any misunderstanding
[sonar:RemoveUselessParentheses].
• Strings literals should be placed on the left side when
checking for equality [sonar:StringCheckOnLeV]
11. Semantic rules
Require
type
or
symbol
resolu-on.
• Collection#isEmpty() should be used to test for emptiness
if (myCollection.size() == 0) {
/* ... */
}
if (myCollection.isEmpty()) {
/* ... */
}
How
to
resolve
if
size() is
a
java.util.Collection#size()
?
12. Example: UseCollectionIsEmpty
…
MethodCallExpr mce = (MethodCallExpr) methodExpr;
MethodSymbolData msd = mce.getSymbolData();
if (msd != null) {
if (mce.getName().equals("size")
&& ("0".equals(((IntegerLiteralExpr) numberExpr).getValue()))) {
if(Collection.class.isAssignableFrom(
msd.getMethod().getDeclaringClass())) {
Expression newExpr = new MethodCallExpr(mce.getScope(), "isEmpty");
if (n.getOperator().equals(BinaryExpr.Operator.notEquals)) {
newExpr = new UnaryExpr(newExpr, UnaryExpr.Operator.not);
}
n.getParentNode().replaceChildNode(n, newExpr);
}
}
[sonar:UseCollec-onIsEmpty]
13. Symbol definitions and references
Field names should comply with a naming
convention
class MyClass {
private int my_field;
}
class MyClass {
private int myField;
}
All
my_field
references
need
to
be
updated!
this.my_field = my_field; this.myField = my_field;
15. Semantic API
• SymbolDataAware#getSymbolData()
• SymbolDefinition#getUsages()
• SymbolReference#getSymbolDefinition()
• ScopeAware
Interface
for
SymbolDefini-on,
SymbolReference
&
BlockStmt
– #getVariableDefinitions()
– #getTypeDefinitions()
– #getMethodDefinitions()
• Refactorizable#rename()
Interface
for
VariableDeclara-on
&
Parameter.
Applies
safe
updates
to
all
the
references
to
that
variable/parameter.
[sonar:LocalVarsShouldComplyWithNamingConvention]
• SemanticTest
16. Semantic rules testing
public class UseCollectionIsEmptyTest extends SemanticTest {
@Test
public void testEqualsToZero() throws Exception {
CompilationUnit cu = compile(
"import java.util.List; “+
” public class Foo { “+
”public boolean testIsEmpty(List list){“+
” return list.size() == 0; }}");
UseCollectionIsEmpty visitor = new UseCollectionIsEmpty();
cu.accept(visitor, null);
MethodDeclaration md = (MethodDeclaration) cu.getTypes()
.get(0).getMembers().get(0);
BlockStmt block = md.getBody();
ReturnStmt returnStmt = (ReturnStmt) block.getStmts().get(0);
Assert.assertTrue(returnStmt.getExpr() instanceof MethodCallExpr);
}
}
17. exercise 2
• Open
org.walkmod.sonar.tutorial.Exercise2
Try
to
implement
the
rule
#9
Useless imports should be removed
18. Other semantic rules
• Local variable and method parameter names should comply with a
naming convention
[sonar:LocalVarsShouldComplyWithNamingConvention]
• Useless imports should be removed
[sonar:RemoveUselessImports]
• Redundant casts should not be used
[sonar:RedundantCastsShouldNotBeUsed]
• String literals should not be duplicated
• Local variables should not shadow class fields
19. External symbol references
• PROBLEM:
Other
files
could
contain
references
to
the
desired
node
to
modify
• It
is
necessary
to
design
a
two
step
process.
– First
step:
To
compute
the
required
refactorings.
Produces
refactoring
configuraCon
– Second
step:
To
apply
the
computed
refactorings.
Executes
walkmod-‐refactoring-‐plugin
20. External refactoring API
It
is
necessary
to
create
a
new
refactoring
chain
dynamically
RefactorConfigurationController
#getMethodRefactorRules
Returns
the
map
of
current
refactoring
rules
and
creates
a
refactoring
chain
if
it
is
missing.
{Foo:bar(java.lang.String s, int c) => Foo:bar(c)}
21. Sonar Rules examples
• Unused method parameters should be removed
[sonar:RemoveUnusedMethodParameters]
• Method names should comply with a naming convention
• Class variable fields should not have public accessibility
22. General working procedure
1. Fork
walkmod/walkmod-sonar-plugin
2. Git
checkout
master
3. Create
a
new
visitor
per
rule
4. Create
a
test
5. Define
it
in
the
walkmod-sonar-plugin.xml
6. Create
pull
request
7. We
deploy
the
changes
under
a
new
version
to
the
maven
repository
23. Local integration tests
1. Go
to
the
walkmod-‐sonar-‐plugin
directory
2. Execute
mvn
install
3. Replace
jars:
1. Open
the
following
directory:
${HOME}/.ivy2/cache/org.walkmod/walkmod-‐sonar-‐plugin/jars
2. Replace
the
jar
that
has
the
same
name
than
walkmod-‐sonar-‐plugin/target/walkmod-‐sonar-‐plugin-‐${version}.jar
4. Run
walkmod
apply
-‐-‐offline