Skip to content

Commit

Permalink
Merge pull request #164 from Fraunhofer-AISEC/annotations
Browse files Browse the repository at this point in the history
Support for C++ attributes as annotations
  • Loading branch information
oxisto committed Jul 22, 2020
2 parents 16c9e27 + 7cd23ad commit 6af6499
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ public class TranslationConfiguration {
/** should the code of a node be shown as parameter in the node * */
public final boolean codeInNodes;

/** Set to true to process annotations or annotation-like elements. */
public final boolean processAnnotations;

/**
* Should parser/translation fail on parse/resolving errors (true) or try to continue in a
* best-effort manner (false).
Expand Down Expand Up @@ -112,6 +115,7 @@ private TranslationConfiguration(
List<String> includeBlacklist,
List<Pass> passes,
boolean codeInNodes,
boolean processAnnotations,
boolean disableCleanup) {
this.symbols = symbols;
this.sourceLocations = sourceLocations;
Expand All @@ -125,6 +129,7 @@ private TranslationConfiguration(
this.passes = passes != null ? passes : new ArrayList<>();
// Make sure to init this AFTER sourceLocations has been set
this.codeInNodes = codeInNodes;
this.processAnnotations = processAnnotations;
this.disableCleanup = disableCleanup;
}

Expand Down Expand Up @@ -170,11 +175,12 @@ public static class Builder {
private boolean failOnError = false;
private boolean loadIncludes = false;
private Map<String, String> symbols = new HashMap<>();
private List<String> includePaths = new ArrayList<>();
private List<String> includeWhitelist = new ArrayList<>();
private List<String> includeBlacklist = new ArrayList<>();
private List<Pass> passes = new ArrayList<>();
private final List<String> includePaths = new ArrayList<>();
private final List<String> includeWhitelist = new ArrayList<>();
private final List<String> includeBlacklist = new ArrayList<>();
private final List<Pass> passes = new ArrayList<>();
private boolean codeInNodes = true;
private boolean processAnnotations = false;
private boolean disableCleanup = false;

public Builder symbols(Map<String, String> symbols) {
Expand Down Expand Up @@ -329,6 +335,18 @@ public Builder codeInNodes(boolean b) {
return this;
}

/**
* Specifies, whether annotations should be process or not. By default, they are not processed,
* since they might populate the graph too much.
*
* @param b the new value
* @return
*/
public Builder processAnnotations(boolean b) {
this.processAnnotations = b;
return this;
}

public TranslationConfiguration build() {
return new TranslationConfiguration(
symbols,
Expand All @@ -342,6 +360,7 @@ public TranslationConfiguration build() {
includeBlacklist,
passes,
codeInNodes,
processAnnotations,
disableCleanup);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,24 @@

package de.fraunhofer.aisec.cpg.frontends.cpp;

import static de.fraunhofer.aisec.cpg.graph.NodeBuilder.newAnnotation;
import static de.fraunhofer.aisec.cpg.graph.NodeBuilder.newDeclaredReferenceExpression;
import static de.fraunhofer.aisec.cpg.graph.NodeBuilder.newLiteral;

import de.fraunhofer.aisec.cpg.TranslationConfiguration;
import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend;
import de.fraunhofer.aisec.cpg.frontends.TranslationException;
import de.fraunhofer.aisec.cpg.graph.Annotation;
import de.fraunhofer.aisec.cpg.graph.Declaration;
import de.fraunhofer.aisec.cpg.graph.DeclaredReferenceExpression;
import de.fraunhofer.aisec.cpg.graph.Expression;
import de.fraunhofer.aisec.cpg.graph.Node;
import de.fraunhofer.aisec.cpg.graph.TranslationUnitDeclaration;
import de.fraunhofer.aisec.cpg.graph.TypeManager;
import de.fraunhofer.aisec.cpg.graph.ValueDeclaration;
import de.fraunhofer.aisec.cpg.graph.type.Type;
import de.fraunhofer.aisec.cpg.graph.type.TypeParser;
import de.fraunhofer.aisec.cpg.graph.type.UnknownType;
import de.fraunhofer.aisec.cpg.helpers.Benchmark;
import de.fraunhofer.aisec.cpg.passes.scopes.ScopeManager;
import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation;
Expand Down Expand Up @@ -308,7 +315,6 @@ public <T> String getCodeFromRawNode(T astNode) {

@Nullable
@Override
@SuppressWarnings("ConstantConditions")
public <T> PhysicalLocation getLocationFromRawNode(T astNode) {
if (astNode instanceof ASTNode) {
ASTNode node = (ASTNode) astNode;
Expand Down Expand Up @@ -372,6 +378,71 @@ public <T> PhysicalLocation getLocationFromRawNode(T astNode) {
return null;
}

/**
* Processes C++ attributes into {@link Annotation} nodes.
*
* @param node the node to process
* @param owner the AST node which holds the attribute
*/
public void processAttributes(@NonNull Node node, @NonNull IASTAttributeOwner owner) {
if (this.config.processAnnotations) {
// set attributes
node.setAnnotations(handleAttributes(owner));
}
}

private List<Annotation> handleAttributes(IASTAttributeOwner owner) {
List<Annotation> list = new ArrayList<>();

for (IASTAttribute attribute : owner.getAttributes()) {
Annotation annotation =
newAnnotation(new String(attribute.getName()), attribute.getRawSignature());

// go over the parameters
if (attribute.getArgumentClause() instanceof IASTTokenList) {
List<Expression> values = handleTokenList((IASTTokenList) attribute.getArgumentClause());

annotation.setValues(values);
}

list.add(annotation);
}

return list;
}

private List<Expression> handleTokenList(IASTTokenList tokenList) {
List<Expression> list = new ArrayList<>();

for (IASTToken token : tokenList.getTokens()) {
if (token.getTokenType() == 6) {
continue;
}

list.add(handleToken(token));
}

return list;
}

private Expression handleToken(IASTToken token) {
String code = new String(token.getTokenCharImage());

switch (token.getTokenType()) {
case 1:
return newDeclaredReferenceExpression(code, UnknownType.getUnknownType(), code);
case 2:
return newLiteral(Integer.parseInt(code), CXXLanguageFrontend.INT_TYPE, code);
case 130:
return newLiteral(
code.length() >= 2 ? code.substring(1, code.length() - 1) : "",
TypeParser.createFrom("const char*", false),
code);
default:
return newLiteral(code, TypeParser.createFrom("const char*", false), code);
}
}

private Field getField(Class<?> type, String fieldName) throws NoSuchFieldException {
try {
return type.getDeclaredField(fieldName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ private FunctionDeclaration handleFunctionDefinition(CPPASTFunctionDefinition ct
}
}

this.lang.processAttributes(functionDeclaration, ctx);

lang.getScopeManager().leaveScope(functionDeclaration);

if (recordDeclaration != null) {
Expand Down Expand Up @@ -220,13 +222,20 @@ private Declaration handleSimpleDeclaration(CPPASTSimpleDeclaration ctx) {
}
}

Declaration declaration;
if (ctx.getDeclarators().length == 0) {
return handleNoDeclarator(ctx);
declaration = handleNoDeclarator(ctx);
} else if (ctx.getDeclarators().length == 1) {
return handleSingleDeclarator(ctx);
declaration = handleSingleDeclarator(ctx);
} else {
return handleMultipleDeclarators(ctx);
declaration = handleMultipleDeclarators(ctx);
}

if (declaration != null) {
this.lang.processAttributes(declaration, ctx);
}

return declaration;
}

private Declaration handleNoDeclarator(CPPASTSimpleDeclaration ctx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ private List<Declaration> handleSimpleDeclaration(CPPASTSimpleDeclaration ctx) {
// cache binding
this.lang.cacheDeclaration(declarator.getName().resolveBinding(), declaration);

// process attributes
this.lang.processAttributes(declaration, ctx);

list.add(declaration);
}

Expand Down
62 changes: 62 additions & 0 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/Annotation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2020, 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 java.util.List;
import java.util.Objects;

public class Annotation extends Node {

// should be extended later into annotation members
private List<Expression> values;

public List<Expression> getValues() {
return values;
}

public void setValues(List<Expression> values) {
this.values = values;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Annotation)) {
return false;
}

Annotation that = (Annotation) o;
return super.equals(that) && Objects.equals(values, that.values);
}

@Override
public int hashCode() {
return super.hashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static ConstructorDeclaration from(MethodDeclaration methodDeclaration) {
c.setBody(methodDeclaration.getBody());
c.setLocation(methodDeclaration.getLocation());
c.setParameters(methodDeclaration.getParameters());
c.setAnnotations(methodDeclaration.getAnnotations());

return c;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ private FieldDeclaration(VariableDeclaration declaration) {
this.location = declaration.getLocation();
this.type = declaration.getType();
this.initializer = declaration.getInitializer();
this.annotations = declaration.getAnnotations();
}

public static FieldDeclaration from(VariableDeclaration declaration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static MethodDeclaration from(
md.setParameters(functionDeclaration.getParameters());
md.setBody(functionDeclaration.getBody());
md.setType(functionDeclaration.getType());
md.setAnnotations(functionDeclaration.getAnnotations());
md.setRecordDeclaration(recordDeclaration);

return md;
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ public class Node extends IVisitable<Node> {
/** Index of the argument if this node is used in a function call or parameter list. */
private int argumentIndex;

/** List of annotations associated with that node. */
@SubGraph("AST")
protected List<Annotation> annotations;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -322,4 +326,12 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(name, this.getClass());
}

public void setAnnotations(List<Annotation> annotations) {
this.annotations = annotations;
}

public List<Annotation> getAnnotations() {
return annotations;
}
}
8 changes: 8 additions & 0 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -695,4 +695,12 @@ public static CompoundStatementExpression newCompoundStatementExpression(@NonNul
cse.setCode(code);
return cse;
}

public static Annotation newAnnotation(String name, @NonNull String code) {
Annotation annotation = new Annotation();
annotation.setName(name);
annotation.setCode(code);

return annotation;
}
}
Loading

0 comments on commit 6af6499

Please sign in to comment.