From 88dd331a38644ba721c7b383f36ee2c363d170ee Mon Sep 17 00:00:00 2001 From: Robin Maisch Date: Tue, 19 Mar 2024 17:24:53 +0100 Subject: [PATCH] Fix JavaDoc Add many comments and put a file in the 'passes' package. When JavaDoc cannot find a Java file in there, it quits. --- core/src/main/java/de/jplag/Submission.java | 8 + .../src/main/java/de/jplag/SubmissionSet.java | 4 + .../java/de/jplag/java_cpg/CpgAdapter.java | 16 ++ .../de/jplag/java_cpg/JavaCpgLanguage.java | 56 +++-- .../java_cpg/passes/JTokenizationPass.java | 76 ++++++ .../java_cpg/token/ACpgNodeListener.java | 8 +- .../jplag/java_cpg/token/CpgNodeListener.java | 13 + .../de/jplag/java_cpg/token/CpgToken.java | 9 + .../java_cpg/token/CpgTokenConsumer.java | 8 +- .../jplag/java_cpg/token/IVisitorExitor.java | 16 +- .../jplag/java_cpg/token/TokenConsumer.java | 12 +- .../transformation/GraphTransformation.java | 224 ++++++++++-------- .../TransformationException.java | 10 +- .../TransformationRepository.java | 27 ++- .../matching/CpgIsomorphismDetector.java | 9 +- .../matching/PatternRepository.java | 10 + .../transformation/matching/edges/AEdge.java | 88 +++++++ .../matching/edges/CpgEdge.java | 63 ++--- .../matching/edges/CpgMultiEdge.java | 121 ++++++---- .../matching/edges/CpgNthEdge.java | 6 +- .../matching/edges/EdgeUtil.java | 16 +- .../transformation/matching/edges/Edges.java | 22 +- .../transformation/matching/edges/IEdge.java | 42 +++- .../matching/pattern/GraphPattern.java | 4 + .../matching/pattern/GraphPatternBuilder.java | 37 ++- .../matching/pattern/GraphPatternImpl.java | 21 +- .../matching/pattern/Match.java | 66 ++++-- .../matching/pattern/MatchProperty.java | 17 +- .../matching/pattern/MultiGraphPattern.java | 5 + .../matching/pattern/NodeListPattern.java | 26 +- .../matching/pattern/PatternRegistry.java | 75 +++++- .../matching/pattern/PatternUtil.java | 198 ++++++++-------- .../matching/pattern/SimpleGraphPattern.java | 34 ++- .../pattern/WildcardGraphPattern.java | 12 +- .../operations/CreateNodeOperation.java | 4 +- .../operations/DummyNeighbor.java | 7 + .../operations/GraphOperation.java | 25 +- .../operations/GraphOperationImpl.java | 18 +- .../operations/InsertOperation.java | 20 +- .../operations/RemoveOperation.java | 43 +++- .../operations/ReplaceOperation.java | 18 +- .../operations/SetOperation.java | 22 +- .../operations/TransformationUtil.java | 82 ++++++- .../visitorStrategy/MethodOrderStrategy.java | 7 +- .../visitorStrategy/NodeOrderStrategy.java | 13 +- 45 files changed, 1170 insertions(+), 448 deletions(-) create mode 100644 languages/java-cpg/src/main/java/de/jplag/java_cpg/passes/JTokenizationPass.java create mode 100644 languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/AEdge.java diff --git a/core/src/main/java/de/jplag/Submission.java b/core/src/main/java/de/jplag/Submission.java index 0fe8db33f..a0c002926 100644 --- a/core/src/main/java/de/jplag/Submission.java +++ b/core/src/main/java/de/jplag/Submission.java @@ -65,6 +65,8 @@ public class Submission implements Comparable { private Map fileTokenCount; + private long parsingTimeInMillis; + /** * Creates a submission. * @param name Identification of the submission (directory or filename). @@ -97,6 +99,10 @@ public boolean equals(Object obj) { return otherSubmission.getName().equals(name); } + public long getParsingTime() { + return parsingTimeInMillis; + } + @Override public int hashCode() { return Objects.hash(name); @@ -252,7 +258,9 @@ private static File createErrorDirectory(String... subdirectoryNames) { } try { + long timeBeforeParsing = System.currentTimeMillis(); tokenList = language.parse(new HashSet<>(files), normalize); + parsingTimeInMillis = System.currentTimeMillis() - timeBeforeParsing; if (logger.isDebugEnabled()) { for (Token token : tokenList) { logger.debug(String.join(" | ", token.getType().toString(), Integer.toString(token.getLine()), token.getSemantics().toString())); diff --git a/core/src/main/java/de/jplag/SubmissionSet.java b/core/src/main/java/de/jplag/SubmissionSet.java index 907687974..08568fabc 100644 --- a/core/src/main/java/de/jplag/SubmissionSet.java +++ b/core/src/main/java/de/jplag/SubmissionSet.java @@ -51,6 +51,10 @@ public SubmissionSet(List submissions, Submission baseCode, JPlagOpt invalidSubmissions = filterInvalidSubmissions(); } + public long getTotalParsingTime() { + return submissions.stream().mapToLong(Submission::getParsingTime).sum(); + } + /** * @return Whether a basecode is available for this collection. */ diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/CpgAdapter.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/CpgAdapter.java index aeb596582..fb01494b8 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/CpgAdapter.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/CpgAdapter.java @@ -14,6 +14,7 @@ import de.jplag.Token; import de.jplag.java_cpg.passes.*; import de.jplag.java_cpg.transformation.GraphTransformation; +import de.jplag.java_cpg.transformation.GraphTransformation.ExecutionPhase; import kotlin.jvm.JvmClassMappingKt; import kotlin.reflect.KClass; @@ -26,6 +27,10 @@ public class CpgAdapter { private List tokenList; private boolean reorderingEnabled = true; + /** + * Constructor for CpgAdapter. + * @param transformations a list of {@link GraphTransformation}s + */ public CpgAdapter(GraphTransformation... transformations) { addTransformations(transformations); } @@ -89,6 +94,10 @@ public void addTransformations(GraphTransformation[] transformations) { Arrays.stream(transformations).forEach(this::addTransformation); } + /** + * Adds a transformation at the end of its respective ATransformationPass. + * @param transformation a {@link GraphTransformation} + */ public void addTransformation(GraphTransformation transformation) { switch (transformation.getPhase()) { case OBLIGATORY -> PrepareTransformationPass.registerTransformation(transformation); @@ -97,11 +106,18 @@ public void addTransformation(GraphTransformation transformation) { } } + /** + * Clears all non-{@link ExecutionPhase#OBLIGATORY} transformations from the pipeline. + */ public void clearTransformations() { AstTransformationPass.clearTransformations(); CpgTransformationPass.clearTransformations(); } + /** + * Sets reorderingEnabled. If true, statements may be reordered. + * @param enabled value for reorderingEnabled. + */ public void setReorderingEnabled(boolean enabled) { this.reorderingEnabled = enabled; } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/JavaCpgLanguage.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/JavaCpgLanguage.java index b675d58f7..a121597a3 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/JavaCpgLanguage.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/JavaCpgLanguage.java @@ -18,12 +18,15 @@ */ @MetaInfServices(de.jplag.Language.class) public class JavaCpgLanguage implements Language { - public static final int DEFAULT_MINIMUM_TOKEN_MATCH = 9; - public static final String[] FILE_EXTENSIONS = {".java"}; - public static final String NAME = "Java Code Property Graph module"; + private static final int DEFAULT_MINIMUM_TOKEN_MATCH = 9; + private static final String[] FILE_EXTENSIONS = {".java"}; + private static final String NAME = "Java Code Property Graph module"; private static final String IDENTIFIER = "java-cpg"; private final CpgAdapter cpgAdapter; + /** + * Creates a new {@link JavaCpgLanguage}. + */ public JavaCpgLanguage() { this.cpgAdapter = new CpgAdapter(allTransformations()); } @@ -69,6 +72,9 @@ public boolean requiresCoreNormalization() { return false; } + /** + * Resets the set of transformations to the obligatory transformations only. + */ public void resetTransformations() { this.cpgAdapter.clearTransformations(); this.cpgAdapter.addTransformations(this.obligatoryTransformations()); @@ -87,12 +93,12 @@ private GraphTransformation[] obligatoryTransformations() { * @return the array of recommended transformations */ public GraphTransformation[] standardTransformations() { - return new GraphTransformation[] {removeOptionalOfCall, // 3 - removeOptionalGetCall, // 4 - moveConstantToOnlyUsingClass, // 6 - inlineSingleUseVariable, // 8 - removeLibraryRecord, // 11 - removeEmptyRecord, // 16 + return new GraphTransformation[] {removeOptionalOfCall, // 1 + removeOptionalGetCall, // 2 + moveConstantToOnlyUsingClass, // 5 + inlineSingleUseVariable, // 7 + removeLibraryRecord, // 10 + removeEmptyRecord, // 15 }; } @@ -101,22 +107,22 @@ public GraphTransformation[] standardTransformations() { * @return the array of all transformations */ public GraphTransformation[] allTransformations() { - return new GraphTransformation[] {ifWithNegatedConditionResolution, // 1 - forStatementToWhileStatement, // 2 - removeOptionalOfCall, // 3 - removeOptionalGetCall, // 4 - removeGetterMethod, // 5 - moveConstantToOnlyUsingClass, // 6 - inlineSingleUseConstant, // 7 - inlineSingleUseVariable, // 8 - removeEmptyDeclarationStatement, // 9 - removeImplicitStandardConstructor, // 10 - removeLibraryRecord, // 11 - removeLibraryField, // 12 - removeEmptyConstructor, // 13 - removeUnsupportedConstructor, // 14 - removeUnsupportedMethod, // 15 - removeEmptyRecord, // 16 + return new GraphTransformation[] {ifWithNegatedConditionResolution, // 0 + forStatementToWhileStatement, // 1 + removeOptionalOfCall, // 2 + removeOptionalGetCall, // 3 + removeGetterMethod, // 4 + moveConstantToOnlyUsingClass, // 5 + inlineSingleUseConstant, // 6 + inlineSingleUseVariable, // 7 + removeEmptyDeclarationStatement, // 8 + removeImplicitStandardConstructor, // 9 + removeLibraryRecord, // 10 + removeLibraryField, // 11 + removeEmptyConstructor, // 12 + removeUnsupportedConstructor, // 13 + removeUnsupportedMethod, // 14 + removeEmptyRecord, // 15 }; } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/passes/JTokenizationPass.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/passes/JTokenizationPass.java new file mode 100644 index 000000000..b6be3f20e --- /dev/null +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/passes/JTokenizationPass.java @@ -0,0 +1,76 @@ +package de.jplag.java_cpg.passes; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.fraunhofer.aisec.cpg.TranslationContext; +import de.fraunhofer.aisec.cpg.TranslationResult; +import de.fraunhofer.aisec.cpg.graph.Name; +import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker; +import de.fraunhofer.aisec.cpg.passes.TranslationResultPass; +import de.jplag.Token; +import de.jplag.TokenType; +import de.jplag.java_cpg.token.CpgNodeListener; +import de.jplag.java_cpg.token.CpgToken; +import de.jplag.java_cpg.token.CpgTokenConsumer; +import de.jplag.java_cpg.visitorStrategy.NodeOrderStrategy; + +/** + * This pass tokenizes the {@link de.fraunhofer.aisec.cpg.TranslationResult}. It is a duplicate of + * de.jplag.java_cpg.passes.TokenizationPass implemented in Java as a workaround to make JavaDoc work. If the package + * 'passes' contains only Kotlin files, JavaDoc fails. + */ +public class JTokenizationPass extends TranslationResultPass { + + private static final Logger logger = LoggerFactory.getLogger(TokenizationPass.class); + private final ArrayList tokenList = new ArrayList<>(); + private final CpgTokenConsumer consumer = new ConcreteCpgTokenConsumer(); + private final NodeOrderStrategy strategy = new NodeOrderStrategy(); + Consumer> callback = null; + + /** + *

+ * Constructor for JTokenizationPass. + *

+ * @param ctx a {@link de.fraunhofer.aisec.cpg.TranslationContext} object + */ + public JTokenizationPass(@NotNull TranslationContext ctx) { + super(ctx); + } + + /** {@inheritDoc} */ + @Override + public void accept(TranslationResult translationResult) { + tokenList.clear(); + CpgNodeListener listener = new CpgNodeListener(consumer); + SubgraphWalker.IterativeGraphWalker walker = new SubgraphWalker.IterativeGraphWalker(); + walker.setStrategy(strategy::getIterator); + walker.registerOnNodeVisit(listener::visit); + walker.registerOnNodeExit(listener::exit); + walker.iterate(translationResult); + callback.accept(tokenList); + } + + /** + *

+ * cleanup. + *

+ */ + public void cleanup() { + logger.info("Found %d tokens".formatted(tokenList.size())); + } + + private class ConcreteCpgTokenConsumer extends CpgTokenConsumer { + public void addToken(TokenType type, File file, int rowBegin, int colBegin, int length, Name name) { + CpgToken token = new CpgToken(type, file, rowBegin, colBegin, length, name); + tokenList.add(token); + } + } + +} diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/ACpgNodeListener.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/ACpgNodeListener.java index ea1aaac71..d35967ed9 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/ACpgNodeListener.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/ACpgNodeListener.java @@ -6,10 +6,16 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.*; /** - * This class provides empty dummy implementations for {@link CpgNodeListener}s. + * This class provides empty dummy implementations for {@link de.jplag.java_cpg.token.CpgNodeListener}s. */ public abstract class ACpgNodeListener extends IVisitorExitor { + /** + * Creates a new {@link ACpgNodeListener}. + */ + public ACpgNodeListener() { + } + void exit(AssertStatement assertStatement) { } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgNodeListener.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgNodeListener.java index 6c20c760b..37ff2010d 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgNodeListener.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgNodeListener.java @@ -25,12 +25,21 @@ public class CpgNodeListener extends ACpgNodeListener { private final LinkedList openBlocks; private final LinkedList expectedBlocks; + /** + * Creates a new {@link CpgNodeListener}. + * @param consumer the {@link CpgTokenConsumer} that receives the tokens. + */ public CpgNodeListener(CpgTokenConsumer consumer) { this.tokenConsumer = consumer; this.expectedBlocks = new LinkedList<>(); this.openBlocks = new LinkedList<>(); } + /** + * This is used to iterate over {@link Token} list, comparing them one {@link Token} at a time. + * @param nodes an iterator for {@link Node}s + * @return an iterator for {@link Token}s + */ public static Iterator tokenIterator(Iterator nodes) { return new Iterator<>() { @@ -388,6 +397,10 @@ public void visit(MemberCallExpression memberCallExpression) { tokenConsumer.addToken(METHOD_CALL, memberCallExpression, false); } + /** + * Visits a {@link Node}. + * @param node the node + */ public void visit(Node node) { super.visit(node); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgToken.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgToken.java index 5bccfdf48..7f447c164 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgToken.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgToken.java @@ -13,6 +13,15 @@ public class CpgToken extends Token { private final Name name; + /** + * Creates a new {@link CpgToken}. + * @param tokenType the {@link de.jplag.TokenType} + * @param file the {@link java.io.File} that contains the represented piece of code + * @param startLine the starting line of the represented code + * @param startColumn the starting column of the represented code + * @param length the length of the represented code + * @param name the name of the represented CPG node + */ public CpgToken(TokenType tokenType, File file, int startLine, int startColumn, int length, Name name) { super(tokenType, file, startLine, startColumn, length); this.name = name; diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgTokenConsumer.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgTokenConsumer.java index b8d3fa133..71d5b0717 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgTokenConsumer.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/CpgTokenConsumer.java @@ -17,7 +17,7 @@ */ public abstract class CpgTokenConsumer implements TokenConsumer { - public static final Logger logger = LoggerFactory.getLogger(CpgTokenConsumer.class); + private static final Logger logger = LoggerFactory.getLogger(CpgTokenConsumer.class); /** * This is used as the Token's length if the token spans multiple lines. The value is supposed to be greater than the * length of any sensible line of code. @@ -32,6 +32,12 @@ private static int calculateLength(Region region) { return MULTILINE_TOKEN_LENGTH; } + /** + * Adds a new {@link de.jplag.Token} for the given {@link TokenType} and {@link Node}. + * @param type the {@link de.jplag.TokenType} + * @param node the represented {@link de.fraunhofer.aisec.cpg.graph.Node} + * @param isEndToken true iff the token represents the end of a block + */ public void addToken(TokenType type, Node node, boolean isEndToken) { logger.debug(type.toString() + "/" + node.toString()); PhysicalLocation location = node.getLocation(); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/IVisitorExitor.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/IVisitorExitor.java index 4890d6982..320dbaa81 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/IVisitorExitor.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/IVisitorExitor.java @@ -3,26 +3,32 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import de.fraunhofer.aisec.cpg.graph.Node; import de.fraunhofer.aisec.cpg.processing.IVisitable; import de.fraunhofer.aisec.cpg.processing.IVisitor; /** * This class adds exit methods to the {@link IVisitor} class. This implementation is supposed to be a close replication * of {@link IVisitor}. + * @param the object type to visit and exit */ public abstract class IVisitorExitor> extends IVisitor { - public static final String EXIT_METHOD_IDENTIFIER = "exit"; + private static final String EXIT_METHOD_IDENTIFIER = "exit"; - public void exit(V t) { + /** + * Calls the most specific implementation of exit for the given {@link Node}. + * @param node the node + */ + public void exit(V node) { try { - Method mostSpecificExit = this.getClass().getMethod(EXIT_METHOD_IDENTIFIER, t.getClass()); + Method mostSpecificExit = this.getClass().getMethod(EXIT_METHOD_IDENTIFIER, node.getClass()); mostSpecificExit.setAccessible(true); - mostSpecificExit.invoke(this, t); + mostSpecificExit.invoke(this, node); } catch (NoSuchMethodException e) { // This method is not implemented, that is okay } catch (InvocationTargetException | IllegalAccessException e) { } } -} \ No newline at end of file +} diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/TokenConsumer.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/TokenConsumer.java index 7e4b1f58c..6e92132f5 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/TokenConsumer.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/token/TokenConsumer.java @@ -3,14 +3,22 @@ import java.io.File; import de.fraunhofer.aisec.cpg.graph.Name; -import de.jplag.Token; import de.jplag.TokenType; /** - * This interface represents classes that can consume and save {@link Token}s. + * This interface represents classes that can consume and save {@link de.jplag.Token}s. */ public interface TokenConsumer { + /** + * Creates a new token to be consumed by this token consumer. + * @param type the token type + * @param file the file that contains the represented code + * @param startLine the line where the represented code starts + * @param startColumn the column where the represented code starts + * @param length The length of the represented code + * @param name the name of the represented {@link de.fraunhofer.aisec.cpg.graph.Node} + */ void addToken(TokenType type, File file, int startLine, int startColumn, int length, Name name); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/GraphTransformation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/GraphTransformation.java index 302e45ffe..51fa51b93 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/GraphTransformation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/GraphTransformation.java @@ -16,7 +16,6 @@ import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgNthEdge; import de.jplag.java_cpg.transformation.matching.pattern.*; -import de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern; import de.jplag.java_cpg.transformation.operations.*; /** @@ -29,19 +28,43 @@ public interface GraphTransformation { * Applies the transformation to the Graph represented by the given {@link Match} which indicates which {@link Node}s * shall be involved in the transformation. * @param match the match of this {@link GraphTransformation}'s source pattern to a concrete graph + * @param ctx a {@link TranslationContext} object */ void apply(Match match, TranslationContext ctx); - GraphPattern getSourcePattern(); + /** + * Gets the {@link ExecutionPhase} for this {@link GraphTransformation} + * @return a {@link ExecutionOrder} object + */ + ExecutionOrder getExecutionOrder(); - GraphPattern getTargetPattern(); + /** + * Gets the name for this {@link GraphTransformation}. + * @return the name + */ + String getName(); + /** + * Gets the {@link ExecutionPhase} for this {@link GraphTransformation}. + * @return the execution phase + */ ExecutionPhase getPhase(); - String getName(); + /** + * Gets the source {@link GraphPattern} for this {@link GraphTransformation}. + * @return the source pattern + */ + GraphPattern getSourcePattern(); - ExecutionOrder getExecutionOrder(); + /** + * Gets the target {@link GraphPattern} for this {@link GraphTransformation}. + * @return the target pattern + */ + GraphPattern getTargetPattern(); + /** + * Determines in which transformation pass this transformation is executed. + */ enum ExecutionPhase { /** @@ -54,14 +77,11 @@ enum ExecutionPhase { */ AST_TRANSFORM(false), /** - * Executes after the EOG is constructed, right before the TokenizationPass. - *

- * Usages: + * Executes after the EOG is constructed, right before the TokenizationPass. Usages: *

    *
  • Transformations that rely on usage, type information
  • *
  • Removing elements that shall be excluded from Tokenization
  • *
- *

*/ CPG_TRANSFORM(true); @@ -72,6 +92,10 @@ enum ExecutionPhase { } } + /** + * Determines the order in which matches of this {@link GraphTransformation} should be processed in order to ensure + * correct and efficient processing. + */ enum ExecutionOrder { ASCENDING_LOCATION, @@ -104,24 +128,13 @@ public void apply(Match match, TranslationContext ctx) { List concreteOperations = instantiate(operations, match); // create nodes of the target graph missing from the source graph - newNodes.forEach(op -> op.resolve(match, ctx)); + newNodes.forEach(op -> op.resolveAndApply(match, ctx)); logger.debug("Apply %s to node %s".formatted(name, match.get(sourcePattern.getRepresentingNode()))); // apply other operations apply(match, concreteOperations, ctx); } - private List instantiate(List operations, Match match) { - return operations.stream().map((GraphOperation op) -> { - if (op.isWildcarded()) { - return op.instantiateWildcard(match); - } else if (op.isMultiEdged()) { - return op.instantiateAny1ofNEdge(match); - } - return op; - }).toList(); - } - /** * Applies the given list of {@link GraphOperation}s to the {@link Match}, following the structure of the * {@link NodePattern}. @@ -132,7 +145,7 @@ private List instantiate(List operations, Match protected void apply(Match match, List operations, TranslationContext ctx) { for (GraphOperation op : operations) { try { - op.resolve(match, ctx); + op.resolveAndApply(match, ctx); } catch (TransformationException | RuntimeException e) { throw new RuntimeException(e); } @@ -141,13 +154,13 @@ protected void apply(Match match, List operations, TranslationCo } @Override - public GraphPattern getSourcePattern() { - return sourcePattern; + public ExecutionOrder getExecutionOrder() { + return this.executionOrder; } @Override - public GraphPattern getTargetPattern() { - return targetPattern; + public String getName() { + return name; } @Override @@ -156,13 +169,24 @@ public ExecutionPhase getPhase() { } @Override - public String getName() { - return name; + public GraphPattern getSourcePattern() { + return sourcePattern; } @Override - public ExecutionOrder getExecutionOrder() { - return this.executionOrder; + public GraphPattern getTargetPattern() { + return targetPattern; + } + + private List instantiate(List operations, Match match) { + return operations.stream().map((GraphOperation op) -> { + if (op.isWildcarded()) { + return op.instantiateWildcard(match); + } else if (op.isMultiEdged()) { + return op.instantiateAnyOfNEdge(match); + } + return op; + }).toList(); } @Override @@ -210,6 +234,10 @@ public static Builder from(MultiGraphPattern sourcePattern, MultiGraphPatt return new Builder<>(sourcePattern, targetPattern, name, phase); } + public GraphTransformation build() { + return this.calculateTransformation(); + } + private GraphTransformation calculateTransformation() { List> newNodes = this.createNewNodes(sourcePattern, targetPattern); List ops = new ArrayList<>(); @@ -218,22 +246,6 @@ private GraphTransformation calculateTransformation() { return new GraphTransformationImpl<>(sourcePattern, targetPattern, name, phase, newNodes, ops, executionOrder); } - private List> createNewNodes(GraphPattern sourcePattern, GraphPattern targetPattern) { - List newRoles = new ArrayList<>(targetPattern.getAllIds()); - newRoles.removeAll(sourcePattern.getAllIds()); - - List> newNodes = new ArrayList<>(); - for (String roleName : newRoles) { - // new node pattern needed for the transformation calculation - NodePattern newPattern = sourcePattern.addNode(roleName, targetPattern.getPattern(roleName)); - - // new nodes needed for the transformation application - CreateNodeOperation createNodeOperation = new CreateNodeOperation<>(sourcePattern, roleName, newPattern); - newNodes.add(createNodeOperation); - } - return newNodes; - } - /** * @param

(super)type of the parent node, specified by the incoming edge * @param common type of the current source and target node, defined by the incoming edge @@ -286,50 +298,30 @@ private void compar } - private void handleSimpleRelationships(NodePattern source, NodePattern target, List ops) { - List> unprocessedTargetRelated = new ArrayList<>(target.getRelatedNodes()); - for (NodePattern.RelatedNode sourceRelated : source.getRelatedNodes()) { - if (sourceRelated.edge().isAnalytic()) - continue; - - Optional maybeNextTarget = unprocessedTargetRelated.stream() - .filter(rel -> sourceRelated.edge().isEquivalentTo(rel.edge())).map(rel -> sourceRelated.getClass().cast(rel)).findFirst(); + private List> createNewNodes(GraphPattern sourcePattern, GraphPattern targetPattern) { + List newRoles = new ArrayList<>(targetPattern.getAllIds()); + newRoles.removeAll(sourcePattern.getAllIds()); - maybeNextTarget.ifPresent(unprocessedTargetRelated::remove); - recurseSimple(source, sourceRelated, maybeNextTarget.orElse(null), ops); - } + List> newNodes = new ArrayList<>(); + for (String roleName : newRoles) { + // new node pattern needed for the transformation calculation + NodePattern newPattern = sourcePattern.addNode(roleName, targetPattern.getPattern(roleName)); - for (NodePattern.RelatedNode targetRelated : unprocessedTargetRelated) { - // -> SetOperation - recurseSimple(source, targetRelated, targetRelated, ops); + // new nodes needed for the transformation application + CreateNodeOperation createNodeOperation = new CreateNodeOperation<>(sourcePattern, roleName, newPattern); + newNodes.add(createNodeOperation); } - } - - /** - * Try to iterate into the related nodes. - * @param Type of the source node, defined by the edge - * @param Type of the related node, defined by the edge - * @param parent Parent of the next source node - * @param sourceRelated Relation in the source graph that is currently recursed into. - * @param targetRelated Relation in the target graph equivalent to sourceRelated. - * @param ops List to save transformations into - */ - private void recurseSimple(NodePattern

parent, NodePattern.RelatedNode sourceRelated, - NodePattern.RelatedNode targetRelated, List ops) { - NodePattern nextSource = sourceRelated.pattern(); - - NodePattern nextTarget = Objects.isNull(targetRelated) ? nextSource : targetRelated.pattern(); - compare(nextSource, nextTarget, parent, ops, sourceRelated.edge()); + return newNodes; } private void handleMultiRelationships(NodePattern target, List ops, NodePattern newSource) { - List> allTargetRelated = target.getRelated1ToNNodes(); - for (NodePattern.Related1ToNNode sourceRelated : newSource.getRelated1ToNNodes()) { + List> allTargetRelated = target.getRelated1ToNNodes(); + for (NodePattern.RelatedOneToNNode sourceRelated : newSource.getRelated1ToNNodes()) { if (sourceRelated.edge().isAnalytic()) continue; - Optional maybeTargetRelated = allTargetRelated.stream() + Optional maybeTargetRelated = allTargetRelated.stream() .filter(rel -> sourceRelated.edge().isEquivalentTo(rel.edge())) // exactly 1 candidate -> role names may differ, possible replacement // more than 1 candidate -> role names must match @@ -342,16 +334,49 @@ private void handleMultiRelationships(NodePattern recurseMulti(newSource, sourceRelated, maybeTargetRelated.orElse(null), ops); } - for (NodePattern.Related1ToNNode targetRelated : allTargetRelated) { + for (NodePattern.RelatedOneToNNode targetRelated : allTargetRelated) { // needs to be inserted recurseMulti(newSource, targetRelated, targetRelated, ops); } } + private void handleSequenceRelationships(NodePattern source, NodePattern target, List ops) { + List> allTargetRelated = target.getRelated1ToNSequences(); + for (NodePattern.Related1ToNSequence sourceRelated : source.getRelated1ToNSequences()) { + if (sourceRelated.edge().isAnalytic()) + continue; + + Optional maybeTargetRelated = allTargetRelated.stream() + .filter(rel -> sourceRelated.edge().isEquivalentTo(rel.edge())).findFirst().map(rel -> sourceRelated.getClass().cast(rel)); + + maybeTargetRelated.ifPresent(allTargetRelated::remove); + recurseSequence(source, sourceRelated, maybeTargetRelated.orElse(null), ops); + } + } + + private void handleSimpleRelationships(NodePattern source, NodePattern target, List ops) { + List> unprocessedTargetRelated = new ArrayList<>(target.getRelatedNodes()); + for (NodePattern.RelatedNode sourceRelated : source.getRelatedNodes()) { + if (sourceRelated.edge().isAnalytic()) + continue; + + Optional maybeNextTarget = unprocessedTargetRelated.stream() + .filter(rel -> sourceRelated.edge().isEquivalentTo(rel.edge())).map(rel -> sourceRelated.getClass().cast(rel)).findFirst(); + + maybeNextTarget.ifPresent(unprocessedTargetRelated::remove); + recurseSimple(source, sourceRelated, maybeNextTarget.orElse(null), ops); + } + + for (NodePattern.RelatedNode targetRelated : unprocessedTargetRelated) { + // -> SetOperation + recurseSimple(source, targetRelated, targetRelated, ops); + } + } + private void recurseMulti(NodePattern

parent, - NodePattern.Related1ToNNode sourceRelated, NodePattern.Related1ToNNode targetRelated, List ops) { + NodePattern.RelatedOneToNNode sourceRelated, NodePattern.RelatedOneToNNode targetRelated, List ops) { NodePattern nextSource = sourceRelated.pattern(); - CpgMultiEdge.Any1ofNEdge incomingEdge = sourceRelated.edge().getAny1ofNEdgeTo(nextSource); + CpgMultiEdge.AnyOfNEdge incomingEdge = sourceRelated.edge().getAnyOfNEdgeTo(nextSource); NodePattern nextTarget; if (Objects.isNull(targetRelated)) { @@ -359,27 +384,13 @@ private void recurseMulti(NodePatt nextTarget = nextSource; } else { // R is guaranteed by the equal edge type - NodePattern.Related1ToNNode target1ofN = (NodePattern.Related1ToNNode) targetRelated; + NodePattern.RelatedOneToNNode target1ofN = (NodePattern.RelatedOneToNNode) targetRelated; nextTarget = target1ofN.pattern(); } compare(nextSource, nextTarget, parent, ops, incomingEdge); } - private void handleSequenceRelationships(NodePattern source, NodePattern target, List ops) { - List> allTargetRelated = target.getRelated1ToNSequences(); - for (NodePattern.Related1ToNSequence sourceRelated : source.getRelated1ToNSequences()) { - if (sourceRelated.edge().isAnalytic()) - continue; - - Optional maybeTargetRelated = allTargetRelated.stream() - .filter(rel -> sourceRelated.edge().isEquivalentTo(rel.edge())).findFirst().map(rel -> sourceRelated.getClass().cast(rel)); - - maybeTargetRelated.ifPresent(allTargetRelated::remove); - recurseSequence(source, sourceRelated, maybeTargetRelated.orElse(null), ops); - } - } - private void recurseSequence(NodePattern

parent, NodePattern.Related1ToNSequence sourceRelated, NodePattern.Related1ToNSequence targetRelated, List ops) { @@ -395,8 +406,21 @@ private void recurseSequence(NodeP } } - public GraphTransformation build() { - return this.calculateTransformation(); + /** + * Try to iterate into the related nodes. + * @param Type of the source node, defined by the edge + * @param Type of the related node, defined by the edge + * @param parent Parent of the next source node + * @param sourceRelated Relation in the source graph that is currently recursed into. + * @param targetRelated Relation in the target graph equivalent to sourceRelated. + * @param ops List to save transformations into + */ + private void recurseSimple(NodePattern

parent, NodePattern.RelatedNode sourceRelated, + NodePattern.RelatedNode targetRelated, List ops) { + NodePattern nextSource = sourceRelated.pattern(); + + NodePattern nextTarget = Objects.isNull(targetRelated) ? nextSource : targetRelated.pattern(); + compare(nextSource, nextTarget, parent, ops, sourceRelated.edge()); } public GraphTransformation.Builder setExecutionOrder(ExecutionOrder executionOrder) { diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationException.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationException.java index cc6003fcb..2f5be4743 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationException.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationException.java @@ -1,9 +1,17 @@ package de.jplag.java_cpg.transformation; /** - * An {@link Exception} respective to the Transformation process. + * An {@link java.lang.Exception} respective to the Transformation process. + * @author robin + * @version $Id: $Id */ public class TransformationException extends Exception { + /** + *

+ * Constructor for TransformationException. + *

+ * @param msg a {@link java.lang.String} object + */ public TransformationException(String msg) { super(msg); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationRepository.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationRepository.java index 9448b046e..ce59504b6 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationRepository.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/TransformationRepository.java @@ -19,37 +19,62 @@ import de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern; /** - * Contains factory methods to create different {@link GraphTransformation}s. + * Contains factory methods to create different {@link de.jplag.java_cpg.transformation.GraphTransformation}s. + * @author robin + * @version $Id: $Id */ public class TransformationRepository { /* * These constants are supposed to avoid uselessly building the same graph transformations multiple times. * Alternatively, all factory methods could be public and use private fields to create a kind-of singleton pattern. */ + /** Constant ifWithNegatedConditionResolution */ public static final GraphTransformation ifWithNegatedConditionResolution = ifWithNegatedConditionResolution(); + /** Constant forStatementToWhileStatement */ public static final GraphTransformation forStatementToWhileStatement = forStatementToWhileStatement(); + /** Constant removeGetterMethod */ public static final GraphTransformation removeGetterMethod = removeGetterMethod(); + /** Constant removeUnusedVariableDeclaration */ public static final GraphTransformation removeUnusedVariableDeclaration = removeUnusedVariableDeclaration(); + /** Constant removeUnusedVariableDeclarationStatement */ public static final GraphTransformation removeUnusedVariableDeclarationStatement = removeUnusedVariableDeclarationStatement(); + /** Constant removeEmptyDeclarationStatement */ public static final GraphTransformation removeEmptyDeclarationStatement = removeEmptyDeclarationStatement(); + /** Constant removeLibraryRecord */ public static final GraphTransformation removeLibraryRecord = removeLibraryRecord(); + /** Constant removeLibraryField */ public static final GraphTransformation removeLibraryField = removeLibraryField(); + /** Constant moveConstantToOnlyUsingClass */ public static final GraphTransformation moveConstantToOnlyUsingClass = moveConstantToOnlyUsingClass(); + /** Constant inlineSingleUseVariable */ public static final GraphTransformation inlineSingleUseVariable = inlineSingleUseVariable(); + /** Constant inlineSingleUseConstant */ public static final GraphTransformation inlineSingleUseConstant = inlineSingleUseConstant(); + /** Constant removeEmptyConstructor */ public static final GraphTransformation removeEmptyConstructor = removeEmptyConstructor(); + /** Constant removeEmptyRecord */ public static final GraphTransformation removeEmptyRecord = removeEmptyRecord(); + /** Constant removeImplicitStandardConstructor */ public static final GraphTransformation removeImplicitStandardConstructor = removeImplicitStandardConstructor(); + /** Constant removeOptionalOfCall */ public static final GraphTransformation removeOptionalOfCall = removeOptionalOfCall(); + /** Constant removeOptionalGetCall */ public static final GraphTransformation removeOptionalGetCall = removeOptionalGetCall(); + /** Constant removeUnsupportedConstructor */ public static final GraphTransformation removeUnsupportedConstructor = removeUnsupportedConstructor(); + /** Constant removeUnsupportedMethod */ public static final GraphTransformation removeUnsupportedMethod = removeUnsupportedMethod(); + /** Constant wrapElseStatement */ public static final GraphTransformation wrapElseStatement = wrapElseStatement(); + /** Constant wrapForStatement */ public static final GraphTransformation wrapForStatement = wrapForStatement(); + /** Constant wrapThenStatement */ public static final GraphTransformation wrapThenStatement = wrapThenStatement(); + /** Constant wrapWhileStatement */ public static final GraphTransformation wrapWhileStatement = wrapWhileStatement(); + /** Constant wrapDoStatement */ public static final GraphTransformation wrapDoStatement = wrapDoStatement(); private TransformationRepository() { diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/CpgIsomorphismDetector.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/CpgIsomorphismDetector.java index ce3085bfd..b0a2e400c 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/CpgIsomorphismDetector.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/CpgIsomorphismDetector.java @@ -17,10 +17,16 @@ */ public class CpgIsomorphismDetector { - public static final Logger logger = LoggerFactory.getLogger(CpgIsomorphismDetector.class); + private static final Logger logger = LoggerFactory.getLogger(CpgIsomorphismDetector.class); private TreeMap, List> nodeMap; private ClassComparator classComparator; + /** + * Creates a new {@link CpgIsomorphismDetector}. + */ + public CpgIsomorphismDetector() { + } + /** * Sets the current graph to find pattern matches in. * @param root The root {@link Node} of the graph. @@ -87,6 +93,7 @@ public List getNodesOfType(Class superClass) { * Verifies that the given match of the source {@link GraphPattern} is still valid. After a transformation involving the * match's {@link Node}s, a match may be invalidated. * @param match the match + * @param sourcePattern the source pattern * @return true iff the match is still valid */ public boolean validateMatch(Match match, GraphPattern sourcePattern) { diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/PatternRepository.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/PatternRepository.java index a16a723fd..d88534e60 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/PatternRepository.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/PatternRepository.java @@ -20,12 +20,18 @@ /** * This class is used to collect sub-patterns that may appear repetitively, or used in tests. + * @author robin + * @version $Id: $Id */ public final class PatternRepository { private PatternRepository() { /* should not be instantiated */} + /** + * Creates a {@link GraphPatternBuilder} for an {@link IfStatement} with an else statement. + * @return the graph pattern builder + */ public static GraphPatternBuilder ifElseWithNegatedCondition() { return new GraphPatternBuilder() { @@ -41,6 +47,10 @@ public GraphPattern build() { }; } + /** + * Creates a {@link GraphPatternBuilder} for a setter method + * @return a {@link de.jplag.java_cpg.transformation.matching.pattern.GraphPatternBuilder} object + */ public static GraphPatternBuilder setterMethod() { return new GraphPatternBuilder() { diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/AEdge.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/AEdge.java new file mode 100644 index 000000000..c648efb7e --- /dev/null +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/AEdge.java @@ -0,0 +1,88 @@ +package de.jplag.java_cpg.transformation.matching.edges; + +import static de.jplag.java_cpg.transformation.matching.edges.IEdge.EdgeCategory.*; + +import de.fraunhofer.aisec.cpg.graph.Node; + +/** + * This abstract class contains the method implementations common to all {@link IEdge}s. + * @param the source node type + * @param the target node type + */ +public abstract class AEdge implements IEdge { + /** + * The {@link EdgeCategory} of the edge. + */ + protected final EdgeCategory category; + private Class sourceClass; + private Class targetClass; + + /** + * Creates a new AEdge of the given category + * @param category the category + */ + public AEdge(EdgeCategory category) { + this.category = category; + } + + /** + * Gets the {@link EdgeCategory} of this edge. + * @return the edge category + */ + public EdgeCategory getCategory() { + return category; + } + + /** + * Gets the source node class of this edge. + * @return the source node class + */ + public Class getSourceClass() { + return this.sourceClass; + } + + /** + * Gets the target node class of this edge. + * @return the target node class + */ + public Class getTargetClass() { + return targetClass; + } + + /** + * @return true iff this edge is {@link EdgeCategory#ANALYTIC}. + */ + public boolean isAnalytic() { + return category == ANALYTIC; + } + + /** + * @return true iff this edge is {@link EdgeCategory#AST}. + */ + public boolean isAst() { + return category == AST; + } + + /** + * @return true iff this edge is {@link EdgeCategory#REFERENCE}. + */ + public boolean isReference() { + return category == REFERENCE; + } + + public abstract boolean isEquivalentTo(IEdge other); + + /** + * {@inheritDoc} + */ + public void setSourceClass(Class sourceClass) { + this.sourceClass = sourceClass; + } + + /** + * {@inheritDoc} + */ + public void setTargetClass(Class targetClass) { + this.targetClass = targetClass; + } +} diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgEdge.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgEdge.java index 082778a3a..cca333d65 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgEdge.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgEdge.java @@ -14,12 +14,9 @@ * @param The type of the source node * @param The type of the target node */ -public class CpgEdge implements IEdge { +public class CpgEdge extends AEdge { private final Function getter; private final BiConsumer setter; - private final EdgeCategory category; - private Class fromClass; - private Class toClass; /** * Creates a new {@link CpgEdge} with a getter and setter for the target node. @@ -28,17 +25,30 @@ public class CpgEdge implements IEdge { * @param category the edge category */ public CpgEdge(Function getter, BiConsumer setter, EdgeCategory category) { + super(category); this.getter = getter; this.setter = setter; - this.category = category; } + /** + * Creates a new {@link CpgEdge} with a getter and setter for the target node. + * @param getter the getter + * @param setter the setter + */ public CpgEdge(Function getter, BiConsumer setter) { this(getter, setter, AST); } - public static CpgEdge listValued(Function> getRhs, BiConsumer> setRhs) { - return new CpgEdge<>(node -> getRhs.apply(node).get(0), (node, value) -> setRhs.accept(node, List.of(value))); + /** + * Creates a new list-valued {@link CpgEdge} with a getter and setter for the target node list. + * @param getter the getter + * @param setter the setter + * @param The type of the source node + * @param The type of the target node + * @return a {@link CpgEdge} object + */ + public static CpgEdge listValued(Function> getter, BiConsumer> setter) { + return new CpgEdge<>(node -> getter.apply(node).get(0), (node, value) -> setter.accept(node, List.of(value))); } /** @@ -50,28 +60,18 @@ public T getRelated(S from) { return getter.apply(from); } - @Override - public void setFromClass(Class sClass) { - this.fromClass = sClass; - } - - @Override - public void setToClass(Class tClass) { - this.toClass = tClass; - } - - public Class getFromClass() { - return fromClass; - } - - public Class getToClass() { - return toClass; - } - + /** + * Gets the getter function of this {@link CpgEdge}, used to get the targets from a given source. + * @return the getter + */ public Function getter() { return getter; } + /** + * Gets the setter function of this {@link CpgEdge}, used to set the targets for a given source. + * @return the setter + */ public BiConsumer setter() { return setter; } @@ -86,17 +86,4 @@ public boolean isEquivalentTo(IEdge other) { return Objects.equals(this, other); } - @Override - public boolean isAst() { - return category == AST; - } - - @Override - public boolean isAnalytic() { - return category == ANALYTIC; - } - - public boolean isReference() { - return category == REFERENCE; - } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgMultiEdge.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgMultiEdge.java index 0788586e8..144b9d9ea 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgMultiEdge.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgMultiEdge.java @@ -1,6 +1,6 @@ package de.jplag.java_cpg.transformation.matching.edges; -import static de.jplag.java_cpg.transformation.matching.edges.IEdge.EdgeCategory.ANALYTIC; +import static de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge.ValueType.NODE_VALUED; import static de.jplag.java_cpg.transformation.matching.edges.IEdge.EdgeCategory.AST; import java.util.HashMap; @@ -19,33 +19,28 @@ * @param The type of the source node * @param The type of the target node */ -public final class CpgMultiEdge implements IEdge { +public final class CpgMultiEdge extends AEdge { private final Function> getter; private final Function>> getEdges; - private final EdgeCategory category; private final TriConsumer setter; - private final boolean edgeValued; - private Class fromClass; - private Class toClass; - private final Map, Any1ofNEdge> any1ofNEdges; + private final Map, AnyOfNEdge> any1ofNEdges; + private final ValueType valueType; /** * Creates a new CpgMultiEdge. * @param getter a function to get all the target nodes * @param setter a function to set the nth target node - * @param edgeValued if true, then this relation is represented by a {@link List} of {@link PropertyEdge}s. Otherwise, - * it returns a list of {@link Node}s. + * @param valueType describes the type of representation of this edge in the CPG. * @param getEdges if edgeValued, then this should be a function to get all the target edges, null otherwise. * @param category category of the edge */ - public CpgMultiEdge(Function> getter, TriConsumer setter, boolean edgeValued, + public CpgMultiEdge(Function> getter, TriConsumer setter, ValueType valueType, Function>> getEdges, EdgeCategory category) { + super(category); this.getter = getter; this.setter = setter; - // TODO: Model edgeValued as enum {NODE, EDGE} instead? - this.edgeValued = edgeValued; + this.valueType = valueType; this.getEdges = getEdges; - this.category = category; this.any1ofNEdges = new HashMap<>(); } @@ -61,24 +56,40 @@ public static CpgMultiEdge edgeValued(Fun return edgeValued(getter, AST); } + /** + * A shorthand to create an edge-valued {@link CpgMultiEdge}. + * @param getter a function to get all the edges + * @param category the category of the edge + * @param The type of the source node + * @param The type of the target node + * @return the new {@link CpgMultiEdge} + */ public static CpgMultiEdge edgeValued(Function>> getter, EdgeCategory category) { Function> getNodes = (S node) -> getter.apply(node).stream().map(PropertyEdge::getEnd).toList(); TriConsumer setOne = (S node, Integer n, T value) -> getter.apply(node).get(n).setEnd(value); - return new CpgMultiEdge<>(getNodes, setOne, true, getter, category); + return new CpgMultiEdge<>(getNodes, setOne, ValueType.EDGE_VALUED, getter, category); } /** * A shorthand to create a node-valued {@link CpgMultiEdge}. * @param getter a function to get all the nodes + * @param category the edge category * @param The type of the source node * @param The type of the target node * @return the new {@link CpgMultiEdge} */ public static CpgMultiEdge nodeValued(Function> getter, EdgeCategory category) { TriConsumer setOne = (S node, Integer n, T value) -> getter.apply(node).set(n, value); - return new CpgMultiEdge<>(getter, setOne, false, null, category); + return new CpgMultiEdge<>(getter, setOne, NODE_VALUED, null, category); } + /** + * A shorthand to create a node-valued AST {@link CpgMultiEdge}. + * @param getter a function to get all the nodes + * @param The type of the source node + * @param The type of the target node + * @return the new {@link CpgMultiEdge} + */ public static CpgMultiEdge nodeValued(Function> getter) { return nodeValued(getter, AST); } @@ -92,32 +103,29 @@ public List getAllTargets(S s) { return getter.apply(s); } - public Class getFromClass() { - return this.fromClass; - } - - public void setFromClass(Class sClass) { - this.fromClass = sClass; - } - - public Class getToClass() { - return toClass; - } - - public void setToClass(Class tClass) { - this.toClass = tClass; - } - + /** + * Get the getter function of this multi edge. + * @return the getter + */ public Function> getter() { return getter; } + /** + * Gets the setter function of this multi edge. + * @return a {@link TriConsumer} object + */ public TriConsumer setter() { return setter; } - public CpgMultiEdge.Any1ofNEdge getAny1ofNEdgeTo(NodePattern pattern) { - return (CpgMultiEdge.Any1ofNEdge) this.any1ofNEdges.computeIfAbsent(pattern, p -> new Any1ofNEdge()); + /** + * Gets a {@link AnyOfNEdge} from this {@link CpgMultiEdge} directed at the given {@link NodePattern}. + * @param pattern the pattern + * @return the 'any of n' edge + */ + public CpgMultiEdge.AnyOfNEdge getAnyOfNEdgeTo(NodePattern pattern) { + return this.any1ofNEdges.computeIfAbsent(pattern, p -> new AnyOfNEdge()); } /** @@ -125,9 +133,10 @@ public CpgMultiEdge.Any1ofNEdge getAny1of * @return true if this edge is edge-valued, false if this edge is node-valued. */ public boolean isEdgeValued() { - return edgeValued; + return this.valueType == ValueType.EDGE_VALUED; } + /** {@inheritDoc} */ @Override public boolean isEquivalentTo(IEdge other) { return Objects.equals(this, other); @@ -142,31 +151,43 @@ public List> getAllEdges(S s) { return getEdges.apply(s); } - public boolean isAst() { - return category == AST; - } - - @Override - public boolean isAnalytic() { - return category == ANALYTIC; - } - - public EdgeCategory getCategory() { - return category; - } - /** - * A {@link Any1ofNEdge} serves as a placeholder for a {@link CpgNthEdge} during transformation calculation as long as + * A {@link AnyOfNEdge} serves as a placeholder for a {@link CpgNthEdge} during transformation calculation as long as * the index is not known. */ - public class Any1ofNEdge extends CpgNthEdge { + public class AnyOfNEdge extends CpgNthEdge { - public Any1ofNEdge() { + /** + * Creates a new {@link AnyOfNEdge} for the corresponding {@link CpgMultiEdge}. + */ + public AnyOfNEdge() { super(CpgMultiEdge.this, -1); } + /** + * Gets the corresponding {@link CpgMultiEdge}. + * @return the multi edge + */ public CpgMultiEdge getMultiEdge() { return CpgMultiEdge.this; } } + + /** + * Describes the type of connection between nodes via an edge. + */ + public enum ValueType { + /** + * An edge where the targets can be accessed directly as nodes. + */ + NODE_VALUED, + /** + * An edge where the target can be accessed via {@link PropertyEdge}s. + */ + EDGE_VALUED, + /** + * An edge where the target is a List of nodes. + */ + LIST_VALUED + } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgNthEdge.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgNthEdge.java index 7a6ba339b..02a0cc7ba 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgNthEdge.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/CpgNthEdge.java @@ -5,6 +5,8 @@ /** * A {@link CpgNthEdge} represents an individual {@link de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge} out of a * {@link CpgMultiEdge}. + * @param source node type + * @param target node type */ public class CpgNthEdge extends CpgEdge { private final CpgMultiEdge multiEdge; @@ -19,8 +21,8 @@ public CpgNthEdge(CpgMultiEdge edge, int index) { super(t -> edge.getAllTargets(t).get(index), (t, r) -> edge.setter().accept(t, index, r), edge.getCategory()); this.multiEdge = edge; this.index = index; - this.setFromClass(edge.getFromClass()); - this.setToClass(edge.getToClass()); + this.setSourceClass(edge.getSourceClass()); + this.setTargetClass(edge.getTargetClass()); } @Override diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/EdgeUtil.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/EdgeUtil.java index ddd572498..070e02001 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/EdgeUtil.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/EdgeUtil.java @@ -1,5 +1,7 @@ package de.jplag.java_cpg.transformation.matching.edges; +import java.util.Objects; + import org.jetbrains.annotations.NotNull; import de.fraunhofer.aisec.cpg.graph.Node; @@ -14,13 +16,21 @@ public final class EdgeUtil { private EdgeUtil() { } - public static RecordDeclaration getRecord(N node) { + /** + * Gets the {@link RecordDeclaration} that a {@link Node} is located in. + * @param node a node + * @return the record declaration + */ + public static RecordDeclaration getRecord(Node node) { Scope scope = node.getScope(); - while (!(scope.getAstNode() instanceof RecordDeclaration record)) { + while (!Objects.isNull(scope)) { + if (scope.getAstNode() instanceof RecordDeclaration record) { + return record; + } scope = scope.getParent(); } - return record; + return null; } @NotNull diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/Edges.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/Edges.java index 87d753dad..e149408a2 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/Edges.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/Edges.java @@ -40,7 +40,7 @@ public class Edges { public static CpgEdge ASSIGN_EXPRESSION__RHS = CpgEdge.listValued(AssignExpression::getRhs, AssignExpression::setRhs); public static CpgEdge BINARY_OPERATOR__LHS = new CpgEdge<>(BinaryOperator::getLhs, BinaryOperator::setLhs); - public static CpgPropertyEdge BINARY_OPERATOR__OPERATOR_CODE = new CpgPropertyEdge<>(BinaryOperator::getOperatorCode, + public static CpgAttributeEdge BINARY_OPERATOR__OPERATOR_CODE = new CpgAttributeEdge<>(BinaryOperator::getOperatorCode, BinaryOperator::setOperatorCode); public static CpgEdge BINARY_OPERATOR__RHS = new CpgEdge<>(BinaryOperator::getRhs, BinaryOperator::setRhs); public static CpgMultiEdge BLOCK__DECLARATIONS = CpgMultiEdge.nodeValued(Block::getDeclarations, REFERENCE); @@ -53,8 +53,8 @@ public class Edges { .nodeValued(Component::getTranslationUnits); public static CpgMultiEdge DECLARATION_STATEMENT__DECLARATIONS = CpgMultiEdge .edgeValued(DeclarationStatement::getDeclarationEdges); - public static CpgPropertyEdge> FIELD_DECLARATION__MODIFIERS = new CpgPropertyEdge<>(FieldDeclaration::getModifiers, - FieldDeclaration::setModifiers); + public static CpgAttributeEdge> FIELD_DECLARATION__MODIFIERS = new CpgAttributeEdge<>( + FieldDeclaration::getModifiers, FieldDeclaration::setModifiers); public static CpgEdge FOR_STATEMENT__CONDITION = new CpgEdge<>(ForStatement::getCondition, ForStatement::setCondition); public static CpgEdge FOR_STATEMENT__INITIALIZER_STATEMENT = new CpgEdge<>(ForStatement::getInitializerStatement, ForStatement::setInitializerStatement); @@ -83,9 +83,9 @@ public class Edges { MethodDeclaration::getRecordDeclaration, MethodDeclaration::setRecordDeclaration, REFERENCE); public static CpgMultiEdge NAMESPACE_DECLARATION__DECLARATIONS = CpgMultiEdge .nodeValued(NamespaceDeclaration::getDeclarations); - public static CpgPropertyEdge NODE__LOCATION = new CpgPropertyEdge<>(Node::getLocation, Node::setLocation); - public static CpgPropertyEdge NODE__NAME = new CpgPropertyEdge<>(Node::getName, Node::setName); - public static CpgPropertyEdge NODE__LOCAL_NAME = new CpgPropertyEdge<>(EdgeUtil::getLocalName, null); + public static CpgAttributeEdge NODE__LOCATION = new CpgAttributeEdge<>(Node::getLocation, Node::setLocation); + public static CpgAttributeEdge NODE__NAME = new CpgAttributeEdge<>(Node::getName, Node::setName); + public static CpgAttributeEdge NODE__LOCAL_NAME = new CpgAttributeEdge<>(EdgeUtil::getLocalName, null); public static CpgEdge OBJECT_TYPE__RECORD_DECLARATION = new CpgEdge<>(ObjectType::getRecordDeclaration, ObjectType::setRecordDeclaration, REFERENCE); @@ -105,9 +105,9 @@ public class Edges { SubscriptExpression::getArrayExpression, SubscriptExpression::setArrayExpression); public static CpgMultiEdge TRANSLATION_UNIT__DECLARATIONS = CpgMultiEdge .edgeValued(TranslationUnitDeclaration::getDeclarationEdges); - public static CpgPropertyEdge TYPE__TYPE_NAME = new CpgPropertyEdge<>(Type::getTypeName, null); + public static CpgAttributeEdge TYPE__TYPE_NAME = new CpgAttributeEdge<>(Type::getTypeName, null); public static CpgEdge UNARY_OPERATOR__INPUT = new CpgEdge<>(UnaryOperator::getInput, UnaryOperator::setInput); - public static CpgPropertyEdge UNARY_OPERATOR__OPERATOR_CODE = new CpgPropertyEdge<>(UnaryOperator::getOperatorCode, + public static CpgAttributeEdge UNARY_OPERATOR__OPERATOR_CODE = new CpgAttributeEdge<>(UnaryOperator::getOperatorCode, UnaryOperator::setOperatorCode); public static CpgMultiEdge VALUE_DECLARATION__USAGES = CpgMultiEdge.edgeValued(ValueDeclaration::getUsageEdges, REFERENCE); @@ -176,8 +176,8 @@ private Edges() { * @param type of the edge target */ private static void register(IEdge edge, Class sClass, Class tClass) { - edge.setFromClass(sClass); - edge.setToClass(tClass); + edge.setSourceClass(sClass); + edge.setTargetClass(tClass); fromType.computeIfAbsent(sClass, c -> new ArrayList<>()).add(edge); toType.computeIfAbsent(tClass, c -> new ArrayList<>()).add(edge); } @@ -185,8 +185,8 @@ private static void register(IEdge edge, /** * Gets the list of edges with the given node class as target. * @param tClass the target node class - * @return the list of edges * @param the target node type + * @return the list of edges */ public static List> getEdgesToType(Class tClass) { List> result = new ArrayList<>(); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/IEdge.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/IEdge.java index 3d9c901e7..b3c7b690b 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/IEdge.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/edges/IEdge.java @@ -6,33 +6,34 @@ /** * This serves as an interface to wrap any kind of {@link PropertyEdge}. - * @param - * @param + * @param the source node type + * @param the target node type */ public interface IEdge { + /** * Sets the class object representing the source {@link Node} type. - * @param sClass the source {@link Node} class + * @param sourceClass the source {@link Node} class */ - void setFromClass(Class sClass); + void setSourceClass(Class sourceClass); /** * Sets the class object representing the target {@link Node} type. - * @param tClass the target {@link Node} class + * @param targetClass the target {@link Node} class */ - void setToClass(Class tClass); + void setTargetClass(Class targetClass); /** * Gets the class object representing the source {@link Node} type. * @return the source {@link Node} class */ - Class getFromClass(); + Class getSourceClass(); /** * Gets the class object representing the target {@link Node} type. * @return the target {@link Node} class */ - Class getToClass(); + Class getTargetClass(); /** * If true, this edge should be treated as equivalent to this one in the context of stepping through the source and @@ -42,13 +43,38 @@ public interface IEdge { */ boolean isEquivalentTo(IEdge other); + /** + * If true, this is an {@link EdgeCategory#AST} edge. + * @return true iff this is an AST edge + */ boolean isAst(); + /** + * If true, this is an {@link EdgeCategory#ANALYTIC} edge. + * @return true iff this is an analytic edge + */ boolean isAnalytic(); + /** + * If true, this is an {@link EdgeCategory#REFERENCE} edge. + * @return true iff this is a reference edge + */ + boolean isReference(); + enum EdgeCategory { + /** + * An edge that represents the inherent structure of the code. + */ AST, + + /** + * An edge that represents that nodes are connected by reference (e.g. method call -> method definition). + */ REFERENCE, + + /** + * An edge that represents a connection that is the result of a calculation. These edges can never be set. + */ ANALYTIC } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPattern.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPattern.java index 94e1a98eb..fa7752381 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPattern.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPattern.java @@ -30,6 +30,10 @@ public interface GraphPattern { /** * Adds a newly created {@link NodePattern} to this pattern. This occurs when a {@link GraphTransformation} includes the * generation of new {@link Node}s. + * @param roleName a {@link String} object + * @param newNode a {@link NodePattern} object + * @param a T class + * @return a {@link NodePattern} object */ NodePattern addNode(String roleName, NodePattern newNode); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternBuilder.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternBuilder.java index 403d70a0e..955a1f762 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternBuilder.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternBuilder.java @@ -6,9 +6,10 @@ import org.jetbrains.annotations.NotNull; import de.fraunhofer.aisec.cpg.graph.Node; +import de.jplag.java_cpg.transformation.GraphTransformation; +import de.jplag.java_cpg.transformation.matching.edges.CpgAttributeEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge; -import de.jplag.java_cpg.transformation.matching.edges.CpgPropertyEdge; import de.jplag.java_cpg.transformation.matching.pattern.NodePattern.ForAllRelatedNode; /** @@ -54,7 +55,7 @@ private static NodePattern createNodePattern(Class tClass * @param

the attribute type * @return the {@link PatternModification} */ - public static PatternModification equalAttributes(CpgPropertyEdge propertyEdge, String otherId) { + public static PatternModification equalAttributes(CpgAttributeEdge propertyEdge, String otherId) { return new AddEqualAttributes<>(propertyEdge, otherId); } @@ -70,6 +71,13 @@ public static PatternModification assignedValueStableBetween return new AddAssignedValueStableBetween<>(startId, endId); } + /** + * Creates a {@link PatternModification} that adds a {@link Predicate} property to a {@link NodePattern} that specifies + * that matching {@link Node}s not be equal to the {@link Node} given by the identifier. + * @param otherId the identifier of the other {@link Node} + * @param the {@link Node} type of the target node + * @return the pattern modification + */ public static PatternModification notEqualTo(String otherId) { return new AddNotEqualTo<>(otherId); } @@ -103,8 +111,8 @@ public final SimpleGraphPattern create(Class tClass, Stri } /** - * Creates an empty {@link WildcardGraphPattern}. It can be used as a target pattern for a - * {@link de.jplag.java_cpg.transformation.GraphTransformation} where a {@link Node} shall be removed. + * Creates an empty {@link WildcardGraphPattern}. It can be used as a target pattern for a {@link GraphTransformation} + * where a {@link Node} shall be removed. * @return the wildcard graph pattern */ protected SimpleGraphPattern emptyWildcardParent() { @@ -117,10 +125,10 @@ protected SimpleGraphPattern emptyWildcardParent() { * @param cClass the concrete class object of the for-all related nodes * @param id the identifier for the related nodes * @param modifications the modifications for the created node pattern - * @return the pattern modification * @param the type of source node * @param the type of related node, defined by the edge * @param the concrete type of related node + * @return the pattern modification */ @SafeVarargs public final PatternModification forAllRelated(CpgMultiEdge multiEdge, Class cClass, @@ -142,9 +150,9 @@ public final MultiGraphPattern multiRoot(SimpleGraphPattern... subgraphs) { * @param cClass the concrete class of the added NodePattern * @param id the identifier for the node pattern * @param modifications the modifications to be applied to the node - * @return the pattern list modification * @param the node type of the added node as defined by the edge * @param the concrete type of the added node + * @return the pattern list modification */ @SafeVarargs public final PatternListModification node(Class cClass, String id, PatternModification... modifications) { @@ -203,6 +211,8 @@ public final PatternModification the source {@link Node} type * @param the target {@link Node} type + * @param modifications a {@link PatternListModification} object + * @param a C class * @return the pattern modification */ @SafeVarargs @@ -216,6 +226,10 @@ public final PatternModification the target {@link Node} type + * @param cClass a {@link Class} object + * @param modifications a {@link PatternModification} object + * @param a T class + * @param a C class * @return the pattern modification */ @SafeVarargs @@ -230,6 +244,9 @@ public final PatternModification the target {@link Node} type * @param the related {@link Node} type + * @param cClass a {@link Class} object + * @param modifications a {@link PatternModification} object + * @param a C class * @return the pattern modification */ @SafeVarargs @@ -238,6 +255,12 @@ public final PatternModification(edge, cClass, id, List.of(modifications)); } + /** + * Creates a {@link PatternModification} that sets the target {@link NodePattern} as the representative of the + * NodePattern. {@link Node}s matching this {@link NodePattern} will be the representative of the {@link Match}. + * @param the {@link Node} type + * @return the pattern modification + */ public final PatternModification setRepresentingNode() { return new SetRepresentingNode<>(); } @@ -507,7 +530,7 @@ public void apply(NodePattern target, PatternRegistry patterns) { } } - private record AddEqualAttributes(CpgPropertyEdge propertyEdge, String otherId) implements PatternModification { + private record AddEqualAttributes(CpgAttributeEdge propertyEdge, String otherId) implements PatternModification { @Override public void apply(NodePattern target, PatternRegistry patterns) { NodePattern otherPattern = (NodePattern) patterns.getPattern(otherId); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternImpl.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternImpl.java index c64d97bf8..88115de5e 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternImpl.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/GraphPatternImpl.java @@ -12,6 +12,10 @@ public abstract class GraphPatternImpl implements GraphPattern { protected final PatternRegistry patternRegistry; protected NodePattern representingNode; + /** + * Constructs a new {@link GraphPatternImpl} from a {@link PatternRegistry}. + * @param patterns a {@link PatternRegistry} object + */ public GraphPatternImpl(PatternRegistry patterns) { representingNode = patterns.getRepresentingNode(); this.patternRegistry = patterns; @@ -30,11 +34,6 @@ public String getId(NodePattern pattern) { return patternRegistry.getId(pattern); } - /** - * Gets the {@link NodePattern} corresponding to the given {@link String} ID. - * @param id the ID - * @return the node pattern - */ public NodePattern getPattern(String id) { return patternRegistry.getPattern(id); } @@ -43,20 +42,16 @@ public Collection getAllIds() { return patternRegistry.allIds(); } - /** - * Adds a copy of the given (transformation target) {@link NodePattern} to this (transformation source) - * {@link SimpleGraphPattern}. - * @param roleName the {@link String} ID of the {@link NodePattern} - * @param pattern the node pattern - * @param The node type of the {@link NodePattern} - * @return a copy of the given {@link NodePattern} - */ public NodePattern addNode(String roleName, NodePattern pattern) { NodePattern patternCopy = pattern.deepCopy(); this.patternRegistry.put(roleName, patternCopy); return patternCopy; } + /** + * Gets the representingNode of this {@link GraphPatternImpl}. + * @return the representative {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} + */ public NodePattern getRepresentingNode() { return representingNode; } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/Match.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/Match.java index 2a3b4d339..51b9fc7d0 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/Match.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/Match.java @@ -7,19 +7,20 @@ import de.fraunhofer.aisec.cpg.graph.Node; import de.jplag.java_cpg.transformation.matching.edges.CpgEdge; -import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge; +import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge.AnyOfNEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgNthEdge; +import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern.ParentNodePattern; /** * A {@link Match} stores the mapping between a {@link GraphPattern} and {@link Node}s matching the pattern. Especially, - * a {@link WildcardGraphPattern.ParentNodePattern}'s match in the sourceGraph can be saved. + * a {@link ParentNodePattern}'s match in the sourceGraph can be saved. */ public class Match implements Comparable { private final Map, Node> patternToNode; private final GraphPattern pattern; private final Match parent; - private final Map, WildcardMatch> wildcardMatches; + private final Map, WildcardMatch> wildcardMatches; private final Map> edgeMap; private final int childId; @@ -39,6 +40,11 @@ public Match(GraphPattern pattern) { this.wildcardMatches = new HashMap<>(); } + /** + * Creates a new {@link Match}. + * @param pattern the {@link GraphPattern} that this is a match of + * @param parent the parent {@link Match} + */ public Match(GraphPattern pattern, Match parent) { this.pattern = pattern; patternToNode = new HashMap<>(parent.patternToNode); @@ -61,13 +67,14 @@ public void register(NodePattern pattern, N node) { /** * Saves the concrete parent {@link Node} and edge corresponding to a {@link WildcardGraphPattern}. - * @param the concrete node type of the parent - * @param parent the parent + * @param parentPattern the parent node pattern + * @param parent the concrete parent node * @param edge the edge + * @param the node type of the parent as specified by the edge + * @param the node type of the child as specified by the edge */ - public void resolveWildcard(WildcardGraphPattern.ParentNodePattern parentPattern, S parent, - CpgEdge edge) { - NodePattern concreteRoot = NodePattern.forNodeType(edge.getFromClass()); + public void resolveWildcard(ParentNodePattern parentPattern, S parent, CpgEdge edge) { + NodePattern concreteRoot = NodePattern.forNodeType(edge.getSourceClass()); concreteRoot.addRelatedNodePattern(parentPattern.getChildPattern(), edge); this.wildcardMatches.put(parentPattern, new WildcardMatch<>(concreteRoot, edge)); @@ -102,17 +109,28 @@ public T get(NodePattern pattern) { } /** - * Gets the current wildcard match. - * @return the wildcard match + * Gets the current wildcard match for the given {@link ParentNodePattern}. + * @param node the wildcard parent node pattern + * @return the wildcard match for the pattern + * @param the node type of the child */ - public WildcardMatch getWildcardMatch(WildcardGraphPattern.ParentNodePattern node) { + public WildcardMatch getWildcardMatch(ParentNodePattern node) { WildcardMatch wildcardMatch = (WildcardMatch) wildcardMatches.get(node); return wildcardMatch; } - public CpgNthEdge resolveAny1ofNEdge(NodePattern parent, NodePattern.Related1ToNNode relation, + /** + * Resolves an {@link AnyOfNEdge} to a concrete {@link CpgNthEdge}. + * @param parent the parent node pattern + * @param relation the relation object + * @param index the child index + * @param the parent node type + * @param the child node type + * @return the nth edge + */ + public CpgNthEdge resolveAnyOfNEdge(NodePattern parent, NodePattern.RelatedOneToNNode relation, int index) { - CpgMultiEdge.Any1ofNEdge any1ofNEdge = relation.edge().getAny1ofNEdgeTo(relation.pattern()); + AnyOfNEdge any1ofNEdge = relation.edge().getAnyOfNEdgeTo(relation.pattern()); CpgNthEdge concreteEdgePattern = new CpgNthEdge<>(any1ofNEdge.getMultiEdge(), index); EdgeMapKey key = new EdgeMapKey(parent, any1ofNEdge); this.edgeMap.put(key, concreteEdgePattern); @@ -158,6 +176,10 @@ public String toString() { + (getRepresentingNode() == null ? "" : "[%s]".formatted(desc(getRepresentingNode()))); } + /** + * Removes a node from this {@link Match}. + * @param pattern the pattern + */ public void remove(NodePattern pattern) { this.patternToNode.remove(pattern); } @@ -199,10 +221,22 @@ public boolean equals(Object o) { return true; } - public CpgNthEdge getEdge(NodePattern parentPattern, CpgMultiEdge.Any1ofNEdge edge) { - return (CpgNthEdge) this.edgeMap.get(new EdgeMapKey(parentPattern, edge)); + /** + * Gets the concrete {@link CpgNthEdge} for a {@link AnyOfNEdge} in this {@link Match}. + * @param sourcePattern the source pattern + * @param edge the any-of-n edge + * @param the source node type + * @param the target node type + * @return the nth edge + */ + public CpgNthEdge getEdge(NodePattern sourcePattern, AnyOfNEdge edge) { + return (CpgNthEdge) this.edgeMap.get(new EdgeMapKey(sourcePattern, edge)); } + /** + * Gets the representing {@link Node} of this {@link Match}. + * @return the representing node. + */ public Node getRepresentingNode() { NodePattern representingNodePattern = this.pattern.getRepresentingNode(); if (Objects.isNull(representingNodePattern)) { @@ -221,7 +255,7 @@ public Node getRepresentingNode() { /* package-private */ public record WildcardMatch(NodePattern parentPattern, CpgEdge edge) { } - private record EdgeMapKey(NodePattern parent, CpgMultiEdge.Any1ofNEdge edge) { + private record EdgeMapKey(NodePattern parent, AnyOfNEdge edge) { } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MatchProperty.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MatchProperty.java index 0a38094ff..5fe3548f2 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MatchProperty.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MatchProperty.java @@ -3,12 +3,19 @@ import de.fraunhofer.aisec.cpg.graph.Node; /** - * A {@link MatchProperty} can be used to represent a property of a {@link Match} involving multiple {@link Node}s and - * their relations. - * @param The node type of the node that the property is assigned to + * A {@link de.jplag.java_cpg.transformation.matching.pattern.MatchProperty} can be used to represent a property of a + * {@link de.jplag.java_cpg.transformation.matching.pattern.Match} involving multiple + * {@link de.fraunhofer.aisec.cpg.graph.Node}s and their relations. + * @param The node type of the node that the property is assigned to */ @FunctionalInterface -public interface MatchProperty { +public interface MatchProperty { - boolean test(S s, Match match); + /** + * Tests whether the {@link Node} and the {@link Match} satisfy this {@link MatchProperty}. + * @param n the node + * @param match the match + * @return true iff the match satisfies the match property + */ + boolean test(N n, Match match); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MultiGraphPattern.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MultiGraphPattern.java index 3b0241e20..51e3aa14a 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MultiGraphPattern.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/MultiGraphPattern.java @@ -17,6 +17,11 @@ public class MultiGraphPattern extends GraphPatternImpl { private final List> subgraphs; + /** + * Creates a new {@link MultiGraphPattern}. + * @param subgraphs the child graphs + * @param patterns the pattern registry + */ public MultiGraphPattern(List> subgraphs, PatternRegistry patterns) { super(patterns); this.subgraphs = subgraphs; diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/NodeListPattern.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/NodeListPattern.java index 685266794..4fc0592a4 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/NodeListPattern.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/NodeListPattern.java @@ -1,12 +1,13 @@ package de.jplag.java_cpg.transformation.matching.pattern; import java.util.ArrayList; +import java.util.List; import de.fraunhofer.aisec.cpg.graph.Node; /** * A {@link NodeListPattern} is a pattern that involves a sequence of {@link Node}s. - * @param + * @param the base type of the nodes */ public class NodeListPattern { @@ -19,23 +20,44 @@ public class NodeListPattern { */ private final ArrayList> elements; + /** + * Constructs a new {@link NodeListPattern}. + * @param tClass the common supertype of the {@link Node}s in the list. + */ public NodeListPattern(Class tClass) { this.tClass = tClass; this.elements = new ArrayList<>(); } + /** + * Adds a {@link NodePattern} to the {@link NodeListPattern}. + * @param nodePattern the node pattern + */ public void addElement(NodePattern nodePattern) { elements.add(nodePattern); } + /** + * Gets the nth {@link Node} of this {@link NodeListPattern} + * @param index the index + * @return the element at the given index + */ public NodePattern get(int index) { return elements.get(index); } - public ArrayList> getElements() { + /** + * Gets the list of all {@link Node}s in this {@link NodeListPattern}. + * @return list of all elements + */ + public List> getElements() { return new ArrayList<>(elements); } + /** + * Gets the size of the {@link NodeListPattern}. + * @return the element count + */ public int size() { return elements.size(); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternRegistry.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternRegistry.java index 933e2f448..a4992d128 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternRegistry.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternRegistry.java @@ -9,13 +9,16 @@ import org.slf4j.LoggerFactory; import de.fraunhofer.aisec.cpg.graph.Node; -import de.jplag.java_cpg.transformation.GraphTransformation; /** - * The {@link PatternRegistry} saves the {@link NodePattern}s involved in a {@link GraphTransformation} and their - * identifiers. + * The {@link de.jplag.java_cpg.transformation.matching.pattern.PatternRegistry} saves the + * {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern}s involved in a + * {@link de.jplag.java_cpg.transformation.GraphTransformation} and their identifiers. + * @author robin + * @version $Id: $Id */ public class PatternRegistry { + /** Constant WILDCARD_PARENT_ID="wildcardParent#" */ public static final String WILDCARD_PARENT_ID = "wildcardParent#"; private final Map> patternById; private final Map, String> idByPattern; @@ -28,29 +31,68 @@ public class PatternRegistry { private static final Logger logger = LoggerFactory.getLogger(PatternRegistry.class); private int wildcardCounter; + /** + *

+ * Constructor for PatternRegistry. + *

+ */ public PatternRegistry() { this.patternById = new HashMap<>(); this.idByPattern = new HashMap<>(); this.wildcardCounter = 0; } + /** + *

+ * addAll. + *

+ * @param patternByRoleName a {@link java.util.Map} object + */ public void addAll(Map> patternByRoleName) { this.patternById.putAll(patternByRoleName); this.idByPattern.putAll(patternByRoleName.keySet().stream().collect(Collectors.toMap(patternByRoleName::get, k -> k))); } + /** + *

+ * getPattern. + *

+ * @param nodePatternId a {@link java.lang.String} object + * @return a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + */ public NodePattern getPattern(String nodePatternId) { return patternById.get(nodePatternId); } + /** + *

+ * getId. + *

+ * @param nodePattern a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + * @return a {@link java.lang.String} object + */ public String getId(NodePattern nodePattern) { return idByPattern.get(nodePattern); } + /** + *

+ * allIds. + *

+ * @return a {@link java.util.Collection} object + */ public Collection allIds() { return patternById.keySet(); } + /** + *

+ * put. + *

+ * @param id a {@link java.lang.String} object + * @param pattern a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + * @param a T class + */ public void put(String id, NodePattern pattern) { if (patternById.containsKey(id)) { logger.warn("A NodePattern with the id '%s' is already present in the PatternRegistry"); @@ -59,19 +101,44 @@ public void put(String id, NodePattern pattern) { this.idByPattern.put(pattern, id); } + /** + *

+ * Setter for the field representingNode. + *

+ * @param representingNode a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + */ public void setRepresentingNode(NodePattern representingNode) { this.representingNode = representingNode; } + /** + *

+ * Getter for the field representingNode. + *

+ * @return a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + */ public NodePattern getRepresentingNode() { return this.representingNode; } + /** + *

+ * createWildcardId. + *

+ * @return a {@link java.lang.String} object + */ public String createWildcardId() { return WILDCARD_PARENT_ID + wildcardCounter++; } + /** + *

+ * containsPattern. + *

+ * @param notePatternId a {@link java.lang.String} object + * @return a boolean + */ public boolean containsPattern(String notePatternId) { return patternById.containsKey(notePatternId); } -} \ No newline at end of file +} diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternUtil.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternUtil.java index 6d0531d52..a266a69c2 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternUtil.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/PatternUtil.java @@ -7,19 +7,18 @@ import de.fraunhofer.aisec.cpg.graph.*; import de.fraunhofer.aisec.cpg.graph.declarations.Declaration; -import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration; import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration; -import de.fraunhofer.aisec.cpg.graph.declarations.ValueDeclaration; import de.fraunhofer.aisec.cpg.graph.statements.*; import de.fraunhofer.aisec.cpg.graph.statements.expressions.*; -import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker; +import de.jplag.java_cpg.transformation.matching.edges.CpgAttributeEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge; import de.jplag.java_cpg.transformation.matching.edges.CpgNthEdge; -import de.jplag.java_cpg.transformation.matching.edges.CpgPropertyEdge; /** - * Contains convenience methods to create elements of {@link GraphPattern}s and {@link NodePattern}s. + * Contains convenience methods to create elements of + * {@link de.jplag.java_cpg.transformation.matching.pattern.GraphPattern}s and + * {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern}s. */ public class PatternUtil { /** @@ -33,10 +32,27 @@ public static Predicate notNull(CpgEdge !Objects.isNull(edge.getRelated(s)); } - public static Predicate notNull(CpgPropertyEdge edge) { + /** + * Creates a {@link Predicate} property for an edge that specifies that its target shall not be null. + * @param edge the edge + * @param the source node type + * @param

the target property type + * @return the predicate + */ + public static Predicate notNull(CpgAttributeEdge edge) { return s -> !Objects.isNull(edge.getter().apply(s)); } + /** + * Creates a {@link Predicate} property for an edge that specifies that it target shall not be an instant of the given + * type. + * @param edge the edge + * @param clazz the concrete node class + * @param the source node type + * @param the target node type as specified by the edge + * @param the concrete target node type + * @return the predicate + */ public static Predicate notInstanceOf(CpgEdge edge, Class clazz) { return s -> !clazz.isInstance(edge.getter().apply(s)); } @@ -54,35 +70,75 @@ public static CpgEdge nthElement(CpgMulti } /** - * Creates a {@link Predicate} that checks if the related object is equal to the given value. - * @param propertyEdge a function to get the related object + * Creates a {@link Predicate} that checks if the related attribute is equal to the given value. + * @param attributeEdge a function to get the related attribute * @param value the value to check against * @param the source node type * @param

the predicate type * @return the predicate */ - public static Predicate attributeEquals(CpgPropertyEdge propertyEdge, P value) { - return s -> Objects.equals(propertyEdge.get(s), value); + public static Predicate attributeEquals(CpgAttributeEdge attributeEdge, P value) { + return s -> Objects.equals(attributeEdge.get(s), value); } - public static Predicate attributeToStringEquals(CpgPropertyEdge propertyEdge, String value) { - return s -> Objects.equals(propertyEdge.get(s).toString(), value); + /** + * Creates a predicate property for an edge that specifies that its target attribute shall be equal to the given String. + * @param attributeEdge the attribute edge + * @param value the required value + * @param the source node type + * @param

the attribute type + * @return the predicate + */ + public static Predicate attributeToStringEquals(CpgAttributeEdge attributeEdge, String value) { + return s -> Objects.equals(attributeEdge.get(s).toString(), value); } - public static Predicate attributeToStringStartsWith(CpgPropertyEdge propertyEdge, String value) { - return s -> propertyEdge.get(s).toString().startsWith(value); + /** + * Creates a {@link Predicate} property for an edge that specifies that the target attribute as a {@link String} starts + * with the given {@link String}. + * @param attributeEdge the attribute edge + * @param value the required starting substring + * @param the source node type + * @param

the target attribute type + * @return the predicate + */ + public static Predicate attributeToStringStartsWith(CpgAttributeEdge attributeEdge, String value) { + return s -> attributeEdge.get(s).toString().startsWith(value); } - public static Predicate attributeContains(CpgPropertyEdge> propertyEdge, P value) { - return s -> propertyEdge.get(s).contains(value); + /** + * Creates a {@link Predicate} property for an edge that specifies that the target attribute list contains the given + * value. + * @param attributeEdge the attribute edge + * @param value the required contained value + * @param the source node type + * @param

The target attributes type + * @return the predicate + */ + public static Predicate attributeContains(CpgAttributeEdge> attributeEdge, P value) { + return s -> attributeEdge.get(s).contains(value); } - public static Predicate notEmpty(CpgMultiEdge propertyEdge) { - return s -> !propertyEdge.getAllTargets(s).isEmpty(); + /** + * Creates a predicate property for an edge that specifies that the target node list is not empty. + * @param edge the edge + * @param the source node type + * @param the target node type + * @return the predicate + */ + public static Predicate notEmpty(CpgMultiEdge edge) { + return s -> !edge.getAllTargets(s).isEmpty(); } - public static Predicate isEmpty(CpgMultiEdge propertyEdge) { - return s -> propertyEdge.getAllTargets(s).isEmpty(); + /** + * Creates a {@link Predicate} property for an edge that specifies that the target node list is empty. + * @param edge the edge + * @param the source node type + * @param the target node type + * @return the predicate + */ + public static Predicate isEmpty(CpgMultiEdge edge) { + return s -> edge.getAllTargets(s).isEmpty(); } /** @@ -105,15 +161,16 @@ public static Predicate nElements(CpgMultiEd * @param

the property value type * @return the predicate */ - public static Predicate oneOf(CpgPropertyEdge getter, List

acceptedValues) { + public static Predicate oneOf(CpgAttributeEdge getter, List

acceptedValues) { return s -> acceptedValues.contains(getter.get(s)); } /** - * Creates a new {@link Node} of the type specified by the given {@link NodePattern}. + * Creates a new {@link de.fraunhofer.aisec.cpg.graph.Node} of the type specified by the given + * {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern}. * @param pattern the pattern * @param the node pattern type - * @return the new {@link Node} + * @return the new {@link de.fraunhofer.aisec.cpg.graph.Node} */ public static T instantiate(NodePattern pattern) { try { @@ -124,6 +181,11 @@ public static T instantiate(NodePattern pattern) { } } + /** + * Computes the list of {@link Node}s that may influence the given {@link Node}'s value. + * @param node the node + * @return the nodes with data flow dependencies towards the given node + */ public static Set dfgReferences(Node node) { LinkedList workList = new LinkedList<>(List.of(node)); Set references = new HashSet<>(); @@ -146,86 +208,18 @@ public static Set dfgReferences(Node node) { return references.stream().flatMap(decl -> decl.getPrevDFG().stream()).collect(Collectors.toSet()); } - public static Set incomingDeclarations(Node node) { - Set res = new HashSet<>(); - node.getPrevEOG().forEach(it -> res.addAll(incomingDeclarations(it))); - - if (node instanceof AssignmentHolder assignmentHolder) { - for (Assignment assignment : assignmentHolder.getAssignments()) { - res.removeIf(it -> assignment.getTarget().equals(it.getTarget())); - } - res.addAll(assignmentHolder.getAssignments()); - } - - return res; - } - - public static void sortByDfgFlow(MethodDeclaration methodDeclaration) { - List movableStatements = getMovableStatements(methodDeclaration.getBody()); - Map> currentReferences = new HashMap<>(); - Map> possibleValues = new HashMap<>(); - Map> statementToReferences = new HashMap<>(); - Set seen = new HashSet<>(); - - List workList = SubgraphWalker.INSTANCE.getEOGPathEdges(methodDeclaration.getBody()).getExits(); - Statement currentStatement = null; - - while (!workList.isEmpty()) { - Node node = workList.remove(0); - if (seen.contains(node)) - continue; - - if (node instanceof Reference reference) { - currentReferences.computeIfAbsent(reference.getRefersTo(), declaration -> new ArrayList<>()).add(reference); - // statementToReferences.computeIfAbsent(currentStatement, statement -> new ArrayList<>()) - // .add(reference); - } else if (node instanceof AssignmentHolder assignmentHolder) { - for (Assignment assignment : assignmentHolder.getAssignments()) { - ValueDeclaration declaration = (ValueDeclaration) assignment.getTarget(); - List valueReferences = currentReferences.getOrDefault(declaration, List.of()); - valueReferences.forEach(reference -> possibleValues.computeIfAbsent(reference, it -> new ArrayList<>()).add(assignment)); - valueReferences.clear(); - } - } else if (node instanceof UnaryOperator operator && operator.getInput() instanceof Reference ref - && ref.getAccess().equals(AccessValues.READWRITE)) { - Assignment assignment = new Assignment(operator, ref, null); - - ValueDeclaration refersTo = (ValueDeclaration) ref.getRefersTo(); - currentReferences.getOrDefault(refersTo, List.of()); - - } - - seen.add(node); - workList.addAll(0, node.getPrevEOG()); - } - - } - - private static List getMovableStatements(Statement body) { - if (body instanceof Block block) { - return block.getStatements().stream().map(PatternUtil::getMovableStatements).flatMap(List::stream).toList(); - } else if (body instanceof ArgumentHolder holder) { - if (holder instanceof IfStatement || holder instanceof WhileStatement || holder instanceof DoStatement) { - - } - } - return null; - } - /** - * Creates a new {@link Predicate} that checks whether this node contains exactly one exit. This should hold e.g. for - * non-branching statements, loop statements, and method bodies if they do not contain a return statement other than the - * last return statement of the method. + * Creates a {@link Predicate} property that specifies that the given expression is constant. * @return the predicate */ - public static Predicate isEogConfluent() { - return node -> SubgraphWalker.INSTANCE.getEOGPathEdges(node).getExits().size() == 1; - } - public static Predicate isConstant() { return expression -> expression instanceof Literal; } + /** + * Creates a {@link Predicate} property that specifies that the given {@link Expression} is a field reference. + * @return the predicate + */ public static Predicate isFieldReference() { return expression -> { if (!(expression instanceof MemberExpression fieldAccess)) { @@ -237,10 +231,22 @@ public static Predicate isFieldReference() { }; } + /** + * Creates a {@link Predicate} property that specifies that either of the given predicates must hold. + * @param predicate1 the first predicate + * @param predicate2 the second predicate + * @param the target node type + * @return the predicate + */ public static Predicate or(Predicate predicate1, Predicate predicate2) { return t -> predicate1.test(t) || predicate2.test(t); } + /** + * Computes a brief description for a {@link Node}. + * @param node the node + * @return the description + */ public static String desc(Node node) { node.getName(); return "%s(%s%s)".formatted(node.getClass().getSimpleName(), diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/SimpleGraphPattern.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/SimpleGraphPattern.java index ccde3e105..692400ac3 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/SimpleGraphPattern.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/SimpleGraphPattern.java @@ -6,17 +6,22 @@ import de.fraunhofer.aisec.cpg.graph.Node; /** - * A {@link SimpleGraphPattern} describes the occurrence and relation of {@link Node}s in a Graph and their properties. - * A SimpleGraphPattern has exactly one root {@link NodePattern}. - * @param the root {@link Node} type of the graph pattern + * A {@link de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern} describes the occurrence and relation + * of {@link de.fraunhofer.aisec.cpg.graph.Node}s in a Graph and their properties. A SimpleGraphPattern has exactly one + * root {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern}. + * @param the root {@link de.fraunhofer.aisec.cpg.graph.Node} type of the graph pattern + * @author robin + * @version $Id: $Id */ public class SimpleGraphPattern extends GraphPatternImpl { private NodePattern root; /** - * Creates a new {@link SimpleGraphPattern} with the given root {@link NodePattern}. - * @param root the root {@link NodePattern} + * Creates a new {@link de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern} with the given root + * {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern}. + * @param root the root {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} + * @param patterns a {@link de.jplag.java_cpg.transformation.matching.pattern.PatternRegistry} object */ public SimpleGraphPattern(NodePattern root, PatternRegistry patterns) { super(patterns); @@ -28,27 +33,33 @@ public SimpleGraphPattern(NodePattern root, PatternRegistry patterns) { } /** - * Gets the root {@link NodePattern} of the {@link SimpleGraphPattern}. + * Gets the root {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} of the + * {@link de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern}. * @return the root */ public NodePattern getRoot() { return root; } + /** {@inheritDoc} */ @Override public List> getRoots() { return List.of(root); } + /** {@inheritDoc} */ @Override public List match(Map, List> rootCandidates) { return rootCandidates.get(root).stream().map(this::recursiveMatch).flatMap(List::stream).toList(); } /** - * Checks this {@link SimpleGraphPattern} against the given concrete {@link Node} for {@link Match}es. - * @param rootCandidate the possible root {@link Node} of {@link Match}es - * @return the list of {@link Match}es found + * Checks this {@link de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern} against the given concrete + * {@link de.fraunhofer.aisec.cpg.graph.Node} for {@link de.jplag.java_cpg.transformation.matching.pattern.Match}es. + * @param rootCandidate the possible root {@link de.fraunhofer.aisec.cpg.graph.Node} of + * {@link de.jplag.java_cpg.transformation.matching.pattern.Match}es + * @return the list of {@link de.jplag.java_cpg.transformation.matching.pattern.Match}es found + * @param a C class */ public List recursiveMatch(C rootCandidate) { List matches = new ArrayList<>(); @@ -57,6 +68,7 @@ public List recursiveMatch(C rootCandidate) { return matches; } + /** {@inheritDoc} */ @Override public boolean validate(Match match) { Node rootCandidate = match.get(this.root); @@ -64,6 +76,7 @@ public boolean validate(Match match) { return matches.stream().anyMatch(match::equals); } + /** {@inheritDoc} */ @Override public void compareTo(GraphPattern targetPattern, BiConsumer, NodePattern> compareFunction) { if (!(targetPattern instanceof SimpleGraphPattern tTarget && Objects.equals(root.getClass(), tTarget.root.getClass()))) { @@ -74,7 +87,8 @@ public void compareTo(GraphPattern targetPattern, BiConsumer, Nod } /** - * Sets the root {@link NodePattern} of this {@link SimpleGraphPattern}. + * Sets the root {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} of this + * {@link de.jplag.java_cpg.transformation.matching.pattern.SimpleGraphPattern}. * @param rootPattern the root */ protected void setRoot(NodePattern rootPattern) { diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/WildcardGraphPattern.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/WildcardGraphPattern.java index 1c9eb6364..aa45951f6 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/WildcardGraphPattern.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/matching/pattern/WildcardGraphPattern.java @@ -18,6 +18,8 @@ * This class represents a pattern where the root node's parent is unknown, but involved in a transformation (e.g. the * root node is moved/deleted). * @param The node type of the child node of the wildcard parent + * @author robin + * @version $Id: $Id */ public class WildcardGraphPattern extends SimpleGraphPattern { private final ParentNodePattern wildcardParent; @@ -34,6 +36,7 @@ public class WildcardGraphPattern extends SimpleGraphPattern recursiveMatch(Node rootCandidate) { // rootCandidate is actually candidate for wildcard parent pattern! @@ -45,6 +48,7 @@ public List recursiveMatch(Node rootCandidate) { return matches; } + /** {@inheritDoc} */ @Override public boolean validate(Match match) { Node rootCandidate = match.get(this.wildcardParent); @@ -54,6 +58,7 @@ public boolean validate(Match match) { /** * Pattern to describe the unknown AST context that a node may appear in. + * @param the child node type */ public static class ParentNodePattern extends NodePattern.NodePatternImpl { private final NodePattern childPattern; @@ -84,7 +89,7 @@ public void recursiveMatch(Node node, List matches, CpgEdge incomin List resultMatches = new ArrayList<>(); // This node should match if it has a fitting edge and child - edgesToType.stream().filter(e -> e.getFromClass().isAssignableFrom(node.getClass())).forEach(e -> { + edgesToType.stream().filter(e -> e.getSourceClass().isAssignableFrom(node.getClass())).forEach(e -> { List matchesCopy = new ArrayList<>(matches.stream().map(Match::copy).toList()); matchesCopy.forEach(match -> match.register(this, node)); wildCardMatch(e, node, matchesCopy); @@ -131,7 +136,7 @@ private void wildCardMatch(IEdge e, Node parent, @Override public List> getCandidateClasses() { - return edgesToType.stream().map(IEdge::getFromClass).collect(Collectors.toList()); + return edgesToType.stream().map(IEdge::getSourceClass).collect(Collectors.toList()); } public NodePattern getChildPattern() { @@ -141,12 +146,13 @@ public NodePattern getChildPattern() { /** * This models an edge unknown at creation time, of which the target is a T node. + * @param the target node type */ public static class Edge extends CpgEdge { private Edge(Class tClass) { super(null, null, AST); - this.setToClass(tClass); + this.setTargetClass(tClass); } @Override diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/CreateNodeOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/CreateNodeOperation.java index 490f3e9b7..59c0fe462 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/CreateNodeOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/CreateNodeOperation.java @@ -27,7 +27,7 @@ public record CreateNodeOperation(GraphPattern sourceGraph, Stri CatchClause.class, RecordDeclaration.class, TemplateDeclaration.class, TryStatement.class, NamespaceDeclaration.class); @Override - public void resolve(Match match, TranslationContext ctx) { + public void resolveAndApply(Match match, TranslationContext ctx) { N newNode = PatternUtil.instantiate(pattern); match.register(pattern, newNode); @@ -48,7 +48,7 @@ public GraphOperation instantiateWildcard(Match match) { } @Override - public GraphOperation instantiateAny1ofNEdge(Match match) { + public GraphOperation instantiateAnyOfNEdge(Match match) { throw new RuntimeException("Cannot instantiate CreateNodeOperation"); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/DummyNeighbor.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/DummyNeighbor.java index aa98bcfda..b70aad20f 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/DummyNeighbor.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/DummyNeighbor.java @@ -27,6 +27,10 @@ private DummyNeighbor() { targetMap = new HashMap<>(); } + /** + * Gets the singleton instance. + * @return the {@link DummyNeighbor} node + */ public static DummyNeighbor getInstance() { return INSTANCE; } @@ -82,6 +86,9 @@ public void clearOriginalEdgesOfTarget(Node target) { } } + /** + * Clears the saved edges. + */ public void clear() { targetMap.clear(); sourceMap.clear(); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperation.java index 2f38092ec..0244f6ef1 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperation.java @@ -5,10 +5,14 @@ import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge; import de.jplag.java_cpg.transformation.GraphTransformation; import de.jplag.java_cpg.transformation.TransformationException; +import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge; +import de.jplag.java_cpg.transformation.matching.edges.CpgMultiEdge.AnyOfNEdge; +import de.jplag.java_cpg.transformation.matching.edges.CpgNthEdge; import de.jplag.java_cpg.transformation.matching.edges.IEdge; import de.jplag.java_cpg.transformation.matching.pattern.Match; import de.jplag.java_cpg.transformation.matching.pattern.Match.WildcardMatch; import de.jplag.java_cpg.transformation.matching.pattern.NodePattern; +import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern.Edge; import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern.ParentNodePattern; /** @@ -19,9 +23,10 @@ public interface GraphOperation { * Applies the {@link GraphOperation} on the graph represented by a {@link Match} indicating which nodes are involved in * the operation. * @param match the pattern match - * @param ctx + * @param ctx the translation context + * @throws TransformationException if the graph is malformed. */ - void resolve(Match match, TranslationContext ctx) throws TransformationException; + void resolveAndApply(Match match, TranslationContext ctx) throws TransformationException; /** * Gets the {@link NodePattern} representing the {@link Node} where the operation is intended to be applied. @@ -37,9 +42,23 @@ public interface GraphOperation { */ GraphOperation instantiateWildcard(Match match); - GraphOperation instantiateAny1ofNEdge(Match match); + /** + * Returns a copy of this {@link GraphOperation} where the relevant {@link AnyOfNEdge} is replaced with a + * {@link CpgNthEdge}. + * @param match the {@link Match} of a {@link GraphTransformation} source pattern + * @return the instantiated {@link GraphOperation} + */ + GraphOperation instantiateAnyOfNEdge(Match match); + /** + * Determines whether this {@link GraphOperation} is wildcarded. + * @return true iff this {@link GraphOperation} involves a {@link Edge} that needs to be instantiated. + */ boolean isWildcarded(); + /** + * Determines whether this {@link GraphOperation} is multi-edged. + * @return true iff this {@link GraphOperation} involves a {@link CpgMultiEdge}. + */ boolean isMultiEdged(); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperationImpl.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperationImpl.java index 2ab36e7eb..972875f96 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperationImpl.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/GraphOperationImpl.java @@ -7,7 +7,8 @@ import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern; /** - * This class stores method implementations common to all types of {@link GraphOperation}s. + * This class stores method implementations common to all types of + * {@link de.jplag.java_cpg.transformation.operations.GraphOperation}s. * @param The type of the parent node where this GraphOperation happens * @param The type of node related to the parent node */ @@ -16,16 +17,23 @@ public abstract class GraphOperationImpl impleme protected final NodePattern parentPattern; protected final CpgEdge edge; + /** + * Creates a new GraphOperationImpl. + * @param parentPattern the {@link NodePattern} where the {@link GraphOperation} sets in + * @param edge the {@link CpgEdge} that this {@link GraphOperation} manipulates + */ protected GraphOperationImpl(NodePattern parentPattern, CpgEdge edge) { this.parentPattern = parentPattern; this.edge = edge; } - public boolean isWildcarded() { - return this.parentPattern instanceof WildcardGraphPattern.ParentNodePattern && this.edge instanceof WildcardGraphPattern.Edge; + @Override + public boolean isMultiEdged() { + return this.edge instanceof CpgMultiEdge.AnyOfNEdge; } - public boolean isMultiEdged() { - return this.edge instanceof CpgMultiEdge.Any1ofNEdge; + @Override + public boolean isWildcarded() { + return this.parentPattern instanceof WildcardGraphPattern.ParentNodePattern && this.edge instanceof WildcardGraphPattern.Edge; } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/InsertOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/InsertOperation.java index 38685bff2..21f781bb8 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/InsertOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/InsertOperation.java @@ -20,7 +20,7 @@ import de.jplag.java_cpg.transformation.matching.pattern.NodePattern; /** - * Inserts the target {@link Node} into a collection of other subnodes of the parent {@link Node}. + * Inserts the target {@link Node} into a collection of other child nodes of the parent {@link Node}. * @param type of the parentPattern node, defined by the edge * @param type of the target node, defined by the edge */ @@ -37,6 +37,7 @@ public final class InsertOperation extends Graph private final boolean connectEog; /** + * Creates a new {@link InsertOperation}. * @param parentPattern source node of the edge * @param edge edge where an element shall be inserted * @param newChildPattern node to be inserted @@ -51,7 +52,7 @@ public InsertOperation(NodePattern parentPattern, CpgNthEdge } @Override - public void resolve(Match match, TranslationContext ctx) { + public void resolveAndApply(Match match, TranslationContext ctx) { S parent = match.get(parentPattern); // match should contain newChildPattern node because of Builder.createNewNodes() T newTarget = match.get(newChildPattern); @@ -62,6 +63,13 @@ public void resolve(Match match, TranslationContext ctx) { } + /** + * Applies the InsertOperation on the given {@link Node}s. + * @param ctx the translation context + * @param parent the parent node + * @param newTarget the new child node + * @param index the insertion index + */ public void apply(TranslationContext ctx, S parent, T newTarget, int index) { PropertyEdge newEdge = new PropertyEdge<>(parent, newTarget); newEdge.addProperty(Properties.INDEX, index); @@ -114,11 +122,11 @@ public GraphOperation instantiateWildcard(Match match) { } @Override - public GraphOperation instantiateAny1ofNEdge(Match match) { - CpgMultiEdge.Any1ofNEdge any1OfNEdge = (CpgMultiEdge.Any1ofNEdge) edge; - CpgNthEdge edge1 = match.getEdge(this.parentPattern, any1OfNEdge); + public GraphOperation instantiateAnyOfNEdge(Match match) { + CpgMultiEdge.AnyOfNEdge anyOfNEdge = (CpgMultiEdge.AnyOfNEdge) edge; + CpgNthEdge edge1 = match.getEdge(this.parentPattern, anyOfNEdge); if (Objects.isNull(edge1)) { - edge1 = new CpgNthEdge<>(any1OfNEdge.getMultiEdge(), 0); + edge1 = new CpgNthEdge<>(anyOfNEdge.getMultiEdge(), 0); } return new InsertOperation<>(parentPattern, edge1, newChildPattern, this.connectEog); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/RemoveOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/RemoveOperation.java index 9ab4f213f..b500fe005 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/RemoveOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/RemoveOperation.java @@ -19,18 +19,26 @@ import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern; /** - * This operation removes a {@link Node} from its AST context. - * @param the parent {@link Node} type - * @param the target {@link Node} type + * This operation removes a {@link de.fraunhofer.aisec.cpg.graph.Node} from its AST context. + * @param the parent {@link de.fraunhofer.aisec.cpg.graph.Node} type + * @param the target {@link de.fraunhofer.aisec.cpg.graph.Node} type + * @author robin + * @version $Id: $Id */ public final class RemoveOperation extends GraphOperationImpl { private final boolean disconnectEog; - public RemoveOperation(NodePattern parentPattern, CpgEdge edge, boolean disconnectEog) { - super(parentPattern, edge); + /** + * Creates a new {@link RemoveOperation}. + * @param sourcePattern The source pattern of which a related node shall be removed + * @param edge the edge + * @param disconnectEog if true, the target node is disconnected in the EOG graph + */ + public RemoveOperation(NodePattern sourcePattern, CpgEdge edge, boolean disconnectEog) { + super(sourcePattern, edge); this.disconnectEog = disconnectEog; - if (Objects.isNull(parentPattern) || Objects.isNull(edge)) { + if (Objects.isNull(sourcePattern) || Objects.isNull(edge)) { throw new RuntimeException("Invalid RemoveOperation: the pattern root needs to be wrapped into a WildcardParentPattern."); } } @@ -42,13 +50,25 @@ public RemoveOperation(NodePattern parentPattern, CpgEdge edg } + /** {@inheritDoc} */ @Override - public void resolve(Match match, TranslationContext ctx) throws TransformationException { + public void resolveAndApply(Match match, TranslationContext ctx) throws TransformationException { S parent = match.get(parentPattern); T element = edge.getter().apply(parent); apply(element, parent, edge, disconnectEog); } + /** + *

+ * apply. + *

+ * @param element a T object + * @param parent a S object + * @param edge a {@link de.jplag.java_cpg.transformation.matching.edges.CpgEdge} object + * @param disconnectEog a boolean + * @param a S class + * @param a T class + */ public static void apply(T element, S parent, CpgEdge edge, boolean disconnectEog) { if (!(edge instanceof CpgNthEdge nthEdge)) { @@ -87,11 +107,13 @@ public static void apply(T element, S parent, C } } + /** {@inheritDoc} */ @Override public NodePattern getTarget() { return parentPattern; } + /** {@inheritDoc} */ @Override public GraphOperation instantiateWildcard(Match match) { WildcardGraphPattern.ParentNodePattern wcParent = (WildcardGraphPattern.ParentNodePattern) this.parentPattern; @@ -103,10 +125,11 @@ private RemoveOperation fromWildcardMatch return new RemoveOperation<>(wildcardMatch.parentPattern(), wildcardMatch.edge(), this.disconnectEog); } + /** {@inheritDoc} */ @Override - public GraphOperation instantiateAny1ofNEdge(Match match) { - CpgMultiEdge.Any1ofNEdge any1OfNEdge = (CpgMultiEdge.Any1ofNEdge) edge; - return new RemoveOperation<>(parentPattern, match.getEdge(this.parentPattern, any1OfNEdge), this.disconnectEog); + public GraphOperation instantiateAnyOfNEdge(Match match) { + CpgMultiEdge.AnyOfNEdge anyOfNEdge = (CpgMultiEdge.AnyOfNEdge) edge; + return new RemoveOperation<>(parentPattern, match.getEdge(this.parentPattern, anyOfNEdge), this.disconnectEog); } } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/ReplaceOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/ReplaceOperation.java index fb0b17c93..dbe6fdac2 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/ReplaceOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/ReplaceOperation.java @@ -17,9 +17,12 @@ import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern; /** - * Replaces the target {@link Node} of an edge by another {@link Node}. + * Replaces the target {@link de.fraunhofer.aisec.cpg.graph.Node} of an edge by another + * {@link de.fraunhofer.aisec.cpg.graph.Node}. * @param type of the parentPattern node, defined by the edge * @param type of the destination node, defined by the edge + * @author robin + * @version $Id: $Id */ public final class ReplaceOperation extends GraphOperationImpl { @@ -33,6 +36,9 @@ public final class ReplaceOperation extends Grap private final boolean disconnectEog; /** + *

+ * Constructor for ReplaceOperation. + *

* @param parentPattern source node of the edge * @param edge edge of which the target shall be replaced * @param newChildPattern replacement node @@ -45,8 +51,9 @@ public ReplaceOperation(NodePattern parentPattern, CpgEdge ed this.disconnectEog = disconnectEog; } + /** {@inheritDoc} */ @Override - public void resolve(Match match, TranslationContext ctx) { + public void resolveAndApply(Match match, TranslationContext ctx) { S parent = match.get(parentPattern); // match should contain newChildPattern node because of Builder.createNewNodes() T newTarget = match.get(newChildPattern); @@ -74,11 +81,13 @@ public void resolve(Match match, TranslationContext ctx) { TransformationUtil.transferEogSuccessor(oldTarget, newTarget); } + /** {@inheritDoc} */ @Override public NodePattern getTarget() { return parentPattern; } + /** {@inheritDoc} */ @Override public GraphOperation instantiateWildcard(Match match) { WildcardGraphPattern.ParentNodePattern wcParent = (WildcardGraphPattern.ParentNodePattern) this.parentPattern; @@ -92,9 +101,10 @@ private ReplaceOperation fromWildcardMatch(Match.Wildcard return new ReplaceOperation<>(sNodePattern, edge1, newChildPattern, this.disconnectEog); } + /** {@inheritDoc} */ @Override - public GraphOperation instantiateAny1ofNEdge(Match match) { - CpgMultiEdge.Any1ofNEdge any1ofNEdge = (CpgMultiEdge.Any1ofNEdge) edge; + public GraphOperation instantiateAnyOfNEdge(Match match) { + CpgMultiEdge.AnyOfNEdge any1ofNEdge = (CpgMultiEdge.AnyOfNEdge) edge; return new ReplaceOperation<>(parentPattern, match.getEdge(this.parentPattern, any1ofNEdge), newChildPattern, this.disconnectEog); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/SetOperation.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/SetOperation.java index 96d9fb26f..fcd42df57 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/SetOperation.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/SetOperation.java @@ -16,15 +16,27 @@ import de.jplag.java_cpg.transformation.matching.pattern.WildcardGraphPattern; /** - * Sets the target {@link Node} of a previously newly created edge to a {@link Node}. + * Sets the target {@link de.fraunhofer.aisec.cpg.graph.Node} of a previously newly created edge to a + * {@link de.fraunhofer.aisec.cpg.graph.Node}. * @param type of the parent node, defined by the edge * @param type of the related node, defined by the edge + * @author robin + * @version $Id: $Id */ public final class SetOperation extends GraphOperationImpl { private static final Logger logger; private final NodePattern newChildPattern; private final boolean disconnectEog; + /** + *

+ * Constructor for SetOperation. + *

+ * @param parentPattern a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + * @param edge a {@link de.jplag.java_cpg.transformation.matching.edges.CpgEdge} object + * @param newChildPattern a {@link de.jplag.java_cpg.transformation.matching.pattern.NodePattern} object + * @param disconnectEog a boolean + */ public SetOperation(NodePattern parentPattern, CpgEdge edge, NodePattern newChildPattern, boolean disconnectEog) { super(parentPattern, edge); this.newChildPattern = newChildPattern; @@ -35,8 +47,9 @@ public SetOperation(NodePattern parentPattern, CpgEdge edge, logger = LoggerFactory.getLogger(SetOperation.class); } + /** {@inheritDoc} */ @Override - public void resolve(Match match, TranslationContext ctx) { + public void resolveAndApply(Match match, TranslationContext ctx) { S parent = match.get(parentPattern); // match should contain newChildPattern node because of Builder.createNewNodes() T newChild = match.get(newChildPattern); @@ -57,11 +70,13 @@ public void resolve(Match match, TranslationContext ctx) { } } + /** {@inheritDoc} */ @Override public NodePattern getTarget() { return parentPattern; } + /** {@inheritDoc} */ @Override public GraphOperation instantiateWildcard(Match match) { if (!(this.parentPattern instanceof WildcardGraphPattern.ParentNodePattern)) { @@ -71,8 +86,9 @@ public GraphOperation instantiateWildcard(Match match) { throw new RuntimeException("Cannot apply SetOperation with WildcardGraphPattern.ParentPattern as parentPattern."); } + /** {@inheritDoc} */ @Override - public GraphOperation instantiateAny1ofNEdge(Match match) { + public GraphOperation instantiateAnyOfNEdge(Match match) { throw new RuntimeException("Cannot apply SetOperation with Any1ofNEdge."); } diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/TransformationUtil.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/TransformationUtil.java index 4edadcfd1..83c6499f6 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/TransformationUtil.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/transformation/operations/TransformationUtil.java @@ -13,24 +13,25 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block; import de.fraunhofer.aisec.cpg.graph.statements.expressions.UnaryOperator; import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker; -import de.jplag.java_cpg.transformation.GraphTransformation; /** - * This class is a collection of auxiliary methods related to {@link GraphTransformation}s. + * This class is a collection of auxiliary methods related to + * {@link de.jplag.java_cpg.transformation.GraphTransformation}s. */ public final class TransformationUtil { - static final Logger logger = LoggerFactory.getLogger(TransformationUtil.class); - public static final DummyNeighbor DUMMY = DummyNeighbor.getInstance(); + private static final Logger logger = LoggerFactory.getLogger(TransformationUtil.class); + private static final DummyNeighbor DUMMY = DummyNeighbor.getInstance(); private TransformationUtil() { /* should not be instantiated */ } /** - * Gets the {@link SubgraphWalker.Border} of the given node's sub-AST that links to outer nodes via EOG edges. + * Gets the {@link de.fraunhofer.aisec.cpg.helpers.SubgraphWalker.Border} of the given node's sub-AST that links to + * outer nodes via EOG edges. * @param astRoot the root of the sub-AST - * @return the EOG {@link SubgraphWalker.Border} of the AST + * @return the EOG {@link de.fraunhofer.aisec.cpg.helpers.SubgraphWalker.Border} of the AST */ public static SubgraphWalker.Border getEogBorders(Node astRoot) { SubgraphWalker.Border result; @@ -93,6 +94,13 @@ static void transferEogPredecessor(Node oldSuccessor, Node newSuccessor) { exits.forEach(exit -> connectNewSuccessor(exit, newSuccessor, true)); } + /** + *

+ * disconnectFromSuccessor. + *

+ * @param astRoot a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @return a {@link de.fraunhofer.aisec.cpg.graph.Node} object + */ public static Node disconnectFromSuccessor(Node astRoot) { Node exit = getExit(astRoot); List> exitEdges = new ArrayList<>(getExitEdges(astRoot, List.of(exit), true)); @@ -159,6 +167,13 @@ static Node connectNewSuccessor(Node target, Node newSuccessor, boolean enforceE return entry; } + /** + *

+ * disconnectFromPredecessor. + *

+ * @param astRoot a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @return a {@link java.util.List} object + */ public static List disconnectFromPredecessor(Node astRoot) { Node entry = getEntry(astRoot); @@ -184,6 +199,13 @@ public static List disconnectFromPredecessor(Node astRoot) { return predExits; } + /** + *

+ * getEntry. + *

+ * @param astRoot a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @return a {@link de.fraunhofer.aisec.cpg.graph.Node} object + */ public static Node getEntry(Node astRoot) { return getEogBorders(astRoot).getEntries().getFirst(); } @@ -215,6 +237,15 @@ static Node connectNewPredecessor(Node target, Node newPredecessor, boolean asAs return entry; } + /** + *

+ * getEntryEdges. + *

+ * @param astParent a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param entry a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param useDummies a boolean + * @return a {@link java.util.List} object + */ @NotNull public static List> getEntryEdges(Node astParent, Node entry, boolean useDummies) { List> currentEntryEdges = entry.getPrevEOGEdges().stream().filter(e -> !isAstChild(astParent, e.getStart())).toList(); @@ -235,6 +266,15 @@ public static List> getEntryEdges(Node astParent, Node entry, } } + /** + *

+ * getExitEdges. + *

+ * @param astParent a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param exits a {@link java.util.List} object + * @param useDummies a boolean + * @return a {@link java.util.List} object + */ @NotNull public static List> getExitEdges(Node astParent, List exits, boolean useDummies) { List> currentExitEdges = exits.stream().flatMap(n -> n.getNextEOGEdges().stream()) @@ -256,6 +296,13 @@ public static List> getExitEdges(Node astParent, List e } + /** + *

+ * insertBefore. + *

+ * @param target a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param newSuccessor a {@link de.fraunhofer.aisec.cpg.graph.Node} object + */ public static void insertBefore(Node target, Node newSuccessor) { Node entry = getEntry(target); List exits = getEogBorders(target).getExits(); @@ -268,6 +315,13 @@ public static void insertBefore(Node target, Node newSuccessor) { exits.forEach(exit -> connectNewSuccessor(exit, succEntry, false)); } + /** + *

+ * insertAfter. + *

+ * @param target a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param newPredecessor a {@link de.fraunhofer.aisec.cpg.graph.Node} object + */ public static void insertAfter(Node target, Node newPredecessor) { Node entry = getEntry(target); Node exit = getExit(target); @@ -280,6 +334,14 @@ public static void insertAfter(Node target, Node newPredecessor) { connectNewSuccessor(predExit, entry, false); } + /** + *

+ * isAstSuccessor. + *

+ * @param element a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param maybeSuccessor a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @return a boolean + */ public static boolean isAstSuccessor(Node element, Node maybeSuccessor) { List exits = getEogBorders(element).getExits(); @@ -289,6 +351,14 @@ public static boolean isAstSuccessor(Node element, Node maybeSuccessor) { return entryEdges.stream().anyMatch(e -> exits.contains(e.getStart())); } + /** + *

+ * isEogSuccessor. + *

+ * @param exit a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @param maybeSuccessor a {@link de.fraunhofer.aisec.cpg.graph.Node} object + * @return a boolean + */ public static boolean isEogSuccessor(Node exit, Node maybeSuccessor) { Node entry = getEntry(maybeSuccessor); List> entryEdges = getEntryEdges(maybeSuccessor, entry, false); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/MethodOrderStrategy.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/MethodOrderStrategy.java index 66686e45e..80d820e85 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/MethodOrderStrategy.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/MethodOrderStrategy.java @@ -23,12 +23,15 @@ * This class contains methods to put a call graph oriented order on methods. */ public class MethodOrderStrategy { - public static final String START_OF_GENERIC_CLASS = "^(\\w+ +)*class +\\w+ *<.*"; - public static final Logger logger = LoggerFactory.getLogger(MethodOrderStrategy.class); + private static final String START_OF_GENERIC_CLASS = "^(\\w+ +)*class +\\w+ *<.*"; + private static final Logger logger = LoggerFactory.getLogger(MethodOrderStrategy.class); private final NodeOrderStrategy nodeOrderStrategy; private int index; private List allMethods; + /** + * Creates a new {@link MethodOrderStrategy}. + */ public MethodOrderStrategy() { this.index = 0; this.nodeOrderStrategy = new NodeOrderStrategy(); diff --git a/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/NodeOrderStrategy.java b/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/NodeOrderStrategy.java index 344fde1ce..87e558b63 100644 --- a/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/NodeOrderStrategy.java +++ b/languages/java-cpg/src/main/java/de/jplag/java_cpg/visitorStrategy/NodeOrderStrategy.java @@ -29,9 +29,12 @@ */ public class NodeOrderStrategy implements IStrategy { - public static final boolean useCallGraphOrder = false; + private static final boolean useCallGraphOrder = true; private List methodOrder; + /** + * Creates a new {@link NodeOrderStrategy}. + */ public NodeOrderStrategy() { } @@ -133,6 +136,12 @@ private static Iterator walkBlock(Block block) { return block.getStatements().stream().map(TransformationUtil::getEntry).iterator(); } + /** + * Finds all child {@link Node}s of the given {@link Statement} in the order determined by the + * {@link NodeOrderStrategy}. + * @param statement the statement + * @return a list of all child nodes + */ public static List flattenStatement(Statement statement) { List astChildren = SubgraphWalker.INSTANCE.flattenAST(statement); NodeOrderStrategy strategy = new NodeOrderStrategy(); @@ -188,4 +197,4 @@ private Iterator walkWhileStatement(WhileStatement whileStatement) { } return Stream.of(body).iterator(); } -} \ No newline at end of file +}