Skip to content

Issue 100 capture database entries #110

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions .github/ISSUE_TEMPLATE/bug_report.md

This file was deleted.

24 changes: 0 additions & 24 deletions .github/ISSUE_TEMPLATE/feature_request.md

This file was deleted.

26 changes: 0 additions & 26 deletions .github/ISSUE_TEMPLATE/user_story.md

This file was deleted.

57 changes: 0 additions & 57 deletions .github/workflows/main.yml

This file was deleted.

2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
Copyright IBM Corporation 2023, 2024

Licensed under the Apache Public License 2.0, Version 2.0 (the "License");
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=2.1.0
version=2.2.0
1 change: 1 addition & 0 deletions src/main/java/com/ibm/cldk/CodeAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public class CodeAnalyzer implements Runnable {
public static Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.serializeNulls() // Fix for issue #108
.disableHtmlEscaping()
.create();

Expand Down
107 changes: 103 additions & 4 deletions src/main/java/com/ibm/cldk/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import com.github.javaparser.utils.SourceRoot;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import com.ibm.cldk.javaee.CRUDFinderFactory;
import com.ibm.cldk.javaee.utils.enums.CRUDOperationType;
import com.ibm.cldk.javaee.utils.enums.CRUDQueryType;
import com.ibm.cldk.entities.*;
import com.ibm.cldk.utils.Log;
import org.apache.commons.lang3.tuple.Pair;
Expand Down Expand Up @@ -409,6 +412,18 @@ private static Pair<String, Callable> processCallableDeclaration(CallableDeclara

callableNode.setAccessedFields(getAccessedFields(body, classFields, typeName));
callableNode.setCallSites(getCallSites(body));
callableNode.setCrudOperations(
callableNode.getCallSites().stream()
.map(CallSite::getCrudOperation)
.filter(Objects::nonNull)
.collect(Collectors.toList())
);
callableNode.setCrudQueries(
callableNode.getCallSites().stream()
.map(CallSite::getCrudQuery)
.filter(Objects::nonNull)
.collect(Collectors.toList())
);
callableNode.setVariableDeclarations(getVariableDeclarations(body));
callableNode.setCyclomaticComplexity(getCyclomaticComplexity(callableDecl));

Expand All @@ -420,16 +435,19 @@ private static boolean isEntryPointMethod(CallableDeclaration callableDecl) {
return isServletEntrypointMethod(callableDecl) || isJaxRsEntrypointMethod(callableDecl) || isSpringEntrypointMethod(callableDecl) | isStrutsEntryPointMethod(callableDecl);
}

@SuppressWarnings("unchecked")
private static boolean isServletEntrypointMethod(CallableDeclaration callableDecl) {
return ((NodeList<Parameter>) callableDecl.getParameters()).stream()
.anyMatch(parameter -> parameter.getType().asString().contains("HttpServletRequest") ||
parameter.getType().asString().contains("HttpServletResponse")) && callableDecl.getAnnotations().stream().anyMatch(a -> a.toString().contains("Override"));
}

@SuppressWarnings("unchecked")
private static boolean isJaxRsEntrypointMethod(CallableDeclaration callableDecl) {
return callableDecl.getAnnotations().stream().anyMatch(a -> a.toString().contains("POST") || a.toString().contains("PUT") || a.toString().contains("GET") || a.toString().contains("HEAD") || a.toString().contains("DELETE"));
}

@SuppressWarnings("unchecked")
private static boolean isSpringEntrypointMethod(CallableDeclaration callableDecl) {
return callableDecl.getAnnotations().stream().anyMatch(a ->
a.toString().contains("GetMapping") ||
Expand All @@ -455,10 +473,11 @@ private static boolean isSpringEntrypointMethod(CallableDeclaration callableDecl
);
}

@SuppressWarnings("unchecked")
private static boolean isStrutsEntryPointMethod(CallableDeclaration callableDecl) {
// First check if this method is in a Struts Action class
Optional<Node> parentNode = callableDecl.getParentNode();
if (!parentNode.isPresent() || !(parentNode.get() instanceof ClassOrInterfaceDeclaration)) {
if (parentNode.isEmpty() || !(parentNode.get() instanceof ClassOrInterfaceDeclaration)) {
return false;
}

Expand Down Expand Up @@ -631,6 +650,7 @@ private static List<String> getAccessedFields(Optional<BlockStmt> callableBody,
* @param callableBody callable to compute call-site information for
* @return list of call sites
*/
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType"})
private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
List<CallSite> callSites = new ArrayList<>();
if (callableBody.isEmpty()) {
Expand Down Expand Up @@ -680,8 +700,31 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
}
// resolve arguments of the method call to types
List<String> arguments = methodCallExpr.getArguments().stream().map(SymbolTable::resolveExpression).collect(Collectors.toList());
// Get argument string from the callsite
List<String> listOfArgumentStrings = methodCallExpr.getArguments().stream().map(Expression::toString).collect(Collectors.toList());
// Determine if this call site is potentially a CRUD operation.
CRUDOperation crudOperation = null;
Optional<CRUDOperationType> crudOperationType = findCRUDOperation(declaringType, methodCallExpr.getNameAsString());
if (crudOperationType.isPresent()) {
// We found a CRUD operation, so we need to populate the details of the call site this CRUD operation.
int lineNumber = methodCallExpr.getRange().isPresent() ? methodCallExpr.getRange().get().begin.line : -1;
crudOperation = new CRUDOperation();
crudOperation.setLineNumber(lineNumber);
crudOperation.setOperationType(crudOperationType.get());
}
// Determine if this call site is potentially a CRUD query.
CRUDQuery crudQuery = null;
Optional<CRUDQueryType> crudQueryType = findCRUDQuery(declaringType, methodCallExpr.getNameAsString(), Optional.of(listOfArgumentStrings));
if (crudQueryType.isPresent()) {
// We found a CRUD query, so we need to populate the details of the call site this CRUD query.
int lineNumber = methodCallExpr.getRange().isPresent() ? methodCallExpr.getRange().get().begin.line : -1;
crudQuery = new CRUDQuery();
crudQuery.setLineNumber(lineNumber);
crudQuery.setQueryType(crudQueryType.get());
crudQuery.setQueryArguments(listOfArgumentStrings);
}
// add a new call site object
callSites.add(createCallSite(methodCallExpr, methodCallExpr.getNameAsString(), receiverName, declaringType, arguments, returnType, calleeSignature, isStaticCall, false, accessSpecifier));
callSites.add(createCallSite(methodCallExpr, methodCallExpr.getNameAsString(), receiverName, declaringType, arguments, returnType, calleeSignature, isStaticCall, false, crudOperation, crudQuery, accessSpecifier));
}

for (ObjectCreationExpr objectCreationExpr : callableBody.get().findAll(ObjectCreationExpr.class)) {
Expand All @@ -700,11 +743,52 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
}

// add a new call site object
callSites.add(createCallSite(objectCreationExpr, "<init>", objectCreationExpr.getScope().isPresent() ? objectCreationExpr.getScope().get().toString() : "", instantiatedType, arguments, instantiatedType, calleeSignature, false, true, AccessSpecifier.NONE));
callSites.add(createCallSite(objectCreationExpr, "<init>", objectCreationExpr.getScope().isPresent() ? objectCreationExpr.getScope().get().toString() : "", instantiatedType, arguments, instantiatedType, calleeSignature, false, true, null, null, AccessSpecifier.NONE));
}

return callSites;
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static Optional<CRUDQueryType> findCRUDQuery(String declaringType, String nameAsString, Optional<List<String>> arguments) {
return CRUDFinderFactory.getCRUDFinders().map(
finder -> {
if (finder.isReadQuery(declaringType, nameAsString, arguments)) {
return CRUDQueryType.READ;
}
else if (finder.isWriteQuery(declaringType, nameAsString, arguments)) {
return CRUDQueryType.WRITE;
}
else if (finder.isNamedQuery(declaringType, nameAsString, arguments)) {
return CRUDQueryType.NAMED;
}
else
return null;
})
.filter(Objects::nonNull)
.findFirst();
}

private static Optional<CRUDOperationType> findCRUDOperation(String declaringType, String nameAsString) {
return CRUDFinderFactory.getCRUDFinders().map(
finder -> {
if (finder.isCreateOperation(declaringType, nameAsString)) {
return CRUDOperationType.CREATE;
}
else if (finder.isReadOperation(declaringType, nameAsString)) {
return CRUDOperationType.READ;
}
else if (finder.isUpdateOperation(declaringType, nameAsString)) {
return CRUDOperationType.UPDATE;
}
else if (finder.isDeleteOperation(declaringType, nameAsString)) {
return CRUDOperationType.DELETE;
}
else
return null;
})
.filter(Objects::nonNull)
.findFirst();
}

/**
* Creates and returns a new CallSite object for the given expression, which
Expand All @@ -719,7 +803,20 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
* @param isConstructorCall
* @return
*/
private static CallSite createCallSite(Expression callExpr, String calleeName, String receiverExpr, String receiverType, List<String> arguments, String returnType, String calleeSignature, boolean isStaticCall, boolean isConstructorCall, AccessSpecifier accessSpecifier) {
private static CallSite createCallSite(
Expression callExpr,
String calleeName,
String receiverExpr,
String receiverType,
List<String> arguments,
String returnType,
String calleeSignature,
boolean isStaticCall,
boolean isConstructorCall,
CRUDOperation crudOperation,
CRUDQuery crudQuery,
AccessSpecifier accessSpecifier
) {
CallSite callSite = new CallSite();
callSite.setMethodName(calleeName);
callSite.setReceiverExpr(receiverExpr);
Expand All @@ -733,6 +830,8 @@ private static CallSite createCallSite(Expression callExpr, String calleeName, S
callSite.setPublic(accessSpecifier.equals(AccessSpecifier.PUBLIC));
callSite.setProtected(accessSpecifier.equals(AccessSpecifier.PROTECTED));
callSite.setUnspecified(accessSpecifier.equals(AccessSpecifier.NONE));
callSite.setCrudOperation(crudOperation);
callSite.setCrudQuery(crudQuery);
if (callExpr.getRange().isPresent()) {
callSite.setStartLine(callExpr.getRange().get().begin.line);
callSite.setStartColumn(callExpr.getRange().get().begin.column);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/ibm/cldk/SystemDependencyGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public static List<Dependency> construct(
Log.done("There were a total of " + cha.getNumberOfClasses() + " classes of which "
+ AnalysisUtils.getNumberOfApplicationClasses(cha) + " are application classes.");

// Initialize analysis options
// Initialize javaee options
AnalysisOptions options = new AnalysisOptions();
Iterable<Entrypoint> entryPoints = AnalysisUtils.getEntryPoints(cha);
options.setEntrypoints(entryPoints);
Expand Down
Loading