From 32de37db6d481f6ad8ce8fdc8f043609f9e86d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lars=C3=A9n?= Date: Wed, 18 Aug 2021 17:28:59 +0200 Subject: [PATCH 1/4] Annotate isSurcharged with invariants --- src/test/java/spoon/reflect/ast/AstCheckerTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/spoon/reflect/ast/AstCheckerTest.java b/src/test/java/spoon/reflect/ast/AstCheckerTest.java index 713f0504f01..6c0fa060008 100644 --- a/src/test/java/spoon/reflect/ast/AstCheckerTest.java +++ b/src/test/java/spoon/reflect/ast/AstCheckerTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import spoon.Launcher; +import spoon.reflect.code.CtStatement; import spoon.reflect.declaration.CtClass; import spoon.reflect.reference.CtExecutableReference; import spoon.support.modelobs.FineModelChangeListener; @@ -207,22 +208,31 @@ private boolean isSurcharged(CtMethod candidate) { if (block.getStatements().isEmpty()) { return false; } + // invariant 1: block is non-empty CtInvocation potentialDelegate; if (block.getLastStatement() instanceof CtReturn) { + // 1, invariant 2: last statement is a return if (!(((CtReturn) block.getLastStatement()).getReturnedExpression() instanceof CtInvocation)) { + // 1, 2, invariant 3: last statement is not a return with an invocation if (block.getStatement(0) instanceof CtInvocation) { + // 1, 2, 3, invariant 4: first statement is an invocation potentialDelegate = block.getStatement(0); } else { + // 1, 2, 3, ~4 return false; } } else { + // 1, 2, ~3 potentialDelegate = (CtInvocation) ((CtReturn) block.getLastStatement()).getReturnedExpression(); } } else if (block.getStatement(0) instanceof CtInvocation && block.getStatements().size() == 1) { + // 1, ~2, invariant 7: there's only one statement, and it's an invocation potentialDelegate = block.getStatement(0); } else { + // 1, ~2, ~7 ==> either a single statement that is neither return nor invocation, or multiple statements return false; } + CtExecutable declaration = potentialDelegate.getExecutable().getDeclaration(); if (!(declaration instanceof CtMethod)) { return false; From 3140a3772444eb860df2456ee0692ac0de00abb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lars=C3=A9n?= Date: Thu, 19 Aug 2021 10:44:04 +0200 Subject: [PATCH 2/4] Flatten isSurcharged --- .../spoon/reflect/ast/AstCheckerTest.java | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/test/java/spoon/reflect/ast/AstCheckerTest.java b/src/test/java/spoon/reflect/ast/AstCheckerTest.java index 6c0fa060008..69dc600dca1 100644 --- a/src/test/java/spoon/reflect/ast/AstCheckerTest.java +++ b/src/test/java/spoon/reflect/ast/AstCheckerTest.java @@ -204,36 +204,26 @@ private boolean isNotCandidate(CtMethod candidate) { } private boolean isSurcharged(CtMethod candidate) { - CtBlock block = candidate.getBody(); - if (block.getStatements().isEmpty()) { + CtBlock body = candidate.getBody(); + if (body.getStatements().isEmpty()) { return false; } - // invariant 1: block is non-empty - CtInvocation potentialDelegate; - if (block.getLastStatement() instanceof CtReturn) { - // 1, invariant 2: last statement is a return - if (!(((CtReturn) block.getLastStatement()).getReturnedExpression() instanceof CtInvocation)) { - // 1, 2, invariant 3: last statement is not a return with an invocation - if (block.getStatement(0) instanceof CtInvocation) { - // 1, 2, 3, invariant 4: first statement is an invocation - potentialDelegate = block.getStatement(0); - } else { - // 1, 2, 3, ~4 - return false; - } - } else { - // 1, 2, ~3 - potentialDelegate = (CtInvocation) ((CtReturn) block.getLastStatement()).getReturnedExpression(); - } - } else if (block.getStatement(0) instanceof CtInvocation && block.getStatements().size() == 1) { - // 1, ~2, invariant 7: there's only one statement, and it's an invocation - potentialDelegate = block.getStatement(0); + + CtStatement firstStatement = body.getStatement(0); + CtStatement lastStatement = body.getLastStatement(); + CtInvocation potentialDelegate; + + if (hasOnlySingleInvocation(body) || + startsWithInvocationAndEndsWithReturnWithoutInvocation(body)) { + potentialDelegate = (CtInvocation) firstStatement; + } else if (isReturnWithInvocation(lastStatement)) { + potentialDelegate = (CtInvocation) ((CtReturn) lastStatement).getReturnedExpression(); } else { - // 1, ~2, ~7 ==> either a single statement that is neither return nor invocation, or multiple statements return false; } - CtExecutable declaration = potentialDelegate.getExecutable().getDeclaration(); + + CtExecutable declaration = potentialDelegate.getExecutable().getDeclaration(); if (!(declaration instanceof CtMethod)) { return false; } @@ -241,6 +231,25 @@ private boolean isSurcharged(CtMethod candidate) { return !isToBeProcessed((CtMethod) declaration); } + private boolean startsWithInvocationAndEndsWithReturnWithoutInvocation(CtBlock block) { + return block.getStatement(0) instanceof CtInvocation + && isReturnWithoutInvocation(block.getLastStatement()); + } + + private boolean hasOnlySingleInvocation(CtBlock block) { + return block.getStatements().size() == 1 + && block.getLastStatement() instanceof CtInvocation; + } + + private boolean isReturnWithoutInvocation(CtStatement statement) { + return statement instanceof CtReturn && !isReturnWithInvocation(statement); + } + + private boolean isReturnWithInvocation(CtStatement statement) { + return statement instanceof CtReturn + && ((CtReturn) statement).getReturnedExpression() instanceof CtInvocation; + } + private boolean isDelegateMethod(CtMethod candidate) { if (candidate.getBody().getStatements().isEmpty()) { return false; From 4c311578222d27643cc3e357cf907504760fc2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lars=C3=A9n?= Date: Thu, 19 Aug 2021 11:01:48 +0200 Subject: [PATCH 3/4] Refactor isSurcharged --- .../spoon/reflect/ast/AstCheckerTest.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/test/java/spoon/reflect/ast/AstCheckerTest.java b/src/test/java/spoon/reflect/ast/AstCheckerTest.java index 69dc600dca1..ea3a97a955c 100644 --- a/src/test/java/spoon/reflect/ast/AstCheckerTest.java +++ b/src/test/java/spoon/reflect/ast/AstCheckerTest.java @@ -46,6 +46,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -204,31 +205,36 @@ private boolean isNotCandidate(CtMethod candidate) { } private boolean isSurcharged(CtMethod candidate) { + return !extractPotentialSurchargeDelegateDeclaration(candidate) + .filter(this::isToBeProcessed) + .isPresent(); + } + + private Optional> extractPotentialSurchargeDelegateDeclaration(CtMethod candidate) { + Optional> maybePotentialDelegate = extractPotentialSurchargeDelegate(candidate); + return maybePotentialDelegate + .map(CtInvocation::getExecutable) + .map(CtExecutableReference::getDeclaration) + .filter(CtMethod.class::isInstance) + .map(ref -> (CtMethod) ref); + } + + private Optional> extractPotentialSurchargeDelegate(CtMethod candidate) { CtBlock body = candidate.getBody(); if (body.getStatements().isEmpty()) { - return false; + return Optional.empty(); } CtStatement firstStatement = body.getStatement(0); CtStatement lastStatement = body.getLastStatement(); - CtInvocation potentialDelegate; - if (hasOnlySingleInvocation(body) || startsWithInvocationAndEndsWithReturnWithoutInvocation(body)) { - potentialDelegate = (CtInvocation) firstStatement; + return Optional.of((CtInvocation) firstStatement); } else if (isReturnWithInvocation(lastStatement)) { - potentialDelegate = (CtInvocation) ((CtReturn) lastStatement).getReturnedExpression(); + return Optional.of((CtInvocation) ((CtReturn) lastStatement).getReturnedExpression()); } else { - return false; - } - - - CtExecutable declaration = potentialDelegate.getExecutable().getDeclaration(); - if (!(declaration instanceof CtMethod)) { - return false; + return Optional.empty(); } - // check if the invocation has a model change listener - return !isToBeProcessed((CtMethod) declaration); } private boolean startsWithInvocationAndEndsWithReturnWithoutInvocation(CtBlock block) { From 03b91b4256d6f6436780806c9683c7a35a30f6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Lars=C3=A9n?= Date: Mon, 23 Aug 2021 13:53:51 +0200 Subject: [PATCH 4/4] Clean up --- .../spoon/reflect/ast/AstCheckerTest.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/test/java/spoon/reflect/ast/AstCheckerTest.java b/src/test/java/spoon/reflect/ast/AstCheckerTest.java index ea3a97a955c..dd5492c54a1 100644 --- a/src/test/java/spoon/reflect/ast/AstCheckerTest.java +++ b/src/test/java/spoon/reflect/ast/AstCheckerTest.java @@ -220,33 +220,24 @@ private Optional> extractPotentialSurchargeDelegateDeclaration(CtMet } private Optional> extractPotentialSurchargeDelegate(CtMethod candidate) { - CtBlock body = candidate.getBody(); + final CtBlock body = candidate.getBody(); if (body.getStatements().isEmpty()) { return Optional.empty(); } - CtStatement firstStatement = body.getStatement(0); - CtStatement lastStatement = body.getLastStatement(); - if (hasOnlySingleInvocation(body) || - startsWithInvocationAndEndsWithReturnWithoutInvocation(body)) { + final CtStatement firstStatement = body.getStatement(0); + final CtStatement lastStatement = body.getLastStatement(); + if (firstStatement instanceof CtInvocation && + (body.getStatements().size() == 1 || isReturnWithoutInvocation(lastStatement))) { return Optional.of((CtInvocation) firstStatement); } else if (isReturnWithInvocation(lastStatement)) { - return Optional.of((CtInvocation) ((CtReturn) lastStatement).getReturnedExpression()); + CtReturn lastStatementReturn = (CtReturn) lastStatement; + return Optional.of((CtInvocation) lastStatementReturn.getReturnedExpression()); } else { return Optional.empty(); } } - private boolean startsWithInvocationAndEndsWithReturnWithoutInvocation(CtBlock block) { - return block.getStatement(0) instanceof CtInvocation - && isReturnWithoutInvocation(block.getLastStatement()); - } - - private boolean hasOnlySingleInvocation(CtBlock block) { - return block.getStatements().size() == 1 - && block.getLastStatement() instanceof CtInvocation; - } - private boolean isReturnWithoutInvocation(CtStatement statement) { return statement instanceof CtReturn && !isReturnWithInvocation(statement); }