Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add support for Java super invocations #106

Merged
merged 9 commits into from
Jun 18, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
import de.fraunhofer.aisec.cpg.graph.type.UnknownType;
import de.fraunhofer.aisec.cpg.passes.scopes.Scope;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.eclipse.cdt.core.dom.ast.*;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
Expand Down Expand Up @@ -206,27 +207,17 @@ private RecordDeclaration handleCompositeTypeSpecifier(CPPASTCompositeTypeSpecif
RecordDeclaration recordDeclaration =
NodeBuilder.newRecordDeclaration(
lang.getScopeManager().getCurrentNamePrefixWithDelimiter() + ctx.getName().toString(),
new ArrayList<>(),
kind,
ctx.getRawSignature());
recordDeclaration.setSuperClasses(
Arrays.stream(ctx.getBaseSpecifiers())
.map(b -> TypeParser.createFrom(b.getNameSpecifier().toString(), true))
.collect(Collectors.toList()));

this.lang.addRecord(recordDeclaration);

lang.getScopeManager().enterScope(recordDeclaration);

if (kind.equals("class")) {
de.fraunhofer.aisec.cpg.graph.FieldDeclaration thisDeclaration =
NodeBuilder.newFieldDeclaration(
"this",
TypeParser.createFrom(ctx.getName().toString(), true),
new ArrayList<>(),
"this",
null,
null,
true);
recordDeclaration.getFields().add(thisDeclaration);
lang.getScopeManager().addValueDeclaration(thisDeclaration);
}
lang.getScopeManager().addValueDeclaration(recordDeclaration.getThis());

for (IASTDeclaration member : ctx.getMembers()) {
if (member instanceof CPPASTVisibilityLabel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DeclarationHandler
extends Handler<Declaration, BodyDeclaration, JavaLanguageFrontend> {
Expand Down Expand Up @@ -210,15 +209,22 @@ public RecordDeclaration handleClassOrInterfaceDeclaration(
// }
name = getAbsoluteName(name);

List<Type> superTypes =
Stream.of(classInterDecl.getExtendedTypes(), classInterDecl.getImplementedTypes())
.flatMap(Collection::stream)
.map(this.lang::getTypeAsGoodAsPossible)
.collect(Collectors.toList());

// add a type declaration
RecordDeclaration recordDeclaration =
NodeBuilder.newRecordDeclaration(name, superTypes, "class", classInterDecl.toString());
NodeBuilder.newRecordDeclaration(name, "class", classInterDecl.toString());
recordDeclaration.setSuperClasses(
classInterDecl.getExtendedTypes().stream()
.map(this.lang::getTypeAsGoodAsPossible)
.collect(Collectors.toList()));
if (recordDeclaration.getSuperClasses().isEmpty()) {
List<Type> superClasses = new ArrayList<>();
superClasses.add(TypeParser.createFrom(Object.class.getName(), true));
recordDeclaration.setSuperClasses(superClasses);
}
recordDeclaration.setImplementedInterfaces(
classInterDecl.getImplementedTypes().stream()
.map(this.lang::getTypeAsGoodAsPossible)
.collect(Collectors.toList()));

Map<Boolean, List<String>> partitioned =
this.lang.getContext().getImports().stream()
Expand All @@ -240,18 +246,7 @@ public RecordDeclaration handleClassOrInterfaceDeclaration(

this.lang.addRecord(recordDeclaration);
lang.getScopeManager().enterScope(recordDeclaration);

de.fraunhofer.aisec.cpg.graph.FieldDeclaration thisDeclaration =
NodeBuilder.newFieldDeclaration(
"this",
TypeParser.createFrom(name, true),
new ArrayList<>(),
"this",
null,
null,
false);
recordDeclaration.getFields().add(thisDeclaration);
lang.getScopeManager().addValueDeclaration(thisDeclaration);
lang.getScopeManager().addValueDeclaration(recordDeclaration.getThis());

// TODO: 'this' identifier for multiple instances?
for (BodyDeclaration<?> decl : classInterDecl.getMembers()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public ExpressionHandler(JavaLanguageFrontend lang) {
map.put(LiteralExpr.class, this::handleLiteralExpression);

map.put(ThisExpr.class, this::handleThisExpression);
map.put(SuperExpr.class, this::handleSuperExpression);
map.put(ClassExpr.class, this::handleClassExpression);
map.put(NameExpr.class, this::handleNameExpression);
map.put(InstanceOfExpr.class, this::handleInstanceOfExpression);
Expand Down Expand Up @@ -432,6 +433,18 @@ private DeclaredReferenceExpression handleThisExpression(Expression expr) {
return thisExpression;
}

private DeclaredReferenceExpression handleSuperExpression(Expression expr) {
// The actual type is hard to determine at this point, as we may not have full information
// about the inheritance structure. Thus we delay the resolving to the variable resolving
// process
DeclaredReferenceExpression superExpression =
NodeBuilder.newDeclaredReferenceExpression(
expr.toString(), UnknownType.getUnknownType(), expr.toString());
lang.setCodeAndRegion(superExpression, expr);

return superExpression;
}

// TODO: this function needs a MAJOR overhaul!
private de.fraunhofer.aisec.cpg.graph.Expression handleNameExpression(Expression expr) {
NameExpr nameExpr = expr.asNameExpr();
Expand Down Expand Up @@ -618,6 +631,9 @@ private CallExpression handleMethodCallExpression(Expression expr) {
scopeName = ((NameExpr) scope).getNameAsString();
((NameExpr) scope).resolve();
isresolvable = true;
} else if (scope instanceof SuperExpr) {
scopeName = scope.toString();
isresolvable = true;
}
} catch (UnsolvedSymbolException ex) {
if (!ex.getName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ protected CompilationUnit parse(File file, JavaParser parser)
}
log.error(sb.toString());
});
log.error("Could not parse the file correctly! AST may be empty");
log.error("Could not parse the file {} correctly! AST may be empty", file);
}
return optional.get();
}
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
package de.fraunhofer.aisec.cpg.graph;

import de.fraunhofer.aisec.cpg.graph.type.Type;
import de.fraunhofer.aisec.cpg.graph.type.TypeParser;
import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -395,14 +397,25 @@ public static TranslationUnitDeclaration newTranslationUnitDeclaration(String na
return node;
}

public static RecordDeclaration newRecordDeclaration(
String name, List<Type> superTypes, String kind, String code) {
public static RecordDeclaration newRecordDeclaration(String name, String kind, String code) {
RecordDeclaration node = new RecordDeclaration();
node.setName(name);
node.setSuperTypes(superTypes);
node.setKind(kind);
node.setCode(code);

if (kind.equals("class")) {
de.fraunhofer.aisec.cpg.graph.FieldDeclaration thisDeclaration =
NodeBuilder.newFieldDeclaration(
"this",
TypeParser.createFrom(name, true),
new ArrayList<>(),
"this",
null,
null,
true);
node.getFields().add(thisDeclaration);
}

log(node);

return node;
Expand Down
46 changes: 41 additions & 5 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/RecordDeclaration.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@

import de.fraunhofer.aisec.cpg.graph.type.Type;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.neo4j.ogm.annotation.Transient;

/** Represents a C++ union/struct/class or Java class */
public class RecordDeclaration extends Declaration {
Expand All @@ -49,7 +52,8 @@ public class RecordDeclaration extends Declaration {
@SubGraph("AST")
private List<RecordDeclaration> records = new ArrayList<>();

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

@org.neo4j.ogm.annotation.Relationship
private Set<RecordDeclaration> superTypeDeclarations = new HashSet<>();
Expand Down Expand Up @@ -115,12 +119,43 @@ public void setRecords(List<RecordDeclaration> records) {
this.records = records;
}

/**
* Combines both implemented interfaces and extended classes. This is most commonly what you are
* looking for when looking for method call targets etc.
*
* @return concatenation of {@link #getSuperClasses()} and {@link #getImplementedInterfaces()}
*/
public List<Type> getSuperTypes() {
return superTypes;
return Stream.of(superClasses, implementedInterfaces)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}

public void setSuperTypes(List<Type> superTypes) {
this.superTypes = superTypes;
/**
* The classes that are extended by this one. Usually zero or one, but in C++ this can contain
* multiple classes
*
* @return extended classes
*/
public List<Type> getSuperClasses() {
return superClasses;
}

public void setSuperClasses(List<Type> superClasses) {
this.superClasses = superClasses;
}

/**
* Interfaces implemented by this class. This concept is not present in C++
*
* @return the list of implemented interfaces
*/
public List<Type> getImplementedInterfaces() {
return implementedInterfaces;
}

public void setImplementedInterfaces(List<Type> implementedInterfaces) {
this.implementedInterfaces = implementedInterfaces;
}

public Set<RecordDeclaration> getSuperTypeDeclarations() {
Expand Down Expand Up @@ -192,7 +227,8 @@ public boolean equals(Object o) {
&& Objects.equals(methods, that.methods)
&& Objects.equals(constructors, that.constructors)
&& Objects.equals(records, that.records)
&& Objects.equals(superTypes, that.superTypes)
&& Objects.equals(superClasses, that.superClasses)
&& Objects.equals(implementedInterfaces, that.implementedInterfaces)
&& Objects.equals(superTypeDeclarations, that.superTypeDeclarations);
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/TypeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ public Language getLanguage() {
}
}

public LanguageFrontend getFrontend() {
return frontend;
}

public boolean isSupertypeOf(Type superType, Type subType) {
if (superType.getReferenceDepth() != subType.getReferenceDepth()) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ public static void setLanguage(TypeManager.Language language) {
}

public static TypeManager.Language getLanguage() {
return language;
if (TypeManager.getInstance().getFrontend() == null) {
return language;
}
return TypeManager.getInstance().getLanguage();
}

/**
Expand Down
Loading