Initial commit
This commit is contained in:
commit
266e5b7b6b
45 changed files with 1080 additions and 0 deletions
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
test-output/**
|
2
.idea/.gitignore
vendored
Normal file
2
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
19
.idea/libraries/asm_6_2_1.xml
Normal file
19
.idea/libraries/asm_6_2_1.xml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<component name="libraryTable">
|
||||||
|
<library name="asm-6.2.1">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-6.2.1.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-tree-6.2.1.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-util-6.2.1.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-6.2.1-javadoc.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-tree-6.2.1-javadoc.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-util-6.2.1-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-6.2.1-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-tree-6.2.1-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/asm-util-6.2.1-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
13
.idea/misc.xml
Normal file
13
.idea/misc.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ASMPluginConfiguration">
|
||||||
|
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
|
||||||
|
<groovy codeStyle="LEGACY" />
|
||||||
|
</component>
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_10" default="false" project-jdk-name="10" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/starter-lab-05-call-graph.iml" filepath="$PROJECT_DIR$/.idea/starter-lab-05-call-graph.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
14
.idea/sonarlint/issuestore/index.pb
Normal file
14
.idea/sonarlint/issuestore/index.pb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
a
|
||||||
|
1src/ch/usi/inf/sp/callgraph/CallGraphBuilder.java,a/d/ad21bb9fca84ba24aa77efa1907f02adf7e9d563
|
||||||
|
f
|
||||||
|
6src/ch/usi/inf/sp/callgraph/ClassHierarchyBuilder.java,3/f/3fa6b31f8e29ac7b8e005caf4b878f80c9fc3e4b
|
||||||
|
:
|
||||||
|
|
||||||
|
.gitignore,a/5/a5cc2925ca8258af241be7e5b0381edf30266302
|
||||||
|
b
|
||||||
|
2src/ch/usi/inf/sp/callgraph/CallGraphRenderer.java,1/d/1d626f79e495ba1c9dcf29a43a14e76b4a6095ac
|
||||||
|
9
|
||||||
|
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
|
||||||
|
T
|
||||||
|
$src/ch/usi/inf/sp/callgraph/App.java,6/d/6d4ba865d940befa40ed49e8650c29be6a5b0682
|
12
.idea/starter-lab-05-call-graph.iml
Normal file
12
.idea/starter-lab-05-call-graph.iml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="asm-6.2.1" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
7
.idea/vcs.xml
Normal file
7
.idea/vcs.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
30
README.md
Normal file
30
README.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Lab 5 - Software Peformance 2023
|
||||||
|
|
||||||
|
This is Lab 5 of the **Software Performance** course at USI.
|
||||||
|
|
||||||
|
Go to [this Lab on iCorsi](https://www.icorsi.ch/course/view.php?id=16963).
|
||||||
|
|
||||||
|
## Submission Info
|
||||||
|
|
||||||
|
Property | Value
|
||||||
|
------------ | -------------
|
||||||
|
First Name | ...
|
||||||
|
Last Name | ...
|
||||||
|
|
||||||
|
## Submission Checklist
|
||||||
|
|
||||||
|
Please complete this checklist (turn [ ] into [X]) before you submit:
|
||||||
|
|
||||||
|
- [ ] I completed the above Submission Info
|
||||||
|
- [ ] I built the project in IntelliJ (Build > Build Project)
|
||||||
|
- [ ] I implemented the ClassHierarchyBuilder
|
||||||
|
- [ ] I implemented the CallGraphBuilder
|
||||||
|
- [ ] I implemented the CallGraphRenderer
|
||||||
|
- [ ] I wrote the source code myself and did not look at the source code of my class mates
|
||||||
|
- [ ] I manually checked that my implementation is correct by doing this:
|
||||||
|
- [ ] I studied the source code within test-input/pacman-src.jar
|
||||||
|
- [ ] I ran App to produce the dot file (in test-output/)
|
||||||
|
- [ ] I ran dot to turn the dot file in test-output into a PDF
|
||||||
|
- [ ] I manually verified that the PDF contains the correct call graph
|
||||||
|
- [ ] I committed my changes (at least one commit, but possibly many)
|
||||||
|
- [ ] I pushed my commits to GitHub
|
BIN
lib/apiguardian-api-1.0.0.jar
Normal file
BIN
lib/apiguardian-api-1.0.0.jar
Normal file
Binary file not shown.
BIN
lib/asm-6.2.1-javadoc.jar
Normal file
BIN
lib/asm-6.2.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-6.2.1-sources.jar
Normal file
BIN
lib/asm-6.2.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-6.2.1.jar
Normal file
BIN
lib/asm-6.2.1.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-6.2.1-javadoc.jar
Normal file
BIN
lib/asm-tree-6.2.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-6.2.1-sources.jar
Normal file
BIN
lib/asm-tree-6.2.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-tree-6.2.1.jar
Normal file
BIN
lib/asm-tree-6.2.1.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-6.2.1-javadoc.jar
Normal file
BIN
lib/asm-util-6.2.1-javadoc.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-6.2.1-sources.jar
Normal file
BIN
lib/asm-util-6.2.1-sources.jar
Normal file
Binary file not shown.
BIN
lib/asm-util-6.2.1.jar
Normal file
BIN
lib/asm-util-6.2.1.jar
Normal file
Binary file not shown.
BIN
lib/junit-jupiter-api-5.0.0.jar
Normal file
BIN
lib/junit-jupiter-api-5.0.0.jar
Normal file
Binary file not shown.
BIN
lib/junit-platform-commons-1.0.0.jar
Normal file
BIN
lib/junit-platform-commons-1.0.0.jar
Normal file
Binary file not shown.
BIN
lib/opentest4j-1.0.0.jar
Normal file
BIN
lib/opentest4j-1.0.0.jar
Normal file
Binary file not shown.
52
src/ch/usi/inf/sp/callgraph/App.java
Normal file
52
src/ch/usi/inf/sp/callgraph/App.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import ch.usi.inf.sp.framework.ArchiveScanner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke like this...
|
||||||
|
* <p>
|
||||||
|
* java App test-input/pacman-src.jar
|
||||||
|
* <p>
|
||||||
|
* to produce ....
|
||||||
|
* Afterwards, go to the test-output folder, and call...
|
||||||
|
* <p>
|
||||||
|
* dot -Tpdf -ograph.pdf graph.dot
|
||||||
|
* <p>
|
||||||
|
* ...to produce a file graph.pdf of the call graph.
|
||||||
|
*
|
||||||
|
* MAKE SURE YOU MANUALLY VERIFY FOR EACH METHOD THAT
|
||||||
|
* THE CALL GRAPH IT'S ACTUALLY CORRECT.
|
||||||
|
*/
|
||||||
|
public final class App {
|
||||||
|
|
||||||
|
public static void main(final String[] args) throws IOException {
|
||||||
|
for (final String arg : args) {
|
||||||
|
System.out.println(arg);
|
||||||
|
}
|
||||||
|
final ArchiveScanner scanner = new ArchiveScanner();
|
||||||
|
|
||||||
|
// phase 1: build inheritance hierarchy
|
||||||
|
final ClassHierarchyBuilder classHierarchyBuilder = new ClassHierarchyBuilder();
|
||||||
|
scanner.addAnalyzer(classHierarchyBuilder);
|
||||||
|
for (int i=0; i<args.length; i++) {
|
||||||
|
scanner.scan(args[i]);
|
||||||
|
}
|
||||||
|
scanner.removeAnalyzer(classHierarchyBuilder);
|
||||||
|
|
||||||
|
// phase 2: add call sites and edges
|
||||||
|
final CallGraphBuilder callGraphBuilder = new CallGraphBuilder(classHierarchyBuilder.getClassHierarchy());
|
||||||
|
scanner.addAnalyzer(callGraphBuilder);
|
||||||
|
for (int i=0; i<args.length; i++) {
|
||||||
|
scanner.scan(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump info about the call graph
|
||||||
|
new File("test-output").mkdirs(); // create output directory
|
||||||
|
new CallGraphRenderer().dumpDot(classHierarchyBuilder.getClassHierarchy(), "test-output/graph.dot");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
54
src/ch/usi/inf/sp/callgraph/ArrayType.java
Normal file
54
src/ch/usi/inf/sp/callgraph/ArrayType.java
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the type of an array.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class ArrayType implements Type {
|
||||||
|
|
||||||
|
private final String internalName;
|
||||||
|
private boolean resolved;
|
||||||
|
private Type componentType;
|
||||||
|
|
||||||
|
|
||||||
|
public ArrayType(final String internalName) {
|
||||||
|
this.internalName = internalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInternalName() {
|
||||||
|
return internalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolved() {
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSimpleName() {
|
||||||
|
if (!resolved) {
|
||||||
|
throw new IllegalStateException("Array type "+internalName+" not resolved yet");
|
||||||
|
}
|
||||||
|
return componentType.getSimpleName()+"[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolve(final ClassHierarchy nameSpace) throws TypeInconsistencyException {
|
||||||
|
if (internalName.charAt(1)=='[') {
|
||||||
|
componentType = nameSpace.getOrCreateArrayType(internalName.substring(1));
|
||||||
|
} else if (internalName.charAt(1)=='L') {
|
||||||
|
componentType = nameSpace.getOrCreateClass(internalName.substring(2, internalName.length()-1));
|
||||||
|
} else {
|
||||||
|
componentType = nameSpace.getPrimitiveType(internalName.substring(1));
|
||||||
|
}
|
||||||
|
resolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws TypeInconsistencyException {
|
||||||
|
ClassHierarchy ch = new ClassHierarchy();
|
||||||
|
ch.getOrCreateArrayType("[[LPacman;");
|
||||||
|
for (Type t : ch.getTypes()) {
|
||||||
|
System.out.println(t.getInternalName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
src/ch/usi/inf/sp/callgraph/CallGraphBuilder.java
Normal file
45
src/ch/usi/inf/sp/callgraph/CallGraphBuilder.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ch.usi.inf.sp.framework.ClassAnalyzer;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a call graph (as part of the class hierarchy)
|
||||||
|
* consisting of CallSite nodes pointing to Method nodes.
|
||||||
|
*
|
||||||
|
* @author ?
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class CallGraphBuilder implements ClassAnalyzer {
|
||||||
|
|
||||||
|
private final ClassHierarchy hierarchy;
|
||||||
|
|
||||||
|
|
||||||
|
public CallGraphBuilder(final ClassHierarchy hierarchy) {
|
||||||
|
this.hierarchy = hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void analyze(final String location, final ClassNode classNode) {
|
||||||
|
try {
|
||||||
|
final ClassType type = hierarchy.getOrCreateClass(classNode.name);
|
||||||
|
final List<MethodNode> methodNodes = (List<MethodNode>)classNode.methods;
|
||||||
|
for (final MethodNode methodNode : methodNodes) {
|
||||||
|
final Method method = type.getMethod(methodNode.name, methodNode.desc);
|
||||||
|
final InsnList instructions = methodNode.instructions;
|
||||||
|
for (int i=0; i<instructions.size(); i++) {
|
||||||
|
|
||||||
|
// TODO implement this
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final TypeInconsistencyException ex) {
|
||||||
|
System.err.println(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
src/ch/usi/inf/sp/callgraph/CallGraphRenderer.java
Normal file
32
src/ch/usi/inf/sp/callgraph/CallGraphRenderer.java
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump out information about the given ClassHierarchy.
|
||||||
|
*
|
||||||
|
* @author ?
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class CallGraphRenderer {
|
||||||
|
|
||||||
|
public void dumpDot(final ClassHierarchy hierarchy, final String fileName) throws IOException {
|
||||||
|
final PrintWriter pw = new PrintWriter(new FileWriter(fileName));
|
||||||
|
pw.println("digraph CallGraph {");
|
||||||
|
pw.println(" rankdir=\"BT\"");
|
||||||
|
for (final Type type : hierarchy.getTypes()) {
|
||||||
|
if (type instanceof ClassType) {
|
||||||
|
final ClassType classType = (ClassType)type;
|
||||||
|
|
||||||
|
// TODO implement this
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pw.println("}");
|
||||||
|
pw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
65
src/ch/usi/inf/sp/callgraph/CallSite.java
Normal file
65
src/ch/usi/inf/sp/callgraph/CallSite.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call site represents a call instruction in the body of a method.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class CallSite {
|
||||||
|
|
||||||
|
private final int opcode;
|
||||||
|
private final String declaredTargetClassName;
|
||||||
|
private final String targetMethodName;
|
||||||
|
private final String targetMethodDescriptor;
|
||||||
|
private final HashSet<ClassType> possibleTargetClasses;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a CallSite given the info taken from an ASM MethodInsnNode.
|
||||||
|
*
|
||||||
|
* @param opcode from MethodInsnNode.getOpcode()
|
||||||
|
* @param declaredTargetClassName from MethodInsnNode.owner
|
||||||
|
* @param targetMethodName from MethodInsnNode.name
|
||||||
|
* @param targetMethodDescriptor from MethodInsnNode.desc
|
||||||
|
*/
|
||||||
|
public CallSite(final int opcode, final String declaredTargetClassName, final String targetMethodName, final String targetMethodDescriptor) {
|
||||||
|
this.opcode = opcode;
|
||||||
|
this.declaredTargetClassName = declaredTargetClassName;
|
||||||
|
this.targetMethodName = targetMethodName;
|
||||||
|
this.targetMethodDescriptor = targetMethodDescriptor;
|
||||||
|
possibleTargetClasses = new HashSet<ClassType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOpcode() {
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeclaredTargetClassName() {
|
||||||
|
return declaredTargetClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetMethodName() {
|
||||||
|
return targetMethodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetMethodDescriptor() {
|
||||||
|
return targetMethodDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to add a possible target during Class Hierarchy Analysis.
|
||||||
|
* @param targetClass
|
||||||
|
*/
|
||||||
|
public void addPossibleTargetClass(final ClassType targetClass) {
|
||||||
|
possibleTargetClasses.add(targetClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ClassType> getPossibleTargetClasses() {
|
||||||
|
return possibleTargetClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
69
src/ch/usi/inf/sp/callgraph/ClassHierarchy.java
Normal file
69
src/ch/usi/inf/sp/callgraph/ClassHierarchy.java
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name space containing all known types.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class ClassHierarchy {
|
||||||
|
|
||||||
|
private HashMap<String, Type> typeByInternalName;
|
||||||
|
|
||||||
|
|
||||||
|
public ClassHierarchy() {
|
||||||
|
typeByInternalName = new HashMap<String, Type>();
|
||||||
|
add(PrimitiveType.BYTE);
|
||||||
|
add(PrimitiveType.SHORT);
|
||||||
|
add(PrimitiveType.CHAR);
|
||||||
|
add(PrimitiveType.INT);
|
||||||
|
add(PrimitiveType.LONG);
|
||||||
|
add(PrimitiveType.FLOAT);
|
||||||
|
add(PrimitiveType.DOUBLE);
|
||||||
|
add(PrimitiveType.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final void add(final Type type) {
|
||||||
|
typeByInternalName.put(type.getInternalName(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassType getOrCreateClass(final String internalName) throws TypeInconsistencyException {
|
||||||
|
Type type = typeByInternalName.get(internalName);
|
||||||
|
if (type==null) {
|
||||||
|
type = new ClassType(internalName);
|
||||||
|
typeByInternalName.put(internalName, type);
|
||||||
|
} else if (!(type instanceof ClassType)) {
|
||||||
|
throw new TypeInconsistencyException("Expected class, got "+type);
|
||||||
|
}
|
||||||
|
return (ClassType)type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayType getOrCreateArrayType(final String internalName) throws TypeInconsistencyException {
|
||||||
|
Type type = typeByInternalName.get(internalName);
|
||||||
|
if (type==null) {
|
||||||
|
final ArrayType arrayType = new ArrayType(internalName);
|
||||||
|
typeByInternalName.put(internalName, arrayType);
|
||||||
|
arrayType.resolve(this);
|
||||||
|
type = arrayType;
|
||||||
|
} else if (!(type instanceof ArrayType)) {
|
||||||
|
throw new TypeInconsistencyException("Expected array type, got "+type);
|
||||||
|
}
|
||||||
|
return (ArrayType)type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimitiveType getPrimitiveType(final String internalName) throws TypeInconsistencyException {
|
||||||
|
final Type type = typeByInternalName.get(internalName);
|
||||||
|
if (!(type instanceof PrimitiveType)) {
|
||||||
|
throw new TypeInconsistencyException("Expected primitive type, got "+type);
|
||||||
|
}
|
||||||
|
return (PrimitiveType)type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Type> getTypes() {
|
||||||
|
return typeByInternalName.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
46
src/ch/usi/inf/sp/callgraph/ClassHierarchyBuilder.java
Normal file
46
src/ch/usi/inf/sp/callgraph/ClassHierarchyBuilder.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import ch.usi.inf.sp.framework.ClassAnalyzer;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a class hierarchy (including methods).
|
||||||
|
*
|
||||||
|
* @author ?
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class ClassHierarchyBuilder implements ClassAnalyzer {
|
||||||
|
|
||||||
|
private final ClassHierarchy classHierarchy;
|
||||||
|
|
||||||
|
|
||||||
|
public ClassHierarchyBuilder() {
|
||||||
|
this.classHierarchy = new ClassHierarchy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassHierarchy getClassHierarchy() {
|
||||||
|
return classHierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void analyze(final String location, final ClassNode clazz) {
|
||||||
|
try {
|
||||||
|
final ClassType classType = classHierarchy.getOrCreateClass(clazz.name);
|
||||||
|
if (classType.isResolved()) {
|
||||||
|
System.err.println("WARNING: Class "+classType.getInternalName()+" defined multiple times");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
classType.setLocation(location);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO extract modifiers, super class, interfaces, methods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
classType.setResolved();
|
||||||
|
} catch (final TypeInconsistencyException ex) {
|
||||||
|
System.err.println(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
210
src/ch/usi/inf/sp/callgraph/ClassType.java
Normal file
210
src/ch/usi/inf/sp/callgraph/ClassType.java
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ClassType represents a class or an interface.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class ClassType implements Type {
|
||||||
|
|
||||||
|
private final String internalName;
|
||||||
|
private boolean resolved;
|
||||||
|
private String location;
|
||||||
|
private int modifiers;
|
||||||
|
private ClassType superClass;
|
||||||
|
private ArrayList<ClassType> interfaces;
|
||||||
|
private ArrayList<Method> methods;
|
||||||
|
private ArrayList<ClassType> subTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a ClassType given an internal name (without "L" prefix or ";" suffix).
|
||||||
|
* @param internalName the internal name of the class,
|
||||||
|
* e.g. "java/lang/Object" (class Object in package java.lang)
|
||||||
|
* or "java/awt/geom/Point2D$Double" (class Double in class Point2D in package java.awt.geom)
|
||||||
|
* or "TypeInDefaultPackage" (class TypeInDefaultPackage in the default package).
|
||||||
|
*/
|
||||||
|
public ClassType(final String internalName) {
|
||||||
|
this.internalName = internalName;
|
||||||
|
this.interfaces = new ArrayList<ClassType>();
|
||||||
|
this.methods = new ArrayList<Method>();
|
||||||
|
this.subTypes = new ArrayList<ClassType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInternalName() {
|
||||||
|
return internalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the simple name of the underlying class as given in the source code.
|
||||||
|
* Returns an empty string if the underlying class is anonymous.
|
||||||
|
* The simple name of an array is the simple name of the component type with "[]" appended.
|
||||||
|
* In particular the simple name of an array whose component type is anonymous is "[]".
|
||||||
|
*/
|
||||||
|
public String getSimpleName() {
|
||||||
|
final int dollar = internalName.lastIndexOf('$');
|
||||||
|
if (dollar>-1) {
|
||||||
|
final String n = internalName.substring(dollar);
|
||||||
|
if (n.matches("[0-9]+")) {
|
||||||
|
// anonymous inner classes have numbers as their names
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
// inner/nested class
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final int slash = internalName.lastIndexOf('/');
|
||||||
|
if (slash>-1) {
|
||||||
|
// class in package
|
||||||
|
return internalName.substring(slash).replace('/', '.');
|
||||||
|
} else {
|
||||||
|
// class in default package
|
||||||
|
return internalName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do this after you have completed reading this class
|
||||||
|
* (classes that were never read, but referenced by other classes, will appear as not resolved)
|
||||||
|
*/
|
||||||
|
public void setResolved() {
|
||||||
|
resolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolved() {
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the location (e.g. the name of the JAR file) this class was loaded from
|
||||||
|
* when you read in the class.
|
||||||
|
* @param location
|
||||||
|
*/
|
||||||
|
public void setLocation(final String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the location (e.g. the name of the JAR file) this class was loaded from.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this class (or interface's) super class
|
||||||
|
* when you read in the class.
|
||||||
|
* @param superClass
|
||||||
|
*/
|
||||||
|
public void setSuperClass(final ClassType superClass) {
|
||||||
|
this.superClass = superClass;
|
||||||
|
// automatically maintain subtypes
|
||||||
|
superClass.subTypes.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this class (or interface's) super class.
|
||||||
|
*/
|
||||||
|
public ClassType getSuperClass() {
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add interfa to the list of this class (or interface's) interfaces
|
||||||
|
* when you read in the class.
|
||||||
|
* @param interfa The interface implemented by this class, resp. extended by this interface.
|
||||||
|
*/
|
||||||
|
public void addInterface(final ClassType interfa) {
|
||||||
|
interfaces.add(interfa);
|
||||||
|
// automatically maintain subtypes
|
||||||
|
interfa.subTypes.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the interfaces implemented by this class resp. extended by this interface.
|
||||||
|
*/
|
||||||
|
public Collection<ClassType> getInterfaces() {
|
||||||
|
return interfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the currently known subtypes (interfaces and/or classes) of this interface or class.
|
||||||
|
*/
|
||||||
|
public Collection<ClassType> getSubTypes() {
|
||||||
|
return subTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a method to this class
|
||||||
|
* when you read in the clas.
|
||||||
|
* The class should contain all the methods it explicitly declares
|
||||||
|
* (including abstract methods).
|
||||||
|
*/
|
||||||
|
public void addMethod(final Method method) {
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the methods this class declares.
|
||||||
|
*/
|
||||||
|
public Collection<Method> getMethods() {
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the method with the given name and descriptor, if such a method is declared in this class.
|
||||||
|
* @param name e.g. "<init>" or "main"
|
||||||
|
* @param descriptor E.g. "()V" or "([Ljava/lang/String;)V"
|
||||||
|
* @return the Method or null
|
||||||
|
*/
|
||||||
|
public Method getMethod(final String name, final String descriptor) {
|
||||||
|
for (final Method method : methods) {
|
||||||
|
if (method.getName().equals(name) && method.getDescriptor().equals(descriptor)) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no such method declared in this class
|
||||||
|
// (one still could be declared in a superclass or interface!)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the modifiers when you read in the class.
|
||||||
|
* @param modifiers Modifiers coming from ASM's ClassNode.access
|
||||||
|
*/
|
||||||
|
public void setModifiers(final int modifiers) {
|
||||||
|
this.modifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
return (modifiers & Opcodes.ACC_INTERFACE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return (modifiers & Opcodes.ACC_ABSTRACT) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinal() {
|
||||||
|
return (modifiers & Opcodes.ACC_FINAL) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnum() {
|
||||||
|
return (modifiers & Opcodes.ACC_ENUM) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return (isInterface()?"interface ":(isEnum()?"enum ":"class "))+getInternalName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
104
src/ch/usi/inf/sp/callgraph/Method.java
Normal file
104
src/ch/usi/inf/sp/callgraph/Method.java
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method declared in a class or interface. May be abstract.
|
||||||
|
* A method can contain several CallSites
|
||||||
|
* (information about CallSites may or may not be available,
|
||||||
|
* e.g. usually CallSites are added to Method objects only by the CallGraphBuilder).
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class Method {
|
||||||
|
|
||||||
|
private final String declaringClassName;
|
||||||
|
private final String name;
|
||||||
|
private final String descriptor;
|
||||||
|
private final int modifiers;
|
||||||
|
private final ArrayList<CallSite> callSites;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param name The name of the method, "<init>" for constructor or instance initializer, "<clinit>" for static initializer.
|
||||||
|
* @param descriptor The descriptor showing argument and return types
|
||||||
|
* (e.g. "(IJ)V" means the method takes two arguments, an int and a long, and its return type is void)
|
||||||
|
* @param modifiers
|
||||||
|
*/
|
||||||
|
public Method(final String declaringClassName, final String name, final String descriptor, final int modifiers) {
|
||||||
|
this.declaringClassName = declaringClassName;
|
||||||
|
this.name = name;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
this.modifiers = modifiers;
|
||||||
|
this.callSites = new ArrayList<CallSite>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the internal name of the class declaring this method.
|
||||||
|
*/
|
||||||
|
public String getDeclaringClassName() {
|
||||||
|
return declaringClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescriptor() {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the modifiers (access flags, ...) as an int, as taken from ASM.
|
||||||
|
*/
|
||||||
|
public int getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return (Opcodes.ACC_STATIC & modifiers) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return (Opcodes.ACC_PUBLIC & modifiers) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtected() {
|
||||||
|
return (Opcodes.ACC_PROTECTED & modifiers) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return (Opcodes.ACC_PRIVATE & modifiers) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return (Opcodes.ACC_ABSTRACT & modifiers) !=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinal() {
|
||||||
|
return (Opcodes.ACC_FINAL & modifiers) !=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a CallSite to this method.
|
||||||
|
* Usually done only when really needed (e.g. by CallGraphBuilder).
|
||||||
|
* @param callSite
|
||||||
|
*/
|
||||||
|
public void addCallSite(final CallSite callSite) {
|
||||||
|
callSites.add(callSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all CallSites in this method
|
||||||
|
* (will return an empty collection if no CallSites were added).
|
||||||
|
*/
|
||||||
|
public Collection<CallSite> getCallSites() {
|
||||||
|
return callSites;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/ch/usi/inf/sp/callgraph/PrimitiveType.java
Normal file
42
src/ch/usi/inf/sp/callgraph/PrimitiveType.java
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a primitive type.
|
||||||
|
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public enum PrimitiveType implements Type {
|
||||||
|
|
||||||
|
BYTE("B", "byte"),
|
||||||
|
SHORT("S", "short"),
|
||||||
|
CHAR("C", "char"),
|
||||||
|
INT("I", "int"),
|
||||||
|
LONG("J", "long"),
|
||||||
|
FLOAT("F", "float"),
|
||||||
|
DOUBLE("D", "double"),
|
||||||
|
BOOLEAN("Z", "boolean"),
|
||||||
|
VOID("V", "void");
|
||||||
|
|
||||||
|
private final String internalName;
|
||||||
|
private final String simpleName;
|
||||||
|
|
||||||
|
|
||||||
|
private PrimitiveType(final String internalName, final String simpleName) {
|
||||||
|
this.internalName = internalName;
|
||||||
|
this.simpleName = simpleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInternalName() {
|
||||||
|
return internalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolved() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSimpleName() {
|
||||||
|
return simpleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/ch/usi/inf/sp/callgraph/Type.java
Normal file
15
src/ch/usi/inf/sp/callgraph/Type.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (primitive, array, or class) type in Java.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public interface Type {
|
||||||
|
|
||||||
|
public String getInternalName();
|
||||||
|
public boolean isResolved();
|
||||||
|
public String getSimpleName();
|
||||||
|
|
||||||
|
}
|
15
src/ch/usi/inf/sp/callgraph/TypeInconsistencyException.java
Normal file
15
src/ch/usi/inf/sp/callgraph/TypeInconsistencyException.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package ch.usi.inf.sp.callgraph;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown in cases of type inconsistencies while building the ClassHierarchy
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public class TypeInconsistencyException extends Exception {
|
||||||
|
|
||||||
|
public TypeInconsistencyException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
src/ch/usi/inf/sp/framework/ArchiveScanner.java
Normal file
58
src/ch/usi/inf/sp/framework/ArchiveScanner.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package ch.usi.inf.sp.framework;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a JAR archive containing Java class files, uses ASM to load each class,
|
||||||
|
* and for each class invokes Analyzer.analyze() on each registered Analyzer.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public final class ArchiveScanner {
|
||||||
|
|
||||||
|
private final ArrayList<ClassAnalyzer> analyzers;
|
||||||
|
|
||||||
|
|
||||||
|
public ArchiveScanner() {
|
||||||
|
analyzers = new ArrayList<ClassAnalyzer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAnalyzer(final ClassAnalyzer analyzer) {
|
||||||
|
analyzers.add(analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAnalyzer(final ClassAnalyzer analyzer) {
|
||||||
|
analyzers.remove(analyzer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scan(final String archiveName) throws IOException {
|
||||||
|
final ZipFile zipFile = new ZipFile(archiveName);
|
||||||
|
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
final ZipEntry zipEntry = entries.nextElement();
|
||||||
|
if (zipEntry.getName().toLowerCase().endsWith(".class"))
|
||||||
|
analyzeClass(zipFile, zipEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void analyzeClass(final ZipFile zipFile, final ZipEntry zipEntry) throws IOException {
|
||||||
|
final String location = zipFile.getName();
|
||||||
|
final ClassReader classReader = new ClassReader(zipFile.getInputStream(zipEntry));
|
||||||
|
// create an empty ClassNode (in-memory representation of a class)
|
||||||
|
final ClassNode classNode = new ClassNode();
|
||||||
|
// have the ClassReader read the class file and populate the ClassNode with the corresponding information
|
||||||
|
classReader.accept(classNode, 0);
|
||||||
|
for (final ClassAnalyzer analyzer : analyzers) {
|
||||||
|
analyzer.analyze(location, classNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/ch/usi/inf/sp/framework/ClassAnalyzer.java
Normal file
15
src/ch/usi/inf/sp/framework/ClassAnalyzer.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package ch.usi.inf.sp.framework;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface if you want to be called by an ArchiveScanner.
|
||||||
|
*
|
||||||
|
* @author Matthias.Hauswirth@usi.ch
|
||||||
|
*/
|
||||||
|
public interface ClassAnalyzer {
|
||||||
|
|
||||||
|
public void analyze(String location, ClassNode clazz);
|
||||||
|
|
||||||
|
}
|
BIN
test-input/pacman-src.jar
Normal file
BIN
test-input/pacman-src.jar
Normal file
Binary file not shown.
Reference in a new issue