Skip to content

Commit

Permalink
Merge pull request #45 from IBM/add-private-method-info-to-callsite-o…
Browse files Browse the repository at this point in the history
…bject

Add callee method's access specifier information to caller's callsite object
  • Loading branch information
rahlk authored Jul 24, 2024
2 parents c13ae69 + 2691303 commit b38d6dc
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 20 deletions.
21 changes: 18 additions & 3 deletions src/main/java/com/ibm/northstar/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.Problem;
import com.github.javaparser.ast.AccessSpecifier;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.*;
Expand All @@ -12,6 +13,7 @@
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.type.ReferenceType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
Expand Down Expand Up @@ -498,12 +500,21 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
Log.debug("Could not resolve method call: " + methodCallExpr + ": " + exception.getMessage());
}

// Resolve access qualifier
AccessSpecifier accessSpecifier = AccessSpecifier.NONE;
try {
ResolvedMethodDeclaration resolvedMethodDeclaration = methodCallExpr.resolve();
accessSpecifier = resolvedMethodDeclaration.accessSpecifier();
}
catch (RuntimeException exception) {
Log.debug("Could not resolve access specifier for method call: " + methodCallExpr + ": " + exception.getMessage());
}
// resolve arguments of the method call to types
List<String> arguments = methodCallExpr.getArguments().stream()
.map(SymbolTable::resolveExpression).collect(Collectors.toList());
// add a new call site object
callSites.add(createCallSite(methodCallExpr, methodCallExpr.getNameAsString(), receiverName, declaringType,
arguments, returnType, calleeSignature, isStaticCall, false));
arguments, returnType, calleeSignature, isStaticCall, false, accessSpecifier));
}

for (ObjectCreationExpr objectCreationExpr : callableBody.get().findAll(ObjectCreationExpr.class)) {
Expand All @@ -525,7 +536,7 @@ 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));
instantiatedType, arguments, instantiatedType, calleeSignature,false, true, AccessSpecifier.NONE));
}

