Skip to content

Commit

Permalink
Adds StatementHolder interface and ability to model statements in s…
Browse files Browse the repository at this point in the history
…tructure declarations (#468)

* Adds CodeHolder interface and abillity to modell code in structure declaration

Some languages allow to write executable code on file, class or even namespace level,
e.g. javas static and initializer blocks or any code outside of functions in scripting
languages.

This commit extracts the statement management from the CompoundStatement into default
implementations of the CodeHolder interface and implements it in RecordDeclaration,
NamespaceDeclaration and TranslationUnitDeclaration.

Additionally the EOG-Pass is adapted to also build EOG-Paths over those code blocks.
  • Loading branch information
konradweiss committed Jul 13, 2021
1 parent fc7a26d commit d420449
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import de.fraunhofer.aisec.cpg.graph.declarations.Declaration;
import de.fraunhofer.aisec.cpg.graph.declarations.ParamVariableDeclaration;
import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration;
import de.fraunhofer.aisec.cpg.graph.statements.CompoundStatement;
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression;
import de.fraunhofer.aisec.cpg.graph.types.ParameterizedType;
import de.fraunhofer.aisec.cpg.graph.types.Type;
Expand Down Expand Up @@ -297,6 +298,12 @@ public RecordDeclaration handleClassOrInterfaceDeclaration(
recordDeclaration.addConstructor(c);
} else if (decl instanceof com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) {
recordDeclaration.addDeclaration(handle(decl));
} else if (decl instanceof com.github.javaparser.ast.body.InitializerDeclaration) {
InitializerDeclaration id = (InitializerDeclaration) decl;
CompoundStatement initializerBlock =
lang.getStatementHandler().handleBlockStatement(id.getBody());
initializerBlock.setStaticBlock(id.isStatic());
recordDeclaration.addStatement(initializerBlock);
} else {
log.debug(
"Member {} of type {} is something that we do not parse yet: {}",
Expand Down Expand Up @@ -375,11 +382,6 @@ public de.fraunhofer.aisec.cpg.graph.declarations.FieldDeclaration handleFieldDe
return fieldDeclaration;
}

public Declaration /* TODO refine return type*/ handleInitializerDeclaration(
InitializerDeclaration initializerDecl) {
return new Declaration();
}

public de.fraunhofer.aisec.cpg.graph.declarations.EnumDeclaration handleEnumDeclaration(
com.github.javaparser.ast.body.EnumDeclaration enumDecl) {
String name = getAbsoluteName(enumDecl.getNameAsString());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2021, Fraunhofer AISEC. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $$$$$$\ $$$$$$$\ $$$$$$\
* $$ __$$\ $$ __$$\ $$ __$$\
* $$ / \__|$$ | $$ |$$ / \__|
* $$ | $$$$$$$ |$$ |$$$$\
* $$ | $$ ____/ $$ |\_$$ |
* $$ | $$\ $$ | $$ | $$ |
* \$$$$$ |$$ | \$$$$$ |
* \______/ \__| \______/
*
*/
package de.fraunhofer.aisec.cpg.graph;

import de.fraunhofer.aisec.cpg.graph.edge.Properties;
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge;
import de.fraunhofer.aisec.cpg.graph.statements.Statement;
import java.util.List;
import org.checkerframework.checker.nullness.qual.NonNull;

/**
* This interface denotes an AST-Node that can contain code. This code is stored as statements. This
* includes Translation units namespaces and classes as some languages, mainly scripting languages
* allow code placement outside of explicit functions.
*
* <p>The reason for not only using a statement property that encapsulates all code in a dummy
* compound statements is that code can be distributed between functions and an encapsulating
* compound statement would imply a block of code with a code region containing only the statements.
*/
public interface StatementHolder {

/**
* Getter to be implemented by implementing classes to gain read access to the classes member.
*
* @return List of property Edge statements
*/
@NonNull
List<PropertyEdge<Statement>> getStatementEdges();

void setStatementEdges(@NonNull List<PropertyEdge<Statement>> statements);

/**
* Returns the list of contained statements.
*
* @return contained statements
*/
@NonNull
default List<Statement> getStatements() {
return (List<Statement>) PropertyEdge.unwrapPropertyEdge(getStatementEdges(), true);
}

@NonNull
default List<PropertyEdge<Statement>> getStatementsPropertyEdge() {
return getStatementEdges();
}

default void setStatements(@NonNull List<Statement> statements) {
setStatementEdges(PropertyEdge.transformIntoOutgoingPropertyEdgeList(statements, (Node) this));
}

/**
* Adds the specified statement to this statement holder. The statements have to be stored as a
* list of statements as we try to avoid adding new AST-nodes that do not exist, e.g. a code body
* to hold statements
*
* @param s the statement
*/
default void addStatement(Statement s) {
PropertyEdge<Statement> propertyEdge = new PropertyEdge<>((Node) this, s);
propertyEdge.addProperty(Properties.INDEX, getStatementEdges().size());
getStatementEdges().add(propertyEdge);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
package de.fraunhofer.aisec.cpg.graph.declarations;

import de.fraunhofer.aisec.cpg.graph.DeclarationHolder;
import de.fraunhofer.aisec.cpg.graph.StatementHolder;
import de.fraunhofer.aisec.cpg.graph.SubGraph;
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge;
import de.fraunhofer.aisec.cpg.graph.statements.Statement;
import de.fraunhofer.aisec.cpg.helpers.Util;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -35,6 +38,7 @@
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.NotNull;
import org.neo4j.ogm.annotation.Relationship;

/**
* Declares the scope of a namespace and appends its own name to the current namespace-prefix to
Expand All @@ -46,14 +50,20 @@
* semantical difference between NamespaceDeclaration and {@link RecordDeclaration} lies in the
* non-instantiabillity of a namespace.
*/
public class NamespaceDeclaration extends Declaration implements DeclarationHolder {
public class NamespaceDeclaration extends Declaration
implements DeclarationHolder, StatementHolder {

/**
* Edges to nested namespaces, records, functions, fields etc. contained in the current namespace.
*/
@SubGraph("AST")
private List<Declaration> declarations = new ArrayList<>();

/** The list of statements. */
@Relationship(value = "STATEMENTS", direction = "OUTGOING")
@NonNull
private @SubGraph("AST") List<PropertyEdge<Statement>> statements = new ArrayList<>();

public List<FieldDeclaration> getFields() {
return Util.filterCast(declarations, FieldDeclaration.class);
}
Expand Down Expand Up @@ -98,6 +108,16 @@ public <T> T getDeclarationAs(int i, Class<T> clazz) {
return clazz.cast(getDeclarations().get(i));
}

@Override
public @NonNull List<PropertyEdge<Statement>> getStatementEdges() {
return this.statements;
}

@Override
public void setStatementEdges(@NonNull List<PropertyEdge<Statement>> statements) {
this.statements = statements;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@

import de.fraunhofer.aisec.cpg.graph.DeclarationHolder;
import de.fraunhofer.aisec.cpg.graph.Node;
import de.fraunhofer.aisec.cpg.graph.StatementHolder;
import de.fraunhofer.aisec.cpg.graph.SubGraph;
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge;
import de.fraunhofer.aisec.cpg.graph.statements.Statement;
import de.fraunhofer.aisec.cpg.graph.types.Type;
import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -43,7 +45,7 @@
import org.neo4j.ogm.annotation.Transient;

/** Represents a C++ union/struct/class or Java class */
public class RecordDeclaration extends Declaration implements DeclarationHolder {
public class RecordDeclaration extends Declaration implements DeclarationHolder, StatementHolder {

/** The kind, i.e. struct, class, union or enum. */
private String kind;
Expand All @@ -68,6 +70,11 @@ public class RecordDeclaration extends Declaration implements DeclarationHolder
@SubGraph("AST")
private List<PropertyEdge<TemplateDeclaration>> templates = new ArrayList<>();

/** The list of statements. */
@Relationship(value = "STATEMENTS", direction = "OUTGOING")
@NonNull
private @SubGraph("AST") List<PropertyEdge<Statement>> statements = new ArrayList<>();

@Transient private List<Type> superClasses = new ArrayList<>();
@Transient private List<Type> implementedInterfaces = new ArrayList<>();

Expand Down Expand Up @@ -300,6 +307,16 @@ public void setStaticImportStatements(List<String> staticImportStatements) {
this.staticImportStatements = staticImportStatements;
}

@Override
public @NonNull List<PropertyEdge<Statement>> getStatementEdges() {
return this.statements;
}

@Override
public void setStatementEdges(@NonNull List<PropertyEdge<Statement>> statements) {
this.statements = statements;
}

@Override
public String toString() {
return new ToStringBuilder(this, Node.TO_STRING_STYLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@

import de.fraunhofer.aisec.cpg.graph.DeclarationHolder;
import de.fraunhofer.aisec.cpg.graph.Node;
import de.fraunhofer.aisec.cpg.graph.StatementHolder;
import de.fraunhofer.aisec.cpg.graph.SubGraph;
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge;
import de.fraunhofer.aisec.cpg.graph.statements.Statement;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.builder.ToStringBuilder;
Expand All @@ -40,7 +42,8 @@
import org.neo4j.ogm.annotation.Relationship;

/** The top most declaration, representing a translation unit, for example a file. */
public class TranslationUnitDeclaration extends Declaration implements DeclarationHolder {
public class TranslationUnitDeclaration extends Declaration
implements DeclarationHolder, StatementHolder {

/** A list of declarations within this unit. */
@Relationship(value = "DECLARATIONS", direction = "OUTGOING")
Expand All @@ -60,6 +63,11 @@ public class TranslationUnitDeclaration extends Declaration implements Declarati
@NonNull
private List<PropertyEdge<Declaration>> namespaces = new ArrayList<>();

/** The list of statements. */
@Relationship(value = "STATEMENTS", direction = "OUTGOING")
@NonNull
private @SubGraph("AST") List<PropertyEdge<Statement>> statements = new ArrayList<>();

/**
* Returns the i-th declaration as a specific class, if it can be cast
*
Expand Down Expand Up @@ -150,6 +158,16 @@ public void addDeclaration(@NonNull Declaration declaration) {
addIfNotContains(declarations, declaration);
}

@Override
public @NonNull List<PropertyEdge<Statement>> getStatementEdges() {
return this.statements;
}

@Override
public void setStatementEdges(@NonNull List<PropertyEdge<Statement>> statements) {
this.statements = statements;
}

@Override
public String toString() {
return new ToStringBuilder(this, Node.TO_STRING_STYLE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
package de.fraunhofer.aisec.cpg.graph.statements;

import de.fraunhofer.aisec.cpg.graph.Node;
import de.fraunhofer.aisec.cpg.graph.StatementHolder;
import de.fraunhofer.aisec.cpg.graph.SubGraph;
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration;
import de.fraunhofer.aisec.cpg.graph.edge.Properties;
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.builder.ToStringBuilder;
Expand All @@ -42,40 +41,38 @@
* A statement which contains a list of statements. A common example is a function body within a
* {@link FunctionDeclaration}.
*/
public class CompoundStatement extends Statement {
public class CompoundStatement extends Statement implements StatementHolder {

/** The list of statements. */
@Relationship(value = "STATEMENTS", direction = "OUTGOING")
@NonNull
private @SubGraph("AST") List<PropertyEdge<Statement>> statements = new ArrayList<>();

@NonNull
public List<Statement> getStatements() {
List<Statement> targets = new ArrayList<>();
for (PropertyEdge<Statement> propertyEdge : this.statements) {
targets.add(propertyEdge.getEnd());
}
return Collections.unmodifiableList(targets);
}
/**
* This variable helps to differentiate between static and non static initializer blocks. Static
* initializer blocks are executed when the enclosing declaration is first referred to, e.g.
* loaded into the jvm or parsed. Non static initializers are executed on Record construction.
*
* <p>If a compound statement is part of a method body, this notion is not relevant.
*/
private boolean staticBlock = false;

@NonNull
public List<PropertyEdge<Statement>> getStatementsPropertyEdge() {
@Override
public @NonNull List<PropertyEdge<Statement>> getStatementEdges() {
return this.statements;
}

public void setStatements(@NonNull List<Statement> statements) {
this.statements = PropertyEdge.transformIntoOutgoingPropertyEdgeList(statements, this);
@Override
public void setStatementEdges(@NonNull List<PropertyEdge<Statement>> statements) {
this.statements = statements;
}

@NonNull
public List<PropertyEdge<Statement>> getStatementEdges() {
return this.statements;
public boolean isStaticBlock() {
return staticBlock;
}

public void addStatement(Statement s) {
PropertyEdge<Statement> propertyEdge = new PropertyEdge<>(this, s);
propertyEdge.addProperty(Properties.INDEX, this.statements.size());
this.statements.add(propertyEdge);
public void setStaticBlock(boolean staticBlock) {
this.staticBlock = staticBlock;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private void removeValues(ControlFlowSensitiveDFGPass.FunctionLevelFixpointItera
* @param node every node in the TranslationResult
*/
public void handle(Node node) {
if (node instanceof FunctionDeclaration) {
if (node instanceof FunctionDeclaration || node instanceof StatementHolder) {
ControlFlowSensitiveDFGPass.FunctionLevelFixpointIterator flfIterator =
new ControlFlowSensitiveDFGPass.FunctionLevelFixpointIterator();
flfIterator.handle(node);
Expand Down
Loading

0 comments on commit d420449

Please sign in to comment.