Skip to content

Commit

Permalink
Implement analyzer for salary-calculator after revert (#157)
Browse files Browse the repository at this point in the history
* Revert "Revert "Implement analyzer for salary-calculator (#155)" (#156)"

This reverts commit fee570b.

* Applying suggestion to make the code more readable on secrets and salary-calculator analyzers
  • Loading branch information
manumafe98 authored Apr 2, 2024
1 parent dd8637b commit 50d729d
Show file tree
Hide file tree
Showing 37 changed files with 751 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/main/java/analyzer/AnalyzerRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import analyzer.exercises.leap.LeapAnalyzer;
import analyzer.exercises.loglevels.LogLevelsAnalyzer;
import analyzer.exercises.needforspeed.NeedForSpeedAnalyzer;
import analyzer.exercises.salarycalculator.SalaryCalculatorAnalyzer;
import analyzer.exercises.secrets.SecretsAnalyzer;
import analyzer.exercises.twofer.TwoferAnalyzer;
import analyzer.exercises.wizardsandwarriors.WizardsAndWarriorsAnalyzer;
Expand Down Expand Up @@ -56,6 +57,7 @@ private static List<Analyzer> createAnalyzers(String slug) {
case "leap" -> analyzers.add(new LeapAnalyzer());
case "log-levels" -> analyzers.add(new LogLevelsAnalyzer());
case "need-for-speed" -> analyzers.add(new NeedForSpeedAnalyzer());
case "salary-calculator" -> analyzers.add(new SalaryCalculatorAnalyzer());
case "secrets" -> analyzers.add(new SecretsAnalyzer());
case "two-fer" -> analyzers.add(new TwoferAnalyzer());
case "wizards-and-warriors" -> analyzers.add(new WizardsAndWarriorsAnalyzer());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package analyzer.exercises.salarycalculator;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.ConditionalExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import analyzer.Analyzer;
import analyzer.OutputCollector;
import analyzer.Solution;
import analyzer.comments.ExemplarSolution;
import analyzer.comments.ReuseCode;

/**
* The {@link SalaryCalculatorAnalyzer} is the analyzer implementation for the {@code salary-calculator} practice exercise.
* It extends from the {@link VoidVisitorAdapter} and uses the visitor pattern to traverse each compilation unit.
*
* @see <a href="https://github.com/exercism/java/tree/main/exercises/concept/salary-calculator">The salary-calculator exercise on the Java track</a>
*/
public class SalaryCalculatorAnalyzer extends VoidVisitorAdapter<OutputCollector> implements Analyzer {
private static final String EXERCISE_NAME = "Salary Calculator";
private static final String SALARY_MULTIPLIER = "salaryMultiplier";
private static final String BONUS_MULTIPLIER = "bonusMultiplier";
private static final String FINAL_SALARY = "finalSalary";
private static final String BONUS_FOR_PRODUCTS_SOLD = "bonusForProductsSold";
private boolean essentialCommentAdded = false;

@Override
public void analyze(Solution solution, OutputCollector output) {
for (CompilationUnit compilationUnit : solution.getCompilationUnits()) {
compilationUnit.accept(this, output);
}

if (output.getComments().isEmpty()) {
output.addComment(new ExemplarSolution(EXERCISE_NAME));
}
}

@Override
public void visit(MethodDeclaration node, OutputCollector output) {
if (essentialCommentAdded) {
return;
}

if (isMethodThatMustContainTernaryOperators(node) && doesNotHasTernaryOperators(node)) {
output.addComment(new UseTernaryOperators(node.getNameAsString()));
essentialCommentAdded = true;
}

if (node.getNameAsString().equals(BONUS_FOR_PRODUCTS_SOLD) && doesNotCallMethod(node, BONUS_MULTIPLIER)) {
output.addComment(new ReuseCode(BONUS_FOR_PRODUCTS_SOLD, BONUS_MULTIPLIER));
}

if (node.getNameAsString().equals(FINAL_SALARY) && doesNotCallMethod(node, SALARY_MULTIPLIER)) {
output.addComment(new ReuseCode(FINAL_SALARY, SALARY_MULTIPLIER));
}

if (node.getNameAsString().equals(FINAL_SALARY) && doesNotCallMethod(node, BONUS_FOR_PRODUCTS_SOLD)) {
output.addComment(new ReuseCode(FINAL_SALARY, BONUS_FOR_PRODUCTS_SOLD));
}

super.visit(node, output);
}

private static boolean isMethodThatMustContainTernaryOperators(MethodDeclaration node) {
return node.getNameAsString().equals(SALARY_MULTIPLIER) || node.getNameAsString().equals(BONUS_MULTIPLIER) || node.getNameAsString().equals(FINAL_SALARY);
}

private static boolean doesNotHasTernaryOperators(MethodDeclaration node) {
return node.findAll(ConditionalExpr.class).isEmpty();
}

private static boolean doesNotCallMethod(MethodDeclaration node, String otherMethodName) {
return node.findAll(MethodCallExpr.class, x -> x.getNameAsString().contains(otherMethodName)).isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package analyzer.exercises.salarycalculator;

import java.util.Map;

import analyzer.Comment;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/salary-calculator/use_ternary_operators.md">Markdown Template</a>
*/
class UseTernaryOperators extends Comment {
private final String inMethod;

public UseTernaryOperators(String inMethod) {
this.inMethod = inMethod;
}

@Override
public String getKey() {
return "java.salary-calculator.use_ternary_operators";
}

@Override
public Map<String, String> getParameters() {
return Map.of(
"inMethod", this.inMethod);
}

@Override
public Type getType() {
return Type.ESSENTIAL;
}
}
15 changes: 9 additions & 6 deletions src/main/java/analyzer/exercises/secrets/SecretsAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,35 @@ public void analyze(Solution solution, OutputCollector output) {

@Override
public void visit(MethodDeclaration node, OutputCollector output) {
if (essentialCommentAdded) {
return;
}

if (!essentialCommentAdded && node.getNameAsString().equals(SHIFT_BACK) && doesNotUseOperator(node, BinaryExpr.Operator.UNSIGNED_RIGHT_SHIFT)) {
if (node.getNameAsString().equals(SHIFT_BACK) && doesNotUseOperator(node, BinaryExpr.Operator.UNSIGNED_RIGHT_SHIFT)) {
output.addComment(new UseBitwiseOperator(">>>", SHIFT_BACK));
essentialCommentAdded = true;
}

if (!essentialCommentAdded && node.getNameAsString().equals(SET_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.BINARY_OR)) {
if (node.getNameAsString().equals(SET_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.BINARY_OR)) {
output.addComment(new UseBitwiseOperator("|", SET_BITS));
essentialCommentAdded = true;
}

if (!essentialCommentAdded && node.getNameAsString().equals(FLIP_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.XOR)) {
if (node.getNameAsString().equals(FLIP_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.XOR)) {
output.addComment(new UseBitwiseOperator("^", FLIP_BITS));
essentialCommentAdded = true;
}

if (!essentialCommentAdded && node.getNameAsString().equals(CLEAR_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.BINARY_AND)) {
if (node.getNameAsString().equals(CLEAR_BITS) && doesNotUseOperator(node, BinaryExpr.Operator.BINARY_AND)) {
output.addComment(new UseBitwiseOperator("&", CLEAR_BITS));
essentialCommentAdded = true;
}

if (!essentialCommentAdded && node.getNameAsString().equals(CLEAR_BITS) && !doesNotUseOperator(node, BinaryExpr.Operator.BINARY_AND) && doesNotImplementBitwiseNot(node)) {
if (node.getNameAsString().equals(CLEAR_BITS) && !doesNotUseOperator(node, BinaryExpr.Operator.BINARY_AND) && doesNotImplementBitwiseNot(node)) {
output.addComment(new PreferBitwiseNot());
}

if (!essentialCommentAdded && hasConditional(node)) {
if (hasConditional(node)) {
output.addComment(new AvoidConditionalLogic());
}

Expand Down
21 changes: 21 additions & 0 deletions src/test/java/analyzer/AnalyzerIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,25 @@ void wizardsandwarriors(String scenario) throws IOException {

Approvals.verify(serialize(output.analysis()), Approvals.NAMES.withParameters(scenario));
}

@ParameterizedTest
@ValueSource(strings = {
"ExemplarSolution",
"NoReuseBonusForProductsSold",
"NoReuseBonusMultiplier",
"NoReuseSalaryMultiplier",
"NotReusingMethodsAtAll",
"NotUsingTernaryOperatorsAndNotReusingMethods",
"NotUsingTernaryOperatorsAtAll",
"NotUsingTernaryOperatorsOnBonusMultiplier",
"NotUsingTernaryOperatorsOnFinalSalary",
"NotUsingTernaryOperatorsOnSalaryMultiplier"
})
void salarycalculator(String scenario) throws IOException {
var path = Path.of("salary-calculator", scenario + ".java");
var solution = new SolutionFromFiles("salary-calculator", SCENARIOS.resolve(path));
var output = AnalyzerRoot.analyze(solution);

Approvals.verify(serialize(output.analysis()), Approvals.NAMES.withParameters(scenario));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"comments": [
{
"comment": "java.general.exemplar",
"params": {
"exerciseName": "Salary Calculator"
},
"type": "celebratory"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "bonusForProductsSold"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "bonusForProductsSold",
"methodToCall": "bonusMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "salaryMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "bonusForProductsSold",
"methodToCall": "bonusMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "salaryMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "bonusForProductsSold"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "bonusMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "finalSalary"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Loading

0 comments on commit 50d729d

Please sign in to comment.