return callSites;
Expand All @@ -546,7 +557,7 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
*/
private static CallSite createCallSite(Expression callExpr, String calleeName, String receiverExpr,
String receiverType, List<String> arguments, String returnType,
String calleeSignature, boolean isStaticCall, boolean isConstructorCall) {
String calleeSignature, boolean isStaticCall, boolean isConstructorCall, AccessSpecifier accessSpecifier) {
CallSite callSite = new CallSite();
callSite.setMethodName(calleeName);
callSite.setReceiverExpr(receiverExpr);
Expand All @@ -556,6 +567,10 @@ private static CallSite createCallSite(Expression callExpr, String calleeName, S
callSite.setCalleeSignature(calleeSignature);
callSite.setStaticCall(isStaticCall);
callSite.setConstructorCall(isConstructorCall);
callSite.setPrivate(accessSpecifier.equals(AccessSpecifier.PRIVATE));
callSite.setPublic(accessSpecifier.equals(AccessSpecifier.PUBLIC));
callSite.setProtected(accessSpecifier.equals(AccessSpecifier.PROTECTED));
callSite.setUnspecified(accessSpecifier.equals(AccessSpecifier.NONE));
if (callExpr.getRange().isPresent()) {
callSite.setStartLine(callExpr.getRange().get().begin.line);
callSite.setStartColumn(callExpr.getRange().get().begin.column);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/ibm/northstar/entities/CallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class CallSite {
private List<String> argumentTypes;
private String returnType;
private String calleeSignature;
// Access specifiers
private boolean isPublic = false;
private boolean isProtected = false;
private boolean isPrivate = false;
private boolean isUnspecified = false;
private boolean isStaticCall;
private boolean isConstructorCall;
private int startLine;
Expand Down
71 changes: 54 additions & 17 deletions src/main/java/com/ibm/northstar/utils/BuildProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

import static com.ibm.northstar.utils.ProjectDirectoryScanner.classFilesStream;
Expand All @@ -17,6 +18,31 @@ public class BuildProject {
private static final String LIB_DEPS_DOWNLOAD_DIR = "_library_dependencies";
private static final String MAVEN_CMD = System.getProperty("os.name").toLowerCase().contains("windows") ? "mvn.cmd" : "mvn";
private static final String GRADLE_CMD = System.getProperty("os.name").toLowerCase().contains("windows") ? "gradlew.bat" : "gradlew";
public static Path tempInitScript;
static {
try {
tempInitScript = Files.createTempFile("gradle-init-", ".gradle");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static final String GRADLE_DEPENDENCIES_TASK = "allprojects { afterEvaluate { project -> task downloadDependencies(type: Copy) {\n" +
" def configs = project.configurations.findAll { it.canBeResolved }\n\n" +
" dependsOn configs\n" +
" from configs\n" +
" into project.hasProperty('outputDir') ? project.property('outputDir') : \"${project.buildDir}/libs\"\n\n" +
" doFirst {\n" +
" println \"Downloading dependencies for project ${project.name} to: ${destinationDir}\"\n" +
" configs.each { config ->\n" +
" println \"Configuration: ${config.name}\"\n" +
" config.resolvedConfiguration.resolvedArtifacts.each { artifact ->\n" +
" println \"\t${artifact.moduleVersion.id}:${artifact.extension}\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";

private static boolean buildWithTool(String[] buildCommand) {
Log.info("Building the project using " + buildCommand[0] + ".");
Expand All @@ -30,6 +56,7 @@ private static boolean buildWithTool(String[] buildCommand) {
Log.info(line);
}
int exitCode = process.waitFor();
process.getErrorStream().transferTo(System.err);
Log.info(buildCommand[0].toUpperCase() + " build exited with code " + exitCode);
return exitCode == 0;
} catch (IOException | InterruptedException e) {
Expand Down Expand Up @@ -73,24 +100,24 @@ private static boolean mavenBuild(String projectPath) {
return false;
}
String[] mavenCommand = {
MAVEN_CMD, "clean", "compile", "-f", projectPath + "/pom.xml", "-B", "-V", "-e", "-Drat.skip",
"-Dfindbugs.skip", "-Dcheckstyle.skip", "-Dpmd.skip=true", "-Dspotbugs.skip", "-Denforcer.skip",
"-Dmaven.javadoc.skip", "-DskipTests", "-Dmaven.test.skip.exec", "-Dlicense.skip=true",
"-Drat.skip=true", "-Dspotless.check.skip=true" };
MAVEN_CMD, "clean", "compile", "-f", projectPath + "/pom.xml", "-B", "-V", "-e", "-Drat.skip",
"-Dfindbugs.skip", "-Dcheckstyle.skip", "-Dpmd.skip=true", "-Dspotbugs.skip", "-Denforcer.skip",
"-Dmaven.javadoc.skip", "-DskipTests", "-Dmaven.test.skip.exec", "-Dlicense.skip=true",
"-Drat.skip=true", "-Dspotless.check.skip=true"};

return buildWithTool(mavenCommand);
}

public static boolean gradleBuild(String projectPath) {
// Adjust Gradle command as needed
String gradleWrapper = projectPath + File.separator + GRADLE_CMD;
String[] gradleCommand = { gradleWrapper, "clean", "compileJava", "-p", projectPath };
String[] gradleCommand = {gradleWrapper, "clean", "compileJava", "-p", projectPath};
return buildWithTool(gradleCommand);
}

private static boolean buildProject(String projectPath, String build) {
File pomFile = new File(projectPath, "pom.xml");
if (build ==null) {
if (build == null) {
return true;
} else if (build.equals("auto")) {
if (pomFile.exists()) {
Expand All @@ -100,8 +127,7 @@ private static boolean buildProject(String projectPath, String build) {
Log.info("Did not find a pom.xml in the project directory. Using Gradle to build the project.");
return gradleBuild(projectPath); // Otherwise, use Gradle
}
}
else {
} else {
// Update command with a project path
build = build.replace(MAVEN_CMD, MAVEN_CMD + " -f " + projectPath);
Log.info("Using custom build command: " + build);
Expand All @@ -127,31 +153,35 @@ public static List<Path> buildProjectAndStreamClassFiles(String projectPath, Str
* @param projectPath Path to the project under analysis
* @return true if dependency download succeeds; false otherwise
*/
public static boolean downloadLibraryDependencies(String projectPath) {
public static boolean downloadLibraryDependencies(String projectPath) throws IOException {
// created download dir if it does not exist
libDownloadPath = Paths.get(projectPath, LIB_DEPS_DOWNLOAD_DIR).toAbsolutePath();
if (!Files.exists(libDownloadPath)) {
try {
Files.createDirectory(libDownloadPath);
} catch (IOException e) {
Log.error("Error creating library dependency directory for " + projectPath + ": " +e.getMessage());
Log.error("Error creating library dependency directory for " + projectPath + ": " + e.getMessage());
return false;
}
}
File pomFile = new File(projectPath, "pom.xml");
if (pomFile.exists()) {
Log.info("Found pom.xml in the project directory. Using Maven to download dependencies.");
String[] mavenCommand = {
MAVEN_CMD, "--no-transfer-progress", "-f",
Paths.get(projectPath, "pom.xml").toString(),
"dependency:copy-dependencies",
"-DoutputDirectory=" + libDownloadPath.toString()
MAVEN_CMD, "--no-transfer-progress", "-f",
Paths.get(projectPath, "pom.xml").toString(),
"dependency:copy-dependencies",
"-DoutputDirectory=" + libDownloadPath.toString()
};
return buildWithTool(mavenCommand);
} else {
// TODO: implement for gradle
return false;
} else if (new File(projectPath, "build.gradle").exists() || new File(projectPath, "build.gradle.kts").exists()) {
Log.info("Found build.gradle[.kts] in the project directory. Using Gradle to download dependencies.");
tempInitScript = Files.writeString(tempInitScript, GRADLE_DEPENDENCIES_TASK);
String[] gradleCommand = {projectPath + File.separator + GRADLE_CMD, "--init-script", tempInitScript.toFile().getAbsolutePath(), "downloadDependencies", "-PoutputDir="+libDownloadPath.toString()};
System.out.println(Arrays.toString(gradleCommand));
return buildWithTool(gradleCommand);
}
return false;
}

public static void cleanLibraryDependencies() {
Expand All @@ -167,5 +197,12 @@ public static void cleanLibraryDependencies() {
Log.error("Error deleting library dependency directory: " + e.getMessage());
}
}
if (tempInitScript != null) {
try {
Files.delete(tempInitScript);
} catch (IOException e) {
Log.error("Error deleting temporary Gradle init script: " + e.getMessage());
}
}
}
}

0 comments on commit b38d6dc

Please sign in to comment.