Adds support for JAVA files

This commit is contained in:
emmanue1 2015-06-14 11:53:48 +02:00
parent 411348dc6b
commit e8a49c4e75
31 changed files with 3754 additions and 809 deletions

View File

@ -10,3 +10,59 @@ dependencies {
compile project(':api') compile project(':api')
testCompile 'org.codehaus.groovy:groovy-test:2.4.0' testCompile 'org.codehaus.groovy:groovy-test:2.4.0'
} }
// ANTLR //
ext.antlr4 = [
antlrSource: 'src/main/antlr',
destinationDir: 'src-generated/antlr/java',
grammarPackage: 'jd.gui.util.parser.antlr'
]
configurations {
antlr4 {
description = "ANTLR4"
}
}
dependencies {
compile 'org.antlr:antlr4-runtime:4.5'
antlr4 'org.antlr:antlr4:4.5'
}
task antlr4OutputDir() {
mkdir antlr4.destinationDir
}
task antlr4GenerateGrammarSource(dependsOn: antlr4OutputDir, type: JavaExec) {
description = 'Generates Java sources from ANTLR4 grammars.'
inputs.dir file(antlr4.antlrSource)
outputs.dir file(antlr4.destinationDir)
def grammars = fileTree(antlr4.antlrSource).include('**/*.g4')
def pkg = antlr4.grammarPackage.replaceAll("\\.", "/")
main = 'org.antlr.v4.Tool'
classpath = configurations.antlr4
args = ['-o', "${antlr4.destinationDir}/${pkg}", '-atn', '-package', antlr4.grammarPackage, grammars.files].flatten()
}
compileJava {
dependsOn antlr4GenerateGrammarSource
source antlr4.destinationDir
}
clean {
delete 'src-generated'
}
idea.module {
sourceDirs += file(antlr4.destinationDir)
}
ideaModule.dependsOn antlr4GenerateGrammarSource
eclipse.classpath.file.withXml { xml ->
def node = xml.asNode()
node.appendNode( 'classpathentry', [ kind: 'src', path: antlr4.destinationDir])
}
eclipseClasspath.dependsOn antlr4GenerateGrammarSource

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.fileloader
import jd.gui.api.API
import jd.gui.api.feature.UriOpenable
import java.nio.file.Paths
abstract class AbstractTypeFileLoaderProvider extends AbstractFileLoaderProvider {
protected boolean load(API api, File file, String pathInFile) {
// Search root path
String pathSuffix = pathInFile
String path = file.path
while (! path.endsWith(pathSuffix)) {
int index = pathSuffix.indexOf(File.separator)
if (index == -1) {
pathSuffix = ''
} else {
pathSuffix = pathSuffix.substring(index+1)
}
}
if (pathSuffix) {
// Init root file
File rootFile = file
int index = pathSuffix.indexOf(File.separator)
while (index != -1) {
rootFile = rootFile.parentFile
pathSuffix = pathSuffix.substring(index+1)
index = pathSuffix.indexOf(File.separator)
}
rootFile = rootFile.parentFile
// Create panel
def mainPanel = load(api, rootFile, Paths.get(rootFile.toURI()))
if (mainPanel instanceof UriOpenable) {
// Open page
pathSuffix = file.absolutePath.substring(rootFile.absolutePath.length()).replace(File.separator, '/')
def rootUri = rootFile.toURI()
def uri = new URI(rootUri.scheme, rootUri.host, rootUri.path + '!' + pathSuffix, null)
mainPanel.openUri(uri)
return true
} else {
return mainPanel != null
}
}
}
}

View File

@ -7,11 +7,8 @@ package jd.gui.service.fileloader
import groovyjarjarasm.asm.ClassReader import groovyjarjarasm.asm.ClassReader
import jd.gui.api.API import jd.gui.api.API
import jd.gui.api.feature.UriOpenable
import java.nio.file.Paths class ClassFileLoaderProvider extends AbstractTypeFileLoaderProvider {
class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
String[] getExtensions() { ['class'] } String[] getExtensions() { ['class'] }
String getDescription() { 'Class files (*.class)' } String getDescription() { 'Class files (*.class)' }
@ -22,48 +19,10 @@ class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
boolean load(API api, File file) { boolean load(API api, File file) {
file.withInputStream { is -> file.withInputStream { is ->
ClassReader classReader = new ClassReader(is) def classReader = new ClassReader(is)
def pathInFile = classReader.className.replace('/', File.separator) + '.class'
// Search root path return load(api, file, pathInFile)
def pathSuffix = classReader.className.replace('/', File.separator) + '.class'
def path = file.path
while (! path.endsWith(pathSuffix)) {
int index = pathSuffix.indexOf(File.separator)
if (index == -1) {
pathSuffix = ''
} else {
pathSuffix = pathSuffix.substring(index+1)
}
}
if (pathSuffix) {
// Init root file
File rootFile = file
int index = pathSuffix.indexOf(File.separator)
while (index != -1) {
rootFile = rootFile.parentFile
pathSuffix = pathSuffix.substring(index+1)
index = pathSuffix.indexOf(File.separator)
}
rootFile = rootFile.parentFile
// Create panel
def mainPanel = load(api, rootFile, Paths.get(rootFile.toURI()))
if (mainPanel instanceof UriOpenable) {
// Open page
pathSuffix = file.absolutePath.substring(rootFile.absolutePath.length()).replace(File.separator, '/')
def rootUri = rootFile.toURI()
def uri = new URI(rootUri.scheme, rootUri.host, rootUri.path + '!' + pathSuffix, null)
mainPanel.openUri(uri)
return true
} else {
return mainPanel != null
}
}
} }
} }
} }

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.fileloader
import jd.gui.api.API
import java.util.regex.Pattern
class JavaFileLoaderProvider extends AbstractTypeFileLoaderProvider {
String[] getExtensions() { ['java'] }
String getDescription() { 'Java files (*.java)' }
boolean accept(API api, File file) {
return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.java')
}
boolean load(API api, File file) {
def pattern = Pattern.compile('(?s)(.*\\s)?package\\s+(\\S+)\\s*;.*')
def matcher = file.text =~ pattern
if (matcher.matches()) {
// Package name found
def pathInFile = matcher[0][2].replace('.', File.separator) + File.separator + file.name
return load(api, file, pathInFile)
} else {
// Package name not found
return load(api, file, file.name)
}
}
}

View File

@ -5,7 +5,6 @@
package jd.gui.service.treenode package jd.gui.service.treenode
import groovy.transform.CompileStatic
import jd.gui.api.API import jd.gui.api.API
import jd.gui.api.feature.PageCreator import jd.gui.api.feature.PageCreator
import jd.gui.api.feature.TreeNodeExpandable import jd.gui.api.feature.TreeNodeExpandable
@ -21,13 +20,13 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator { static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
Container.Entry entry Container.Entry entry
PageFactory pageFactory; PageAndTipFactory factory;
URI uri URI uri
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) { BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
super(userObject) super(userObject)
this.entry = entry this.entry = entry
this.pageFactory = pageFactory this.factory = factory
if (fragment) { if (fragment) {
def uri = entry.uri def uri = entry.uri
@ -43,50 +42,20 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
// --- PageCreator --- // // --- PageCreator --- //
public <T extends JComponent & UriGettable> T createPage(API api) { public <T extends JComponent & UriGettable> T createPage(API api) {
// Lazy 'tip' initialization // Lazy 'tip' initialization
def file = new File(entry.container.root.uri) userObject.tip = factory.makeTip(api, entry)
def tip = "<html>Location: $file.path" return factory.makePage(api, entry)
entry.inputStream.withStream { is ->
is.skip(4) // Skip magic number
int minorVersion = readUnsignedShort(is)
int majorVersion = readUnsignedShort(is)
if (majorVersion >= 49) {
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
} else if (majorVersion >= 45) {
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
}
}
tip += "</html>"
userObject.tip = tip
return pageFactory.make(api, entry)
}
/**
* @see java.io.DataInputStream#readUnsignedShort()
*/
@CompileStatic
int readUnsignedShort(InputStream is) throws IOException {
int ch1 = is.read()
int ch2 = is.read()
if ((ch1 | ch2) < 0)
throw new EOFException()
return (ch1 << 8) + (ch2 << 0)
} }
} }
static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable { static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
boolean initialized boolean initialized
FileTreeNode(Container.Entry entry, Object userObject, PageFactory pageFactory) { FileTreeNode(Container.Entry entry, Object userObject, PageAndTipFactory pageAndTipFactory) {
this(entry, null, userObject, pageFactory) this(entry, null, userObject, pageAndTipFactory)
} }
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) { FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
super(entry, fragment, userObject, pageFactory) super(entry, fragment, userObject, factory)
initialized = false initialized = false
// Add dummy node // Add dummy node
add(new DefaultMutableTreeNode()) add(new DefaultMutableTreeNode())
@ -97,9 +66,10 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
if (!initialized) { if (!initialized) {
removeAllChildren() removeAllChildren()
// Create type node // Create type node
def type = api.getTypeFactory(entry)?.make(api, entry, null) def types = api.getTypeFactory(entry)?.make(api, entry)
if (type) {
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), pageFactory)) for (def type : types) {
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), factory))
} }
initialized = true initialized = true
@ -111,8 +81,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
boolean initialized boolean initialized
Type type Type type
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageFactory pageFactory) { TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageAndTipFactory factory) {
super(entry, type.name, userObject, pageFactory) super(entry, type.name, userObject, factory)
this.initialized = false this.initialized = false
this.type = type this.type = type
// Add dummy node // Add dummy node
@ -134,7 +104,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
type.innerTypes.sort { t1, t2 -> type.innerTypes.sort { t1, t2 ->
t1.name.compareTo(t2.name) t1.name.compareTo(t2.name)
}.each { }.each {
add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon), pageFactory)) add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon), factory))
} }
// Create fields // Create fields
@ -148,7 +118,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
}.sort { f1, f2 -> }.sort { f1, f2 ->
f1.label.compareTo(f2.label) f1.label.compareTo(f2.label)
}.each { }.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory)) add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), factory))
} }
// Create methods // Create methods
@ -161,7 +131,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
}.sort { m1, m2 -> }.sort { m1, m2 ->
m1.label.compareTo(m2.label) m1.label.compareTo(m2.label)
}.each { }.each {
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory)) add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), factory))
} }
initialized = true initialized = true
@ -400,8 +370,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
} }
static class FieldOrMethodTreeNode extends BaseTreeNode { static class FieldOrMethodTreeNode extends BaseTreeNode {
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) { FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
super(entry, fragment, userObject, pageFactory) super(entry, fragment, userObject, factory)
} }
} }
@ -409,8 +379,9 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
String fragment, label String fragment, label
Icon icon Icon icon
} }
interface PageFactory { interface PageAndTipFactory {
public <T extends JComponent & UriGettable> T make(API api, Container.Entry entry); public <T extends JComponent & UriGettable> T makePage(API api, Container.Entry entry);
public String makeTip(API api, Container.Entry entry);
} }
} }

View File

@ -5,6 +5,7 @@
package jd.gui.service.treenode package jd.gui.service.treenode
import groovy.transform.CompileStatic
import jd.gui.api.API import jd.gui.api.API
import jd.gui.api.feature.UriGettable import jd.gui.api.feature.UriGettable
import jd.gui.api.model.Container import jd.gui.api.model.Container
@ -17,6 +18,8 @@ import javax.swing.tree.DefaultMutableTreeNode
class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider { class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png')) static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png'))
static final Factory FACTORY = new Factory();
static { static {
// Early class loading // Early class loading
try { try {
@ -36,9 +39,46 @@ class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryPr
return new FileTreeNode( return new FileTreeNode(
entry, entry,
new TreeNodeBean(label:name, icon:CLASS_FILE_ICON), new TreeNodeBean(label:name, icon:CLASS_FILE_ICON),
new AbstractTypeFileTreeNodeFactoryProvider.PageFactory() { FACTORY
public <T extends JComponent & UriGettable> T make(API a, Container.Entry e) { new ClassFilePage(a, e) }
}
) )
} }
static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
return new ClassFilePage(a, e)
}
public String makeTip(API api, Container.Entry entry) {
def file = new File(entry.container.root.uri)
def tip = "<html>Location: $file.path"
entry.inputStream.withStream { is ->
is.skip(4) // Skip magic number
int minorVersion = readUnsignedShort(is)
int majorVersion = readUnsignedShort(is)
if (majorVersion >= 49) {
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
} else if (majorVersion >= 45) {
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
}
}
tip += "</html>"
return tip
}
/**
* @see java.io.DataInputStream#readUnsignedShort()
*/
@CompileStatic
int readUnsignedShort(InputStream is) throws IOException {
int ch1 = is.read()
int ch2 = is.read()
if ((ch1 | ch2) < 0)
throw new EOFException()
return (ch1 << 8) + (ch2 << 0)
}
}
} }

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.treenode
import jd.gui.api.API
import jd.gui.api.feature.UriGettable
import jd.gui.api.model.Container
import jd.gui.view.component.JavaFilePage
import jd.gui.view.data.TreeNodeBean
import javax.swing.*
import javax.swing.tree.DefaultMutableTreeNode
class JavaFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
static final ImageIcon JAVA_FILE_ICON = new ImageIcon(JavaFileTreeNodeFactoryProvider.class.classLoader.getResource('images/jcu_obj.png'))
static final Factory FACTORY = new Factory();
/**
* @return local + optional external selectors
*/
String[] getSelectors() { ['*:file:*.java'] + externalSelectors }
public <T extends DefaultMutableTreeNode & UriGettable> T make(API api, Container.Entry entry) {
int lastSlashIndex = entry.path.lastIndexOf('/')
def name = entry.path.substring(lastSlashIndex+1)
return new FileTreeNode(
entry,
new TreeNodeBean(label:name, icon:JAVA_FILE_ICON),
FACTORY
)
}
static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
return new JavaFilePage(a, e)
}
public String makeTip(API api, Container.Entry entry) {
def file = new File(entry.container.root.uri)
return "<html>Location: $file.path</html>"
}
}
}

View File

@ -13,22 +13,16 @@ import jd.core.process.DecompilerImpl
import jd.gui.api.API import jd.gui.api.API
import jd.gui.api.feature.* import jd.gui.api.feature.*
import jd.gui.api.model.Container import jd.gui.api.model.Container
import jd.gui.api.model.Indexes
import jd.gui.util.decompiler.ClassFileSourcePrinter import jd.gui.util.decompiler.ClassFileSourcePrinter
import jd.gui.util.decompiler.ContainerLoader import jd.gui.util.decompiler.ContainerLoader
import jd.gui.util.decompiler.GuiPreferences import jd.gui.util.decompiler.GuiPreferences
import jd.gui.util.matcher.DescriptorMatcher
import org.fife.ui.rsyntaxtextarea.DocumentRange import org.fife.ui.rsyntaxtextarea.DocumentRange
import org.fife.ui.rsyntaxtextarea.SyntaxConstants import org.fife.ui.rsyntaxtextarea.SyntaxConstants
import javax.swing.text.DefaultCaret import javax.swing.text.DefaultCaret
import java.awt.Color import java.awt.Color
import java.awt.Point
import java.util.regex.Pattern
class ClassFilePage class ClassFilePage extends TypePage implements PreferencesChangeListener {
extends CustomLineNumbersPage
implements UriGettable, IndexesChangeListener, LineNumberNavigable, FocusedTypeGettable, PreferencesChangeListener {
protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters' protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters'
protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix' protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix'
@ -37,15 +31,6 @@ class ClassFilePage
protected static final Decompiler DECOMPILER = new DecompilerImpl() protected static final Decompiler DECOMPILER = new DecompilerImpl()
protected API api
protected Container.Entry entry
protected Collection<Indexes> collectionOfIndexes
protected ArrayList<ReferenceData> references = new ArrayList<>()
protected HashMap<String, DeclarationData> declarations = new HashMap<>()
protected TreeMap<Integer, DeclarationData> typeDeclarations = new TreeMap<>()
protected ArrayList<StringData> strings = new ArrayList<>()
protected int maximumLineNumber = -1 protected int maximumLineNumber = -1
static { static {
@ -69,9 +54,7 @@ class ClassFilePage
} }
ClassFilePage(API api, Container.Entry entry) { ClassFilePage(API api, Container.Entry entry) {
// Init attributes super(api, entry)
this.api = api
this.entry = entry
// Init view // Init view
errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor')) errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor'))
// Display source // Display source
@ -111,43 +94,18 @@ class ClassFilePage
maximumLineNumber = getMaximumSourceLineNumber() maximumLineNumber = getMaximumSourceLineNumber()
} }
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA } @CompileStatic
protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
String v = preferences.get(key);
protected boolean isHyperlinkEnabled(HyperlinkPage.HyperlinkData hyperlinkData) { hyperlinkData.reference.enabled } if (v == null) {
return defaultValue;
protected void openHyperlink(int x, int y, HyperlinkPage.HyperlinkData hyperlinkData) { } else {
if (hyperlinkData.reference.enabled) { return Boolean.valueOf(v);
// Save current position in history
def location = textArea.getLocationOnScreen()
int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int))
def uri = entry.uri
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
// Open link
def reference = hyperlinkData.reference
def typeName = reference.type
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
def rootUri = entry.container.root.uri.toString()
def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) }
def fragment = typeName
if (reference.name) {
fragment += '-' + reference.name
}
if (reference.descriptor) {
fragment += '-' + reference.descriptor
}
if (sameContainerEntries) {
api.openURI(x, y, sameContainerEntries, null, fragment)
} else if (entries) {
api.openURI(x, y, entries, null, fragment)
}
} }
} }
// --- UriGettable --- // String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
URI getUri() { entry.uri }
// --- ContentSavable --- // // --- ContentSavable --- //
String getFileName() { String getFileName() {
@ -156,89 +114,6 @@ class ClassFilePage
return path.substring(0, index) + '.java' return path.substring(0, index) + '.java'
} }
// --- IndexesChangeListener --- //
@CompileStatic
void indexesChanged(Collection<Indexes> collectionOfIndexes) {
// Update the list of containers
this.collectionOfIndexes = collectionOfIndexes
// Refresh links
boolean refresh = false
for (def reference : references) {
def typeName = reference.type
boolean enabled
if (reference.name) {
typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry)
if (typeName) {
// Replace type with the real type containing the referenced member
reference.type = typeName
enabled = true
} else {
enabled = false
}
} else {
enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null
}
if (reference.enabled != enabled) {
reference.enabled = enabled
refresh = true
}
}
if (refresh) {
textArea.repaint()
}
}
protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) {
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
def rootUri = entry.container.root.uri.toString()
def sameContainerEntries = entries?.grep { Container.Entry e -> e.uri.toString().startsWith(rootUri) }
if (sameContainerEntries) {
return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries)
} else {
return searchTypeHavingMember(typeName, name, descriptor, entries)
}
}
@CompileStatic
protected String searchTypeHavingMember(String typeName, String name, String descriptor, List<Container.Entry> entries) {
for (def entry : entries) {
def type = api.getTypeFactory(entry).make(api, entry, null)
if (type) {
if (descriptor.indexOf('(') == -1) {
// Search a field
for (def field : type.fields) {
if (field.name.equals(name) && field.descriptor.equals(descriptor)) {
// Field found
return typeName
}
}
} else {
// Search a method
for (def method : type.methods) {
if (method.name.equals(name) && method.descriptor.equals(descriptor)) {
// Method found
return typeName
}
}
}
// Not found -> Search in super type
def typeOwnerName = searchTypeHavingMember(type.superName, name, descriptor, entry)
if (typeOwnerName) {
return typeOwnerName
}
}
}
return null
}
// --- LineNumberNavigable --- // // --- LineNumberNavigable --- //
int getMaximumLineNumber() { maximumLineNumber } int getMaximumLineNumber() { maximumLineNumber }
@ -253,218 +128,6 @@ class ClassFilePage
boolean checkLineNumber(int lineNumber) { lineNumber <= maximumLineNumber } boolean checkLineNumber(int lineNumber) { lineNumber <= maximumLineNumber }
// --- UriOpenable --- //
/**
* @param uri for URI format, @see jd.gui.api.feature.UriOpenable
*/
boolean openUri(URI uri) {
List<DocumentRange> ranges = []
def fragment = uri.fragment
def query = uri.query
textArea.highlighter.clearMarkAllHighlights()
if (fragment) {
matchFragmentAndAddDocumentRange(fragment, declarations, ranges)
}
if (query) {
Map<String, String> parameters = parseQuery(query)
if (parameters.containsKey('lineNumber')) {
def lineNumber = parameters.get('lineNumber')
if (lineNumber.isNumber()) {
goToLineNumber(lineNumber.toInteger())
return true
}
} else if (parameters.containsKey('position')) {
def position = parameters.get('position')
if (position.isNumber()) {
int pos = position.toInteger()
if (textArea.document.length > pos) {
ranges.add(new DocumentRange(pos, pos))
}
}
} else {
matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges)
}
}
if (ranges) {
textArea.markAllHighlightColor = SELECT_HIGHLIGHT_COLOR
textArea.markAll(ranges)
setCaretPositionAndCenter(ranges.sort().get(0))
}
return true
}
@CompileStatic
static void matchFragmentAndAddDocumentRange(
String fragment, HashMap<String, DeclarationData> declarations, List<DocumentRange> ranges) {
if ((fragment.indexOf('?') != -1) || (fragment.indexOf('*') != -1)) {
// Unknown type and/or descriptor ==> Select all and scroll to the first one
int lastDash = fragment.lastIndexOf('-')
if (lastDash == -1) {
// Search types
String slashAndTypeName = fragment.substring(1)
String typeName = fragment.substring(2)
for (def entry : declarations.entrySet()) {
if (entry.key.endsWith(slashAndTypeName) || entry.key.equals(typeName)) {
ranges.add(new DocumentRange(entry.value.startPosition, entry.value.endPosition))
}
}
} else {
def prefix = fragment.substring(0, lastDash+1)
def suffix = fragment.substring(lastDash+1)
def addRangeClosure
if (suffix.charAt(0) == '(') {
addRangeClosure = { String key, DeclarationData value ->
int index = key.lastIndexOf('-') + 1
if (DescriptorMatcher.matchMethodDescriptors(suffix, key.substring(index))) {
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
}
}
} else {
addRangeClosure = { String key, DeclarationData value ->
int index = key.lastIndexOf('-') + 1
if (DescriptorMatcher.matchFieldDescriptors(suffix, key.substring(index))) {
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
}
}
}
if (fragment.charAt(0) == '*') {
// Unknown type
String slashAndTypeNameAndName = prefix.substring(1)
String typeNameAndName = prefix.substring(2)
for (def entry : declarations.entrySet()) {
if ((entry.key.indexOf(slashAndTypeNameAndName) != -1) || (entry.key.startsWith(typeNameAndName))) {
addRangeClosure(entry.key, entry.value)
}
}
} else {
// Known type
for (def entry : declarations.entrySet()) {
if (entry.key.startsWith(prefix)) {
addRangeClosure(entry.key, entry.value)
}
}
}
}
} else {
// Known type and descriptor ==> Search and high light item
def data = declarations.get(fragment)
if (data) {
ranges.add(new DocumentRange(data.startPosition, data.endPosition))
}
}
}
@CompileStatic
static void matchQueryAndAddDocumentRange(
Map<String, String> parameters,
HashMap<String, DeclarationData> declarations, TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks, ArrayList<StringData> strings,
List<DocumentRange> ranges) {
def highlightFlags = parameters.get('highlightFlags')
def highlightPattern = parameters.get('highlightPattern')
if (highlightFlags && highlightPattern) {
def highlightScope = parameters.get('highlightScope')
def regexp = createRegExp(highlightPattern)
def pattern = Pattern.compile(regexp + '.*')
if (highlightFlags.indexOf('s') != -1) {
// Highlight strings
def patternForString = Pattern.compile(regexp)
for (def data : strings) {
if (matchScope(highlightScope, data.owner)) {
def matcher = patternForString.matcher(data.text)
int offset = data.startPosition
while(matcher.find()) {
ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end()))
}
}
}
}
boolean t = (highlightFlags.indexOf('t') != -1) // Highlight types
boolean f = (highlightFlags.indexOf('f') != -1) // Highlight fields
boolean m = (highlightFlags.indexOf('m') != -1) // Highlight methods
boolean c = (highlightFlags.indexOf('c') != -1) // Highlight constructors
if (highlightFlags.indexOf('d') != -1) {
// Highlight declarations
for (def entry : declarations.entrySet()) {
def declaration = entry.value
if (matchScope(highlightScope, declaration.type)) {
if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) {
matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.type), declaration.startPosition, declaration.endPosition, ranges)
}
if ((f && declaration.isAField()) || (m && declaration.isAMethod())) {
matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges)
}
}
}
}
if (highlightFlags.indexOf('r') != -1) {
// Highlight references
for (def entry : hyperlinks.entrySet()) {
def hyperlink = entry.value
def reference = ((HyperlinkReferenceData)hyperlink).reference
if (matchScope(highlightScope, reference.owner)) {
if ((t && reference.isAType()) || (c && reference.isAConstructor())) {
matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.type), hyperlink.startPosition, hyperlink.endPosition, ranges)
}
if ((f && reference.isAField()) || (m && reference.isAMethod())) {
matchAndAddDocumentRange(pattern, reference.name, hyperlink.startPosition, hyperlink.endPosition, ranges)
}
}
}
}
}
}
@CompileStatic
static boolean matchScope(String scope, String type) {
if (!scope)
return true
if (scope.charAt(0) == '*')
return type.endsWith(scope.substring(1)) || type.equals(scope.substring(2))
return type.equals(scope)
}
@CompileStatic
static void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List<DocumentRange> ranges) {
if (pattern.matcher(text).matches()) {
ranges.add(new DocumentRange(start, end))
}
}
@CompileStatic
static String getMostInnerTypeName(String typeName) {
int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1
int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1
int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex)
return typeName.substring(lastIndex)
}
// --- FocusedTypeGettable --- //
String getFocusedTypeName() { typeDeclarations.floorEntry(textArea.caretPosition)?.value?.type }
Container.Entry getEntry() { entry }
// --- PreferencesChangeListener --- // // --- PreferencesChangeListener --- //
void preferencesChanged(Map<String, String> preferences) { void preferencesChanged(Map<String, String> preferences) {
def caret = textArea.caret def caret = textArea.caret
@ -477,18 +140,16 @@ class ClassFilePage
@CompileStatic @CompileStatic
class Printer extends ClassFileSourcePrinter { class Printer extends ClassFileSourcePrinter {
protected StringBuffer stringBuffer protected StringBuffer stringBuffer = new StringBuffer(10*1024)
protected boolean realignmentLineNumber protected boolean realignmentLineNumber
protected boolean showPrefixThis protected boolean showPrefixThis
protected boolean unicodeEscape protected boolean unicodeEscape
protected HashMap<String, ReferenceData> referencesCache protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>()
Printer(GuiPreferences preferences) { Printer(GuiPreferences preferences) {
this.stringBuffer = new StringBuffer(10*1024)
this.realignmentLineNumber = preferences.getRealignmentLineNumber() this.realignmentLineNumber = preferences.getRealignmentLineNumber()
this.showPrefixThis = preferences.isShowPrefixThis() this.showPrefixThis = preferences.isShowPrefixThis()
this.unicodeEscape = preferences.isUnicodeEscape() this.unicodeEscape = preferences.isUnicodeEscape()
this.referencesCache = new HashMap<>()
} }
boolean getRealignmentLineNumber() { realignmentLineNumber } boolean getRealignmentLineNumber() { realignmentLineNumber }
@ -496,8 +157,7 @@ class ClassFilePage
boolean isUnicodeEscape() { unicodeEscape } boolean isUnicodeEscape() { unicodeEscape }
void append(char c) { stringBuffer.append(c) } void append(char c) { stringBuffer.append(c) }
void append(String s) { void append(String s) { stringBuffer.append(s) }
stringBuffer.append(s) }
// Manage line number and misalignment // Manage line number and misalignment
int textAreaLineNumber = 1 int textAreaLineNumber = 1
@ -526,52 +186,52 @@ class ClassFilePage
} }
} }
// --- Manage strings --- // // --- Add strings --- //
void printString(String s, String scopeInternalName) { void printString(String s, String scopeInternalName) {
strings.add(new StringData(stringBuffer.length(), s.length(), s, scopeInternalName)) strings.add(new TypePage.StringData(stringBuffer.length(), s.length(), s, scopeInternalName))
super.printString(s, scopeInternalName) super.printString(s, scopeInternalName)
} }
// --- Manage references --- // // --- Add references --- //
void printTypeImport(String internalName, String name) { void printTypeImport(String internalName, String name) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, null))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, null)))
super.printTypeImport(internalName, name) super.printTypeImport(internalName, name)
} }
void printType(String internalName, String name, String scopeInternalName) { void printType(String internalName, String name, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, scopeInternalName)))
super.printType(internalName, name, scopeInternalName) super.printType(internalName, name, scopeInternalName)
} }
void printField(String internalName, String name, String descriptor, String scopeInternalName) { void printField(String internalName, String name, String descriptor, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
super.printField(internalName, name, descriptor, scopeInternalName) super.printField(internalName, name, descriptor, scopeInternalName)
} }
void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) { void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
super.printStaticField(internalName, name, descriptor, scopeInternalName) super.printStaticField(internalName, name, descriptor, scopeInternalName)
} }
void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) { void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, "<init>", descriptor, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, "<init>", descriptor, scopeInternalName)))
super.printConstructor(internalName, name, descriptor, scopeInternalName) super.printConstructor(internalName, name, descriptor, scopeInternalName)
} }
void printMethod(String internalName, String name, String descriptor, String scopeInternalName) { void printMethod(String internalName, String name, String descriptor, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
super.printMethod(internalName, name, descriptor, scopeInternalName) super.printMethod(internalName, name, descriptor, scopeInternalName)
} }
void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) { void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) {
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName))) addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
super.printStaticMethod(internalName, name, descriptor, scopeInternalName) super.printStaticMethod(internalName, name, descriptor, scopeInternalName)
} }
ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) { TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName
def reference = referencesCache.get(key) def reference = referencesCache.get(key)
if (reference == null) { if (reference == null) {
reference = new ReferenceData(internalName, name, descriptor, scopeInternalName) reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName)
referencesCache.put(key, reference) referencesCache.put(key, reference)
references.add(reference) references.add(reference)
} }
@ -579,132 +239,37 @@ class ClassFilePage
return reference return reference
} }
// --- Manage declarations --- // // --- Add declarations --- //
void printTypeDeclaration(String internalName, String name) { void printTypeDeclaration(String internalName, String name) {
def data = new DeclarationData(stringBuffer.length(), name.length(), internalName, null, null) def data = new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, null, null)
declarations.put(internalName, data) declarations.put(internalName, data)
typeDeclarations.put(stringBuffer.length(), data) typeDeclarations.put(stringBuffer.length(), data)
super.printTypeDeclaration(internalName, name) super.printTypeDeclaration(internalName, name)
} }
void printFieldDeclaration(String internalName, String name, String descriptor) { void printFieldDeclaration(String internalName, String name, String descriptor) {
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
super.printFieldDeclaration(internalName, name, descriptor) super.printFieldDeclaration(internalName, name, descriptor)
} }
void printStaticFieldDeclaration(String internalName, String name, String descriptor) { void printStaticFieldDeclaration(String internalName, String name, String descriptor) {
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
super.printStaticFieldDeclaration(internalName, name, descriptor) super.printStaticFieldDeclaration(internalName, name, descriptor)
} }
void printConstructorDeclaration(String internalName, String name, String descriptor) { void printConstructorDeclaration(String internalName, String name, String descriptor) {
declarations.put(internalName + '-<init>-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, "<init>", descriptor)) declarations.put(internalName + '-<init>-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, "<init>", descriptor))
super.printConstructorDeclaration(internalName, name, descriptor) super.printConstructorDeclaration(internalName, name, descriptor)
} }
void printMethodDeclaration(String internalName, String name, String descriptor) { void printMethodDeclaration(String internalName, String name, String descriptor) {
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
super.printMethodDeclaration(internalName, name, descriptor) super.printMethodDeclaration(internalName, name, descriptor)
} }
void printStaticMethodDeclaration(String internalName, String name, String descriptor) { void printStaticMethodDeclaration(String internalName, String name, String descriptor) {
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor)) declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
super.printStaticMethodDeclaration(internalName, name, descriptor) super.printStaticMethodDeclaration(internalName, name, descriptor)
} }
String toString() { stringBuffer.toString() } String toString() { stringBuffer.toString() }
} }
@CompileStatic
static class StringData {
int startPosition
int endPosition
String text
String owner
StringData(int startPosition, int length, String text, String owner) {
this.startPosition = startPosition
this.endPosition = startPosition + length
this.text = text
this.owner = owner
}
}
@CompileStatic
static class DeclarationData {
int startPosition
int endPosition
String type
/**
* Field or method name or null for type
*/
String name
String descriptor
DeclarationData(int startPosition, int length, String type, String name, String descriptor) {
this.startPosition = startPosition
this.endPosition = startPosition + length
this.type = type
this.name = name
this.descriptor = descriptor
}
boolean isAType() { name == null }
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
boolean isAConstructor() { "<init>".equals(name) }
}
@CompileStatic
static class HyperlinkReferenceData extends HyperlinkPage.HyperlinkData {
ReferenceData reference
HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) {
super(startPosition, startPosition+length)
this.reference = reference
}
}
@CompileStatic
static class ReferenceData {
String type
/**
* Field or method name or null for type
*/
String name
/**
* Field or method descriptor or null for type
*/
String descriptor
/**
* Internal type name containing reference or null for "import" statement.
* Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type".
*/
String owner
/**
* "Enabled" flag for link of reference
*/
boolean enabled = false
ReferenceData(String type, String name, String descriptor, String owner) {
this.type = type
this.name = name
this.descriptor = descriptor
this.owner = owner
}
boolean isAType() { name == null }
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
boolean isAConstructor() { "<init>".equals(name) }
}
@CompileStatic
protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
String v = preferences.get(key);
if (v == null) {
return defaultValue;
} else {
return Boolean.valueOf(v);
}
}
} }

View File

@ -15,7 +15,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants
import java.awt.* import java.awt.*
class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener { class EjbJarXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
protected API api protected API api
protected Container.Entry entry protected Container.Entry entry
protected Collection<Indexes> collectionOfIndexes protected Collection<Indexes> collectionOfIndexes
@ -133,7 +133,7 @@ class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, Indexe
int startIndex = position + text.indexOf(trim) int startIndex = position + text.indexOf(trim)
int endIndex = startIndex + trim.length() int endIndex = startIndex + trim.length()
def internalTypeName = trim.replace('.', '/') def internalTypeName = trim.replace('.', '/')
addHyperlink(new TypeHyperlinkPage.TypeHyperlinkData(startIndex, endIndex, internalTypeName)) addHyperlink(new TypeReferencePage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
} }
} }
} }

View File

@ -0,0 +1,735 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.view.component
import groovy.transform.CompileStatic
import jd.gui.api.API
import jd.gui.api.model.Container
import jd.gui.util.parser.antlr.ANTLRParser
import jd.gui.util.parser.antlr.AbstractJavaListener
import jd.gui.util.parser.antlr.JavaParser
import org.antlr.v4.runtime.ANTLRInputStream
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.tree.ParseTree
import org.antlr.v4.runtime.tree.TerminalNode
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
class JavaFilePage extends TypePage {
JavaFilePage(API api, Container.Entry entry) {
super(api, entry)
// Load content file
def text = entry.inputStream.text.replace('\r\n', '\n').replace('\r', '\n')
// Parse
def declarationListener = new DeclarationListener(entry)
def referenceListener = new ReferenceListener(entry)
ANTLRParser.parse(new ANTLRInputStream(text), declarationListener)
referenceListener.init(declarationListener)
ANTLRParser.parse(new ANTLRInputStream(text), referenceListener)
// Display
setText(text)
// Show hyperlinks
indexesChanged(api.collectionOfIndexes)
}
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
// --- ContentSavable --- //
String getFileName() {
def path = entry.path
int index = path.lastIndexOf('/')
return path.substring(index+1)
}
@CompileStatic
class DeclarationListener extends AbstractJavaListener {
protected StringBuffer sbTypeDeclaration = new StringBuffer()
protected String currentInternalTypeName
DeclarationListener(Container.Entry entry) { super(entry) }
HashMap<String, String> getNameToInternalTypeName() { super.nameToInternalTypeName }
// --- Add declarations --- //
void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
super.enterPackageDeclaration(ctx);
if (! packageName.isEmpty()) {
sbTypeDeclaration.append(packageName).append('/');
}
}
void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier()
String internalTypeName = concatIdentifiers(identifiers)
String typeName = identifiers.get(identifiers.size()-1).symbol.text
nameToInternalTypeName.put(typeName, internalTypeName)
}
void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
void enterTypeDeclaration(ParserRuleContext ctx) {
// Type declaration
def identifier = ctx.getToken(JavaParser.Identifier, 0);
def typeName = identifier.text
int position = identifier.symbol.startIndex
int length = sbTypeDeclaration.length();
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
sbTypeDeclaration.append(typeName);
} else {
sbTypeDeclaration.append('$').append(typeName);
}
currentInternalTypeName = sbTypeDeclaration.toString()
nameToInternalTypeName.put(typeName, currentInternalTypeName);
// Super type reference
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0)
String superInternalTypeName = superType ? resolveInternalTypeName(superType.classOrInterfaceType().Identifier()) : null
def data = new TypeDeclarationData(position, typeName.length(), currentInternalTypeName, null, null, superInternalTypeName)
declarations.put(currentInternalTypeName, data)
typeDeclarations.put(position, data)
}
void exitTypeDeclaration() {
int index = sbTypeDeclaration.lastIndexOf('$');
if (index == -1) {
index = sbTypeDeclaration.lastIndexOf('/') + 1;
}
if (index == -1) {
sbTypeDeclaration.setLength(0);
} else {
sbTypeDeclaration.setLength(index);
}
currentInternalTypeName = sbTypeDeclaration.toString()
}
public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
if (ctx.getChildCount() == 2) {
def first = ctx.getChild(0);
if (first instanceof TerminalNode) {
if (first.getSymbol().type == JavaParser.STATIC) {
String name = first.text
int position = first.getSymbol().startIndex
declarations.put(currentInternalTypeName + '-<clinit>-()V', new TypePage.DeclarationData(position, 5, currentInternalTypeName, name, '()V'))
}
}
}
}
void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
def typeContext = ctx.type();
for (def constantDeclaratorContext : ctx.constantDeclarator()) {
def identifier = constantDeclaratorContext.Identifier()
def name = identifier.text
int dimensionOnVariable = countDimension(constantDeclaratorContext.children)
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
int position = identifier.symbol.startIndex
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
}
}
void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
def typeContext = ctx.type();
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
def variableDeclaratorId = declaration.variableDeclaratorId()
def identifier = variableDeclaratorId.Identifier()
def name = identifier.text
int dimensionOnVariable = countDimension(variableDeclaratorId.children)
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
int position = identifier.symbol.startIndex
def data = new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor)
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, data)
}
}
void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
}
void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
}
void enterMethodDeclaration(
ParserRuleContext ctx, TerminalNode identifier,
JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
def name = identifier.text
def paramDescriptors = createParamDescriptors(formalParameters.formalParameterList())
def returnDescriptor = createDescriptor(returnType, 0)
def descriptor = paramDescriptors + returnDescriptor
int position = identifier.symbol.startIndex
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
}
void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
def identifier = ctx.Identifier()
def name = identifier.text
def paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList())
def descriptor = paramDescriptors + "V"
int position = identifier.symbol.startIndex
declarations.put(currentInternalTypeName + '-<init>-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
}
String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
StringBuffer paramDescriptors = null
if (formalParameterList != null) {
def formalParameters = formalParameterList.formalParameter()
paramDescriptors = new StringBuffer("(")
for (def formalParameter : formalParameters) {
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children)
def descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter)
paramDescriptors.append(descriptor)
}
}
return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
}
}
@CompileStatic
class ReferenceListener extends AbstractJavaListener {
protected StringBuffer sbTypeDeclaration = new StringBuffer()
protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>()
protected String currentInternalTypeName
protected Context currentContext = null
ReferenceListener(Container.Entry entry) { super(entry) }
void init(DeclarationListener declarationListener) {
this.nameToInternalTypeName.putAll(declarationListener.nameToInternalTypeName)
}
// --- Add declarations --- //
void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
super.enterPackageDeclaration(ctx);
if (! packageName.isEmpty()) {
sbTypeDeclaration.append(packageName).append('/');
}
}
void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier()
int position = identifiers.get(0).symbol.startIndex
String internalTypeName = concatIdentifiers(identifiers)
addHyperlink(new TypePage.HyperlinkReferenceData(position, internalTypeName.length(), newReferenceData(internalTypeName, null, null, null)))
}
void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
void enterTypeDeclaration(ParserRuleContext ctx) {
// Type declaration
def identifier = ctx.getToken(JavaParser.Identifier, 0);
def typeName = identifier.text
int length = sbTypeDeclaration.length();
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
sbTypeDeclaration.append(typeName);
} else {
sbTypeDeclaration.append('$').append(typeName);
}
currentInternalTypeName = sbTypeDeclaration.toString()
currentContext = new Context(currentContext)
}
void exitTypeDeclaration() {
int index = sbTypeDeclaration.lastIndexOf('$');
if (index == -1) {
index = sbTypeDeclaration.lastIndexOf('/') + 1;
}
if (index == -1) {
sbTypeDeclaration.setLength(0);
} else {
sbTypeDeclaration.setLength(index);
}
currentInternalTypeName = sbTypeDeclaration.toString()
}
void enterFormalParameters(JavaParser.FormalParametersContext ctx) {
def formalParameterList = ctx.formalParameterList()
if (formalParameterList != null) {
def formalParameters = formalParameterList.formalParameter()
for (def formalParameter : formalParameters) {
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children)
def descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter)
def name = formalParameter.variableDeclaratorId().Identifier().symbol.text
currentContext.nameToDescriptor.put(name, descriptor)
}
}
}
// --- Add references --- //
void enterType(JavaParser.TypeContext ctx) {
// Add type reference
def classOrInterfaceType = ctx.classOrInterfaceType()
if (classOrInterfaceType != null) {
def identifiers = classOrInterfaceType.Identifier()
def name = concatIdentifiers(identifiers)
def internalTypeName = resolveInternalTypeName(identifiers)
int position = identifiers.get(0).symbol.startIndex
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
}
}
void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) {
def typeContext = ctx.type()
for (def variableDeclarator : ctx.variableDeclarators().variableDeclarator()) {
def variableDeclaratorId = variableDeclarator.variableDeclaratorId()
int dimensionOnVariable = countDimension(variableDeclaratorId.children)
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
def name = variableDeclarator.variableDeclaratorId().Identifier().getSymbol().getText()
currentContext.nameToDescriptor.put(name, descriptor)
}
}
void enterCreator(JavaParser.CreatorContext ctx) {
enterNewExpression(ctx.createdName().Identifier(), ctx.classCreatorRest())
}
void enterInnerCreator(JavaParser.InnerCreatorContext ctx) {
enterNewExpression(Collections.singletonList(ctx.Identifier()), ctx.classCreatorRest())
}
void enterNewExpression(List<TerminalNode> identifiers, JavaParser.ClassCreatorRestContext classCreatorRest) {
if (identifiers.size() > 0) {
def name = concatIdentifiers(identifiers)
def internalTypeName = resolveInternalTypeName(identifiers)
int position = identifiers.get(0).symbol.startIndex
if (classCreatorRest) {
// Constructor call -> Add a link to the constructor declaration
def expressionList = classCreatorRest.arguments().expressionList()
def descriptor = expressionList ? getParametersDescriptor(expressionList).append('V').toString() : '()V'
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, '<init>', descriptor, currentInternalTypeName)))
} else {
// New type array -> Add a link to the type declaration
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
}
}
}
void enterExpression(JavaParser.ExpressionContext ctx) {
switch (ctx.getChildCount()) {
case 1:
TerminalNode identifier0 = getToken(ctx.children, JavaParser.Identifier, 0);
if (identifier0 != null) {
if (isAField(ctx)) {
def primaryContext = ctx.primary()
if (primaryContext) {
String fieldName = primaryContext.literal().StringLiteral();
if (!currentContext.getDescriptor(fieldName) != null) {
// Not a local variable or a method parameter
def fieldTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, fieldName)
int position = ctx.Identifier().getSymbol().startIndex
addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, '?', currentInternalTypeName)))
}
}
}
} else {
def identifier = ctx.primary().Identifier()
if (identifier) {
def symbol = identifier.getSymbol()
def name = symbol.text
def internalTypeName = nameToInternalTypeName.get(name)
if (internalTypeName) {
int position = symbol.startIndex
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
}
}
}
break;
case 3:
if (getToken(ctx.children, JavaParser.DOT, 1) != null) {
// Search "expression '.' Identifier" : field reference
def identifier3 = getToken(ctx.children, JavaParser.Identifier, 2);
if ((identifier3 != null) && isAField(ctx)) {
def fieldTypeName = getInternalTypeName(ctx.getChild(0))
if (fieldTypeName) {
int position = identifier3.symbol.startIndex
def fieldName = identifier3.getText()
addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, '?', currentInternalTypeName)))
}
}
} else if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
// Search "expression '(' ')'" : method reference
if (getToken(ctx.children, JavaParser.RPAREN, 2) != null) {
enterCallMethodExpression(ctx, null)
}
}
break;
case 4:
if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
// Search "expression '(' expressionList ')'" : method reference
if (getToken(ctx.children, JavaParser.RPAREN, 3) != null) {
def expressionListContext = ctx.expressionList();
if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
enterCallMethodExpression(ctx, expressionListContext)
}
}
}
break;
}
}
void enterCallMethodExpression(JavaParser.ExpressionContext ctx, JavaParser.ExpressionListContext expressionListContext) {
ParseTree first = ctx.children.get(0)
if (first instanceof JavaParser.ExpressionContext) {
switch (first.getChildCount()) {
case 1:
def primary = first.primary()
def identifier = primary.Identifier()
if (identifier) {
def symbol = identifier.getSymbol()
if (symbol) {
String methodName = symbol.text
String methodTypeName = searchInternalTypeNameForThisMethodName(currentInternalTypeName, methodName)
if (methodTypeName) {
int position = symbol.startIndex
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)))
}
}
} else {
def symbol = primary.getChild(TerminalNode.class, 0).getSymbol()
if (symbol) {
switch (symbol.type) {
case JavaParser.THIS:
int position = symbol.startIndex
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
addHyperlink(new TypePage.HyperlinkReferenceData(position, 4, newReferenceData(currentInternalTypeName, '<init>', methodDescriptor, currentInternalTypeName)))
break
case JavaParser.SUPER:
def data = declarations.get(currentInternalTypeName)
if (data instanceof TypeDeclarationData) {
int position = symbol.startIndex
def methodTypeName = ((TypeDeclarationData) data).superTypeName
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
addHyperlink(new TypePage.HyperlinkReferenceData(position, 5, newReferenceData(methodTypeName, '<init>', methodDescriptor, currentInternalTypeName)))
}
break
}
}
}
break
case 3:
// Search "expression '.' Identifier"
ParseTree dot = first.getChild(1)
if ((dot instanceof TerminalNode) && (dot.getSymbol().getType() == JavaParser.DOT)) {
ParseTree identifier3 = first.getChild(2)
if ((identifier3 instanceof TerminalNode) && (identifier3.getSymbol().type == JavaParser.Identifier)) {
String methodTypeName = getInternalTypeName(first.getChild(0))
if (methodTypeName) {
int position = identifier3.getSymbol().startIndex
def methodName = identifier3.getText()
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)))
}
}
}
break
}
}
}
StringBuffer getParametersDescriptor(JavaParser.ExpressionListContext expressionListContext) {
def sb = new StringBuffer('(')
for (def exp : expressionListContext.expression()) sb.append('?')
sb.append(')')
return sb
}
boolean isAField(JavaParser.ExpressionContext ctx) {
def parent = ctx.parent
if (parent instanceof JavaParser.ExpressionContext) {
int size = parent.getChildCount();
if (parent.getChild(size - 1) != ctx) {
for (int i=0; i<size; i++) {
if (parent.getChild(i) == ctx) {
def next = parent.getChild(i+1)
if (next instanceof TerminalNode) {
switch (next.getSymbol().getType()) {
case JavaParser.DOT:
case JavaParser.LPAREN:
return false
}
}
}
}
}
}
return true
}
String getInternalTypeName(ParseTree pt) {
if (pt instanceof JavaParser.ExpressionContext) {
if (pt.getChildCount() == 1) {
def primary = pt.primary()
def identifier = primary.Identifier()
if (identifier) {
String name = identifier.getSymbol().text
String descriptor = currentContext.getDescriptor(name);
if (descriptor) {
// Is a local variable or a method parameter
if (descriptor.charAt(0) == 'L') {
return descriptor.substring(1, descriptor.length() - 1)
}
} else {
String internalTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, name)
if (internalTypeName) {
// Is a field
return internalTypeName
} else {
internalTypeName = resolveInternalTypeName(Collections.singletonList(identifier))
if (internalTypeName) {
// Is a type
return internalTypeName
} else {
// Not found
return null
}
}
}
} else {
def symbol = primary.getChild(TerminalNode.class, 0)?.getSymbol()
if (symbol) {
switch (symbol.type) {
case JavaParser.THIS:
return currentInternalTypeName
case JavaParser.SUPER:
def data = declarations.get(currentInternalTypeName)
if (data instanceof TypeDeclarationData) {
return ((TypeDeclarationData)data).superTypeName
} else {
return null
}
}
}
}
}
}
return null
}
String searchInternalTypeNameForThisFieldName(String internalTypeName, String name) {
String prefix = internalTypeName + '-' + name + '-'
int length = prefix.length()
for (def entry : declarations.entrySet()) {
if (entry.key.startsWith(prefix) && (entry.key.charAt(length) != '(')) {
return entry.value.typeName
}
}
// Not found
int index = internalTypeName.lastIndexOf('$')
if (index != -1) {
// Search in the outer type
internalTypeName = internalTypeName.substring(0, index)
return searchInternalTypeNameForThisFieldName(internalTypeName, name)
}
// Not found
return null
}
String searchInternalTypeNameForThisMethodName(String internalTypeName, String name) {
String prefix = internalTypeName + '-' + name + '-('
for (def entry : declarations.entrySet()) {
if (entry.key.startsWith(prefix)) {
return entry.value.typeName
}
}
// Not found
int index = internalTypeName.lastIndexOf('$')
if (index != -1) {
// Search in the outer type
internalTypeName = internalTypeName.substring(0, index)
return searchInternalTypeNameForThisMethodName(internalTypeName, name)
}
// Not found
return null
}
TerminalNode getToken(List<ParseTree> children, int type, int i) {
ParseTree pt = children.get(i);
if (pt instanceof TerminalNode) {
if (((TerminalNode)pt).getSymbol().getType() == type) {
return (TerminalNode)pt;
}
}
return null;
}
void enterBlock(JavaParser.BlockContext ctx) {
currentContext = new Context(currentContext)
}
void exitBlock(JavaParser.BlockContext ctx) {
currentContext = currentContext.outerContext
}
TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName
def reference = referencesCache.get(key)
if (reference == null) {
reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName)
referencesCache.put(key, reference)
references.add(reference)
}
return reference
}
// --- Add strings --- //
void enterLiteral(JavaParser.LiteralContext ctx) {
def stringLiteral = ctx.StringLiteral()
if (stringLiteral != null) {
String str = stringLiteral.getSymbol().getText()
int position = stringLiteral.getSymbol().getStartIndex()
strings.add(new TypePage.StringData(position, str.length(), str, currentInternalTypeName))
}
}
}
@CompileStatic
static class Context {
Context outerContext
HashMap<String, String> nameToDescriptor = new HashMap<>()
Context(Context outerContext) {
this.outerContext = outerContext
}
/**
* @param name Parameter or variable name
* @return Qualified type name
*/
String getDescriptor(String name) {
String descriptor = nameToDescriptor.get(name)
if ((descriptor == null) && (outerContext != null)) {
descriptor = outerContext.getDescriptor(name)
}
return descriptor
}
}
@CompileStatic
static class TypeDeclarationData extends TypePage.DeclarationData {
String superTypeName
TypeDeclarationData(int startPosition, int length, String type, String name, String descriptor, String superTypeName) {
super(startPosition, length, type, name, descriptor)
this.superTypeName = superTypeName
}
}
}

View File

@ -213,7 +213,7 @@ class TextPage extends JPanel implements ContentCopyable, ContentSelectable, Lin
// --- LineNumberNavigable --- // // --- LineNumberNavigable --- //
int getMaximumLineNumber() { int getMaximumLineNumber() {
return textArea.getLineOfOffset(textArea.document.length) return textArea.getLineOfOffset(textArea.document.length) + 1
} }
void goToLineNumber(int lineNumber) { void goToLineNumber(int lineNumber) {

View File

@ -0,0 +1,457 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.view.component
import groovy.transform.CompileStatic
import jd.gui.api.API
import jd.gui.api.feature.FocusedTypeGettable
import jd.gui.api.feature.IndexesChangeListener
import jd.gui.api.feature.UriGettable
import jd.gui.api.feature.UriOpenable
import jd.gui.api.model.Container
import jd.gui.api.model.Indexes
import jd.gui.util.matcher.DescriptorMatcher
import org.fife.ui.rsyntaxtextarea.DocumentRange
import java.awt.Point
import java.util.regex.Pattern
abstract class TypePage extends CustomLineNumbersPage implements UriGettable, UriOpenable, IndexesChangeListener, FocusedTypeGettable {
protected API api
protected Container.Entry entry
protected Collection<Indexes> collectionOfIndexes
protected HashMap<String, DeclarationData> declarations = new HashMap<>()
protected TreeMap<Integer, DeclarationData> typeDeclarations = new TreeMap<>()
protected ArrayList<ReferenceData> references = new ArrayList<>()
protected ArrayList<StringData> strings = new ArrayList<>()
TypePage(API api, Container.Entry entry) {
// Init attributes
this.api = api
this.entry = entry
}
protected boolean isHyperlinkEnabled(HyperlinkPage.HyperlinkData hyperlinkData) { hyperlinkData.reference.enabled }
protected void openHyperlink(int x, int y, HyperlinkPage.HyperlinkData hyperlinkData) {
if (hyperlinkData.reference.enabled) {
// Save current position in history
def location = textArea.getLocationOnScreen()
int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int))
def uri = entry.uri
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
// Open link
ReferenceData reference = hyperlinkData.reference
def typeName = reference.typeName
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it != null }
def fragment = typeName
if (reference.name) {
fragment += '-' + reference.name
}
if (reference.descriptor) {
fragment += '-' + reference.descriptor
}
if (entries.contains(entry)) {
api.openURI(new URI(uri.scheme, uri.authority, uri.path, fragment))
} else {
def rootUri = entry.container.root.uri.toString()
def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) }
if (sameContainerEntries) {
api.openURI(x, y, sameContainerEntries, null, fragment)
} else if (entries) {
api.openURI(x, y, entries, null, fragment)
}
}
}
}
// --- UriGettable --- //
URI getUri() { entry.uri }
// --- UriOpenable --- //
/**
* @param uri for URI format, @see jd.gui.api.feature.UriOpenable
*/
boolean openUri(URI uri) {
List<DocumentRange> ranges = []
def fragment = uri.fragment
def query = uri.query
textArea.highlighter.clearMarkAllHighlights()
if (fragment) {
matchFragmentAndAddDocumentRange(fragment, declarations, ranges)
}
if (query) {
Map<String, String> parameters = parseQuery(query)
if (parameters.containsKey('lineNumber')) {
def lineNumber = parameters.get('lineNumber')
if (lineNumber.isNumber()) {
goToLineNumber(lineNumber.toInteger())
return true
}
} else if (parameters.containsKey('position')) {
def position = parameters.get('position')
if (position.isNumber()) {
int pos = position.toInteger()
if (textArea.document.length > pos) {
ranges.add(new DocumentRange(pos, pos))
}
}
} else {
matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges)
}
}
if (ranges) {
textArea.markAllHighlightColor = SELECT_HIGHLIGHT_COLOR
textArea.markAll(ranges)
setCaretPositionAndCenter(ranges.sort().get(0))
}
return true
}
@CompileStatic
static void matchFragmentAndAddDocumentRange(
String fragment, HashMap<String, DeclarationData> declarations, List<DocumentRange> ranges) {
if ((fragment.indexOf('?') != -1) || (fragment.indexOf('*') != -1)) {
// Unknown type and/or descriptor ==> Select all and scroll to the first one
int lastDash = fragment.lastIndexOf('-')
if (lastDash == -1) {
// Search types
String slashAndTypeName = fragment.substring(1)
String typeName = fragment.substring(2)
for (def entry : declarations.entrySet()) {
if (entry.key.endsWith(slashAndTypeName) || entry.key.equals(typeName)) {
ranges.add(new DocumentRange(entry.value.startPosition, entry.value.endPosition))
}
}
} else {
def prefix = fragment.substring(0, lastDash+1)
def suffix = fragment.substring(lastDash+1)
def addRangeClosure
if (suffix.charAt(0) == '(') {
addRangeClosure = { String key, DeclarationData value ->
int index = key.lastIndexOf('-') + 1
if (DescriptorMatcher.matchMethodDescriptors(suffix, key.substring(index))) {
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
}
}
} else {
addRangeClosure = { String key, DeclarationData value ->
int index = key.lastIndexOf('-') + 1
if (DescriptorMatcher.matchFieldDescriptors(suffix, key.substring(index))) {
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
}
}
}
if (fragment.charAt(0) == '*') {
// Unknown type
String slashAndTypeNameAndName = prefix.substring(1)
String typeNameAndName = prefix.substring(2)
for (def entry : declarations.entrySet()) {
if ((entry.key.indexOf(slashAndTypeNameAndName) != -1) || (entry.key.startsWith(typeNameAndName))) {
addRangeClosure(entry.key, entry.value)
}
}
} else {
// Known type
for (def entry : declarations.entrySet()) {
if (entry.key.startsWith(prefix)) {
addRangeClosure(entry.key, entry.value)
}
}
}
}
} else {
// Known type and descriptor ==> Search and high light item
def data = declarations.get(fragment)
if (data) {
ranges.add(new DocumentRange(data.startPosition, data.endPosition))
}
}
}
@CompileStatic
static void matchQueryAndAddDocumentRange(
Map<String, String> parameters,
HashMap<String, DeclarationData> declarations, TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks, ArrayList<StringData> strings,
List<DocumentRange> ranges) {
def highlightFlags = parameters.get('highlightFlags')
def highlightPattern = parameters.get('highlightPattern')
if (highlightFlags && highlightPattern) {
def highlightScope = parameters.get('highlightScope')
def regexp = createRegExp(highlightPattern)
def pattern = Pattern.compile(regexp + '.*')
if (highlightFlags.indexOf('s') != -1) {
// Highlight strings
def patternForString = Pattern.compile(regexp)
for (def data : strings) {
if (matchScope(highlightScope, data.owner)) {
def matcher = patternForString.matcher(data.text)
int offset = data.startPosition
while(matcher.find()) {
ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end()))
}
}
}
}
boolean t = (highlightFlags.indexOf('t') != -1) // Highlight types
boolean f = (highlightFlags.indexOf('f') != -1) // Highlight fields
boolean m = (highlightFlags.indexOf('m') != -1) // Highlight methods
boolean c = (highlightFlags.indexOf('c') != -1) // Highlight constructors
if (highlightFlags.indexOf('d') != -1) {
// Highlight declarations
for (def entry : declarations.entrySet()) {
def declaration = entry.value
if (matchScope(highlightScope, declaration.typeName)) {
if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) {
matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.typeName), declaration.startPosition, declaration.endPosition, ranges)
}
if ((f && declaration.isAField()) || (m && declaration.isAMethod())) {
matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges)
}
}
}
}
if (highlightFlags.indexOf('r') != -1) {
// Highlight references
for (def entry : hyperlinks.entrySet()) {
def hyperlink = entry.value
def reference = ((HyperlinkReferenceData)hyperlink).reference
if (matchScope(highlightScope, reference.owner)) {
if ((t && reference.isAType()) || (c && reference.isAConstructor())) {
matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.typeName), hyperlink.startPosition, hyperlink.endPosition, ranges)
}
if ((f && reference.isAField()) || (m && reference.isAMethod())) {
matchAndAddDocumentRange(pattern, reference.name, hyperlink.startPosition, hyperlink.endPosition, ranges)
}
}
}
}
}
}
@CompileStatic
static boolean matchScope(String scope, String type) {
if (!scope)
return true
if (scope.charAt(0) == '*')
return type.endsWith(scope.substring(1)) || type.equals(scope.substring(2))
return type.equals(scope)
}
@CompileStatic
static void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List<DocumentRange> ranges) {
if (pattern.matcher(text).matches()) {
ranges.add(new DocumentRange(start, end))
}
}
@CompileStatic
static String getMostInnerTypeName(String typeName) {
int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1
int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1
int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex)
return typeName.substring(lastIndex)
}
// --- FocusedTypeGettable --- //
String getFocusedTypeName() { typeDeclarations.floorEntry(textArea.caretPosition)?.value?.typeName }
Container.Entry getEntry() { entry }
// --- IndexesChangeListener --- //
@CompileStatic
void indexesChanged(Collection<Indexes> collectionOfIndexes) {
// Update the list of containers
this.collectionOfIndexes = collectionOfIndexes
// Refresh links
boolean refresh = false
for (def reference : references) {
def typeName = reference.typeName
boolean enabled
if (reference.name) {
typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry)
if (typeName) {
// Replace type with the real type containing the referenced member
reference.typeName = typeName
enabled = true
} else {
enabled = false
}
} else {
enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null
}
if (reference.enabled != enabled) {
reference.enabled = enabled
refresh = true
}
}
if (refresh) {
textArea.repaint()
}
}
protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) {
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
def rootUri = entry.container.root.uri.toString()
def sameContainerEntries = entries?.grep { Container.Entry e -> e.uri.toString().startsWith(rootUri) }
if (sameContainerEntries) {
return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries)
} else {
return searchTypeHavingMember(typeName, name, descriptor, entries)
}
}
@CompileStatic
protected String searchTypeHavingMember(String typeName, String name, String descriptor, List<Container.Entry> entries) {
for (def entry : entries) {
def type = api.getTypeFactory(entry).make(api, entry, typeName)
if (type) {
if (descriptor.indexOf('(') == -1) {
// Search a field
for (def field : type.fields) {
if (field.name.equals(name) && DescriptorMatcher.matchFieldDescriptors(field.descriptor, descriptor)) {
// Field found
return typeName
}
}
} else {
// Search a method
for (def method : type.methods) {
if (method.name.equals(name) && DescriptorMatcher.matchMethodDescriptors(method.descriptor, descriptor)) {
// Method found
return typeName
}
}
}
// Not found -> Search in super type
def typeOwnerName = searchTypeHavingMember(type.superName, name, descriptor, entry)
if (typeOwnerName) {
return typeOwnerName
}
}
}
return null
}
@CompileStatic
static class StringData {
int startPosition
int endPosition
String text
String owner
StringData(int startPosition, int length, String text, String owner) {
this.startPosition = startPosition
this.endPosition = startPosition + length
this.text = text
this.owner = owner
}
}
@CompileStatic
static class DeclarationData {
int startPosition
int endPosition
String typeName
/**
* Field or method name or null for type
*/
String name
String descriptor
DeclarationData(int startPosition, int length, String typeName, String name, String descriptor) {
this.startPosition = startPosition
this.endPosition = startPosition + length
this.typeName = typeName
this.name = name
this.descriptor = descriptor
}
boolean isAType() { name == null }
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
boolean isAConstructor() { "<init>".equals(name) }
}
@CompileStatic
static class HyperlinkReferenceData extends HyperlinkPage.HyperlinkData {
ReferenceData reference
HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) {
super(startPosition, startPosition+length)
this.reference = reference
}
}
@CompileStatic
static class ReferenceData {
String typeName
/**
* Field or method name or null for type
*/
String name
/**
* Field or method descriptor or null for type
*/
String descriptor
/**
* Internal type name containing reference or null for "import" statement.
* Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type".
*/
String owner
/**
* "Enabled" flag for link of reference
*/
boolean enabled = false
ReferenceData(String typeName, String name, String descriptor, String owner) {
this.typeName = typeName
this.name = name
this.descriptor = descriptor
this.owner = owner
}
boolean isAType() { name == null }
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
boolean isAConstructor() { "<init>".equals(name) }
}
}

View File

@ -10,7 +10,10 @@ import org.fife.ui.rsyntaxtextarea.DocumentRange
import java.util.regex.Pattern import java.util.regex.Pattern
abstract class TypeHyperlinkPage extends HyperlinkPage { /**
* Page containing type references (Hyperlinks to pages of type)
*/
abstract class TypeReferencePage extends HyperlinkPage {
// --- UriOpenable --- // // --- UriOpenable --- //
boolean openUri(URI uri) { boolean openUri(URI uri) {

View File

@ -16,7 +16,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants
import java.awt.Point import java.awt.Point
class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener { class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
protected API api protected API api
protected Container.Entry entry protected Container.Entry entry
protected Collection<Indexes> collectionOfIndexes protected Collection<Indexes> collectionOfIndexes
@ -47,7 +47,7 @@ class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesCh
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null)) api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
// Open link // Open link
if (hyperlinkData instanceof TypeHyperlinkPage.TypeHyperlinkData) { if (hyperlinkData instanceof TypeReferencePage.TypeHyperlinkData) {
def internalTypeName = hyperlinkData.internalTypeName def internalTypeName = hyperlinkData.internalTypeName
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(internalTypeName) }.flatten().grep { it!=null } def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(internalTypeName) }.flatten().grep { it!=null }
def rootUri = entry.container.root.uri.toString() def rootUri = entry.container.root.uri.toString()
@ -163,7 +163,7 @@ class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesCh
addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim)) addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim))
} else { } else {
def internalTypeName = trim.replace('.', '/') def internalTypeName = trim.replace('.', '/')
addHyperlink(new TypeHyperlinkPage.TypeHyperlinkData(startIndex, endIndex, internalTypeName)) addHyperlink(new TypeReferencePage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
} }
} }
} }

View File

@ -5,13 +5,13 @@
package jd.gui.service.indexer; package jd.gui.service.indexer;
import jd.gui.api.model.Container;
import jd.gui.api.model.Indexes;
import jd.gui.spi.Indexer; import jd.gui.spi.Indexer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.*;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public abstract class AbstractIndexerProvider implements Indexer { public abstract class AbstractIndexerProvider implements Indexer {
@ -51,4 +51,15 @@ public abstract class AbstractIndexerProvider implements Indexer {
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]); return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
} }
public Pattern getPathPattern() { return externalPathPattern; } public Pattern getPathPattern() { return externalPathPattern; }
@SuppressWarnings("unchecked")
protected static void addToIndex(Indexes indexes, String indexName, Set<String> set, Container.Entry entry) {
if (set.size() > 0) {
Map<String, Collection> index = indexes.getIndex(indexName);
for (String key : set) {
index.get(key).add(entry);
}
}
}
} }

View File

@ -12,7 +12,6 @@ import jd.gui.api.API;
import jd.gui.api.model.Container; import jd.gui.api.model.Container;
import jd.gui.api.model.Indexes; import jd.gui.api.model.Indexes;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.*; import java.util.*;
@ -20,17 +19,17 @@ import java.util.*;
* Unsafe thread implementation of class file indexer. * Unsafe thread implementation of class file indexer.
*/ */
public class ClassFileIndexerProvider extends AbstractIndexerProvider { public class ClassFileIndexerProvider extends AbstractIndexerProvider {
protected Set<String> typeDeclarationSet = new HashSet<>(); protected HashSet<String> typeDeclarationSet = new HashSet<>();
protected Set<String> constructorDeclarationSet = new HashSet<>(); protected HashSet<String> constructorDeclarationSet = new HashSet<>();
protected Set<String> methodDeclarationSet = new HashSet<>(); protected HashSet<String> methodDeclarationSet = new HashSet<>();
protected Set<String> fieldDeclarationSet = new HashSet<>(); protected HashSet<String> fieldDeclarationSet = new HashSet<>();
protected Set<String> typeReferenceSet = new HashSet<>(); protected HashSet<String> typeReferenceSet = new HashSet<>();
protected Set<String> constructorReferenceSet = new HashSet<>(); protected HashSet<String> constructorReferenceSet = new HashSet<>();
protected Set<String> methodReferenceSet = new HashSet<>(); protected HashSet<String> methodReferenceSet = new HashSet<>();
protected Set<String> fieldReferenceSet = new HashSet<>(); protected HashSet<String> fieldReferenceSet = new HashSet<>();
protected Set<String> stringSet = new HashSet<>(); protected HashSet<String> stringSet = new HashSet<>();
protected Set<String> superTypeNameSet = new HashSet<>(); protected HashSet<String> superTypeNameSet = new HashSet<>();
protected Set<String> descriptorSet = new HashSet<>(); protected HashSet<String> descriptorSet = new HashSet<>();
protected ClassIndexer classIndexer = new ClassIndexer( protected ClassIndexer classIndexer = new ClassIndexer(
typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet, typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet,
@ -72,11 +71,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
superTypeNameSet.clear(); superTypeNameSet.clear();
descriptorSet.clear(); descriptorSet.clear();
InputStream inputStream = null; try (InputStream inputStream = entry.getInputStream()) {
try {
// Index field, method, interfaces & super type // Index field, method, interfaces & super type
ClassReader classReader = new ClassReader(inputStream = entry.getInputStream()); ClassReader classReader = new ClassReader(inputStream);
classReader.accept(classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); classReader.accept(classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
// Index descriptors // Index descriptors
@ -159,32 +156,17 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
} }
} catch (Exception ignore) { } catch (Exception ignore) {
} finally {
if (inputStream != null) {
try { inputStream.close(); } catch (IOException ignore) {}
}
}
}
@SuppressWarnings("unchecked")
protected static void addToIndex(Indexes indexes, String indexName, Set<String> set, Container.Entry entry) {
if (set.size() > 0) {
Map<String, Collection> index = indexes.getIndex(indexName);
for (String key : set) {
index.get(key).add(entry);
}
} }
} }
protected static class ClassIndexer extends ClassVisitor { protected static class ClassIndexer extends ClassVisitor {
protected Set<String> typeDeclarationSet; protected HashSet<String> typeDeclarationSet;
protected Set<String> constructorDeclarationSet; protected HashSet<String> constructorDeclarationSet;
protected Set<String> methodDeclarationSet; protected HashSet<String> methodDeclarationSet;
protected Set<String> fieldDeclarationSet; protected HashSet<String> fieldDeclarationSet;
protected Set<String> typeReferenceSet; protected HashSet<String> typeReferenceSet;
protected Set<String> superTypeNameSet; protected HashSet<String> superTypeNameSet;
protected Set<String> descriptorSet; protected HashSet<String> descriptorSet;
protected AnnotationIndexer annotationIndexer; protected AnnotationIndexer annotationIndexer;
protected FieldIndexer fieldIndexer; protected FieldIndexer fieldIndexer;
@ -193,9 +175,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
protected String name; protected String name;
public ClassIndexer( public ClassIndexer(
Set<String> typeDeclarationSet, Set<String> constructorDeclarationSet, HashSet<String> typeDeclarationSet, HashSet<String> constructorDeclarationSet,
Set<String> methodDeclarationSet, Set<String> fieldDeclarationSet, HashSet<String> methodDeclarationSet, HashSet<String> fieldDeclarationSet,
Set<String> typeReferenceSet, Set<String> superTypeNameSet, Set<String> descriptorSet) { HashSet<String> typeReferenceSet, HashSet<String> superTypeNameSet, HashSet<String> descriptorSet) {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.typeDeclarationSet = typeDeclarationSet; this.typeDeclarationSet = typeDeclarationSet;
@ -258,9 +240,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
} }
protected static class SignatureIndexer extends SignatureVisitor { protected static class SignatureIndexer extends SignatureVisitor {
protected Set<String> typeReferenceSet; protected HashSet<String> typeReferenceSet;
SignatureIndexer(Set<String> typeReferenceSet) { SignatureIndexer(HashSet<String> typeReferenceSet) {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.typeReferenceSet = typeReferenceSet; this.typeReferenceSet = typeReferenceSet;
} }
@ -271,9 +253,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
} }
protected static class AnnotationIndexer extends AnnotationVisitor { protected static class AnnotationIndexer extends AnnotationVisitor {
protected Set<String> descriptorSet; protected HashSet<String> descriptorSet;
public AnnotationIndexer(Set<String> descriptorSet) { public AnnotationIndexer(HashSet<String> descriptorSet) {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.descriptorSet = descriptorSet; this.descriptorSet = descriptorSet;
} }
@ -289,10 +271,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
} }
protected static class FieldIndexer extends FieldVisitor { protected static class FieldIndexer extends FieldVisitor {
protected Set<String> descriptorSet; protected HashSet<String> descriptorSet;
protected AnnotationIndexer annotationIndexer; protected AnnotationIndexer annotationIndexer;
public FieldIndexer(Set<String> descriptorSet, AnnotationIndexer annotationInexer) { public FieldIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationInexer) {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.descriptorSet = descriptorSet; this.descriptorSet = descriptorSet;
this.annotationIndexer = annotationInexer; this.annotationIndexer = annotationInexer;
@ -310,10 +292,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
} }
protected static class MethodIndexer extends MethodVisitor { protected static class MethodIndexer extends MethodVisitor {
protected Set<String> descriptorSet; protected HashSet<String> descriptorSet;
protected AnnotationIndexer annotationIndexer; protected AnnotationIndexer annotationIndexer;
public MethodIndexer(Set<String> descriptorSet, AnnotationIndexer annotationIndexer) { public MethodIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationIndexer) {
super(Opcodes.ASM5); super(Opcodes.ASM5);
this.descriptorSet = descriptorSet; this.descriptorSet = descriptorSet;
this.annotationIndexer = annotationIndexer; this.annotationIndexer = annotationIndexer;

View File

@ -0,0 +1,321 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.indexer;
import jd.gui.api.API;
import jd.gui.api.model.Container;
import jd.gui.api.model.Indexes;
import jd.gui.util.parser.antlr.ANTLRParser;
import jd.gui.util.parser.antlr.AbstractJavaListener;
import jd.gui.util.parser.antlr.JavaParser;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* Unsafe thread implementation of java file indexer.
*/
public class JavaFileIndexerProvider extends AbstractIndexerProvider {
static {
// Early class loading
ANTLRParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
}
/**
* @return local + optional external selectors
*/
public String[] getSelectors() {
List<String> externalSelectors = getExternalSelectors();
if (externalSelectors == null) {
return new String[] { "*:file:*.java" };
} else {
int size = externalSelectors.size();
String[] selectors = new String[size+1];
externalSelectors.toArray(selectors);
selectors[size] = "*:file:*.java";
return selectors;
}
}
/**
* Index format : @see jd.gui.spi.Indexer
*/
@SuppressWarnings("unchecked")
public void index(API api, Container.Entry entry, Indexes indexes) {
try (InputStream inputStream = entry.getInputStream()) {
Listener listener = new Listener(entry);
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
// Append sets to indexes
addToIndex(indexes, "typeDeclarations", listener.getTypeDeclarationSet(), entry);
addToIndex(indexes, "constructorDeclarations", listener.getConstructorDeclarationSet(), entry);
addToIndex(indexes, "methodDeclarations", listener.getMethodDeclarationSet(), entry);
addToIndex(indexes, "fieldDeclarations", listener.getFieldDeclarationSet(), entry);
addToIndex(indexes, "typeReferences", listener.getTypeReferenceSet(), entry);
addToIndex(indexes, "constructorReferences", listener.getConstructorReferenceSet(), entry);
addToIndex(indexes, "methodReferences", listener.getMethodReferenceSet(), entry);
addToIndex(indexes, "fieldReferences", listener.getFieldReferenceSet(), entry);
addToIndex(indexes, "strings", listener.getStringSet(), entry);
// Populate map [super type name : [sub type name]]
Map<String, Collection> index = indexes.getIndex("subTypeNames");
for (Map.Entry<String, HashSet<String>> e : listener.getSuperTypeNamesMap().entrySet()) {
String typeName = e.getKey();
for (String superTypeName : e.getValue()) {
index.get(superTypeName).add(typeName);
}
}
} catch (IOException ignore) {
}
}
protected static class Listener extends AbstractJavaListener {
protected HashSet<String> typeDeclarationSet = new HashSet<>();
protected HashSet<String> constructorDeclarationSet = new HashSet<>();
protected HashSet<String> methodDeclarationSet = new HashSet<>();
protected HashSet<String> fieldDeclarationSet = new HashSet<>();
protected HashSet<String> typeReferenceSet = new HashSet<>();
protected HashSet<String> constructorReferenceSet = new HashSet<>();
protected HashSet<String> methodReferenceSet = new HashSet<>();
protected HashSet<String> fieldReferenceSet = new HashSet<>();
protected HashSet<String> stringSet = new HashSet<>();
protected HashMap<String, HashSet<String>> superTypeNamesMap = new HashMap<>();
protected StringBuffer sbTypeDeclaration = new StringBuffer();
public Listener(Container.Entry entry) {
super(entry);
}
public HashSet<String> getTypeDeclarationSet() { return typeDeclarationSet; }
public HashSet<String> getConstructorDeclarationSet() { return constructorDeclarationSet; }
public HashSet<String> getMethodDeclarationSet() { return methodDeclarationSet; }
public HashSet<String> getFieldDeclarationSet() { return fieldDeclarationSet; }
public HashSet<String> getTypeReferenceSet() { return typeReferenceSet; }
public HashSet<String> getConstructorReferenceSet() { return constructorReferenceSet; }
public HashSet<String> getMethodReferenceSet() { return methodReferenceSet; }
public HashSet<String> getFieldReferenceSet() { return fieldReferenceSet; }
public HashSet<String> getStringSet() { return stringSet; }
public HashMap<String, HashSet<String>> getSuperTypeNamesMap() { return superTypeNamesMap; }
// --- ANTLR Listener --- //
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
super.enterPackageDeclaration(ctx);
if (! packageName.isEmpty()) {
sbTypeDeclaration.append(packageName).append('/');
}
}
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
protected void enterTypeDeclaration(ParserRuleContext ctx) {
// Add type declaration
String typeName = ctx.getToken(JavaParser.Identifier, 0).getText();
int length = sbTypeDeclaration.length();
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
sbTypeDeclaration.append(typeName);
} else {
sbTypeDeclaration.append('$').append(typeName);
}
String internalTypeName = sbTypeDeclaration.toString();
typeDeclarationSet.add(internalTypeName);
nameToInternalTypeName.put(typeName, internalTypeName);
HashSet<String> superInternalTypeNameSet = new HashSet<>();
// Add super type reference
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
if (superType != null) {
String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
if (superQualifiedTypeName.charAt(0) != '*')
superInternalTypeNameSet.add(superQualifiedTypeName);
}
// Add implementation references
JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0);
if (superInterfaces != null) {
for (JavaParser.TypeContext superInterface : superInterfaces.type()) {
String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier());
if (superQualifiedInterfaceName.charAt(0) != '*')
superInternalTypeNameSet.add(superQualifiedInterfaceName);
}
}
if (! superInternalTypeNameSet.isEmpty()) {
superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet);
}
}
protected void exitTypeDeclaration() {
int index = sbTypeDeclaration.lastIndexOf("$");
if (index == -1) {
index = sbTypeDeclaration.lastIndexOf("/") + 1;
}
if (index == -1) {
sbTypeDeclaration.setLength(0);
} else {
sbTypeDeclaration.setLength(index);
}
}
public void enterType(JavaParser.TypeContext ctx) {
// Add type reference
JavaParser.ClassOrInterfaceTypeContext classOrInterfaceType = ctx.classOrInterfaceType();
if (classOrInterfaceType != null) {
String internalTypeName = resolveInternalTypeName(classOrInterfaceType.Identifier());
if (internalTypeName.charAt(0) != '*')
typeReferenceSet.add(internalTypeName);
}
}
public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
String name = constantDeclaratorContext.Identifier().getText();
fieldDeclarationSet.add(name);
}
}
public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
String name = declaration.variableDeclaratorId().Identifier().getText();
fieldDeclarationSet.add(name);
}
}
public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
String name = ctx.Identifier().getText();
methodDeclarationSet.add(name);
}
public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
String name = ctx.Identifier().getText();
methodDeclarationSet.add(name);
}
public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
String name = ctx.Identifier().getText();
constructorDeclarationSet.add(name);
}
public void enterCreatedName(JavaParser.CreatedNameContext ctx) {
String internalTypeName = resolveInternalTypeName(ctx.Identifier());
if ((internalTypeName != null) && (internalTypeName.charAt(0) != '*'))
constructorReferenceSet.add(internalTypeName);
}
public void enterExpression(JavaParser.ExpressionContext ctx) {
switch (ctx.getChildCount()) {
case 3:
if (getToken(ctx.children, 1, JavaParser.DOT) != null) {
// Search "expression '.' Identifier" : field
TerminalNode identifier3 = getToken(ctx.children, 2, JavaParser.Identifier);
if (identifier3 != null) {
String fieldName = identifier3.getText();
fieldReferenceSet.add(fieldName);
}
} else if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
// Search "expression '(' ')'" : method
if (getToken(ctx.children, 2, JavaParser.RPAREN) != null) {
TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
if (identifier0 != null) {
String methodName = identifier0.getText();
methodReferenceSet.add(methodName);
}
}
}
break;
case 4:
if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
// Search "expression '(' expressionList ')'" : method
if (getToken(ctx.children, 3, JavaParser.RPAREN) != null) {
JavaParser.ExpressionListContext expressionListContext = ctx.expressionList();
if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
if (identifier0 != null) {
String methodName = identifier0.getText();
methodReferenceSet.add(methodName);
}
}
}
}
break;
}
}
protected TerminalNode getToken(List<ParseTree> children, int i, int type) {
ParseTree pt = children.get(i);
if (pt instanceof TerminalNode) {
if (((TerminalNode)pt).getSymbol().getType() == type) {
return (TerminalNode)pt;
}
}
return null;
}
protected TerminalNode getRightTerminalNode(ParseTree pt) {
if (pt instanceof ParserRuleContext) {
List<ParseTree> children = ((ParserRuleContext)pt).children;
int size = children.size();
if (size > 0) {
ParseTree last = children.get(size - 1);
if (last instanceof TerminalNode) {
return (TerminalNode) last;
} else {
return getRightTerminalNode(last);
}
}
}
return null;
}
public void enterLiteral(JavaParser.LiteralContext ctx) {
TerminalNode stringLiteral = ctx.StringLiteral();
if (stringLiteral != null) {
stringSet.add(stringLiteral.getSymbol().getText());
}
}
}
}

View File

@ -5,8 +5,12 @@
package jd.gui.service.type; package jd.gui.service.type;
import jd.gui.api.model.Type;
import jd.gui.spi.TypeFactory; import jd.gui.spi.TypeFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays; import java.util.Arrays;
@ -22,7 +26,7 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
/** /**
* Initialize "selectors" and "pathPattern" with optional external properties file * Initialize "selectors" and "pathPattern" with optional external properties file
*/ */
AbstractTypeFactoryProvider() { public AbstractTypeFactoryProvider() {
Properties properties = new Properties(); Properties properties = new Properties();
Class clazz = this.getClass(); Class clazz = this.getClass();
@ -51,4 +55,153 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]); return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
} }
public Pattern getPathPattern() { return externalPathPattern; } public Pattern getPathPattern() { return externalPathPattern; }
protected static ImageIcon getTypeIcon(int access) {
if ((access & Type.FLAG_ANNOTATION) != 0)
return ANNOTATION_ICON;
else if ((access & Type.FLAG_INTERFACE) != 0)
return INTERFACE_ICONS[accessToIndex(access)];
else if ((access & Type.FLAG_ENUM) != 0)
return ENUM_ICON;
else
return CLASS_ICONS[accessToIndex(access)];
}
protected static ImageIcon getFieldIcon(int access) {
return FIELD_ICONS[accessToIndex(access)];
}
protected static ImageIcon getMethodIcon(int access) {
return METHOD_ICONS[accessToIndex(access)];
}
protected static int accessToIndex(int access) {
int index = 0;
if ((access & Type.FLAG_STATIC) != 0)
index += 4;
if ((access & Type.FLAG_FINAL) != 0)
index += 8;
if ((access & Type.FLAG_ABSTRACT) != 0)
index += 16;
if ((access & Type.FLAG_PUBLIC) != 0)
return index + 1;
else if ((access & Type.FLAG_PROTECTED) != 0)
return index + 2;
else if ((access & Type.FLAG_PRIVATE) != 0)
return index + 3;
else
return index;
}
// Graphic stuff ...
protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) {
int w = background.getIconWidth();
int h = background.getIconHeight();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if (x + overlay.getIconWidth() > w)
x = w - overlay.getIconWidth();
if (y + overlay.getIconHeight() > h)
y = h - overlay.getIconHeight();
Graphics2D g2 = image.createGraphics();
g2.drawImage(background.getImage(), 0, 0, null);
g2.drawImage(overlay.getImage(), x, y, null);
g2.dispose();
return new ImageIcon(image);
}
protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) {
int length = backgrounds.length;
ImageIcon[] result = new ImageIcon[length*2];
// Copy source icons
System.arraycopy(backgrounds, 0, result, 0, length);
// Add overlays
for (int i=0; i<length; i++) {
result[length+i] = mergeIcons(backgrounds[i], overlay, x, y);
}
return result;
}
protected static final ImageIcon ABSTRACT_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/abstract_ovr.png"));
protected static final ImageIcon FINAL_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/final_ovr.png"));
protected static final ImageIcon STATIC_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/static_ovr.png"));
protected static final ImageIcon CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_default_obj.png"));
protected static final ImageIcon PUBLIC_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_obj.png"));
protected static final ImageIcon PROTECTED_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_protected_obj.png"));
protected static final ImageIcon PRIVATE_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_private_obj.png"));
protected static final ImageIcon INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_default_obj.png"));
protected static final ImageIcon PUBLIC_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_obj.png"));
protected static final ImageIcon PROTECTED_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_protected_obj.png"));
protected static final ImageIcon PRIVATE_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_private_obj.png"));
protected static final ImageIcon ANNOTATION_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/annotation_obj.png"));
protected static final ImageIcon ENUM_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/enum_obj.png"));
protected static final ImageIcon FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_default_obj.png"));
protected static final ImageIcon PUBLIC_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_public_obj.png"));
protected static final ImageIcon PROTECTED_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_protected_obj.png"));
protected static final ImageIcon PRIVATE_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_private_obj.png"));
protected static final ImageIcon METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methdef_obj.png"));
protected static final ImageIcon PUBLIC_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpub_obj.png"));
protected static final ImageIcon PROTECTED_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpro_obj.png"));
protected static final ImageIcon PRIVATE_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpri_obj.png"));
// Default icon set
protected static final ImageIcon[] DEFAULT_CLASS_ICONS = {
CLASS_ICON,
PUBLIC_CLASS_ICON,
PROTECTED_CLASS_ICON,
PRIVATE_CLASS_ICON
};
protected static final ImageIcon[] DEFAULT_INTERFACE_ICONS = {
INTERFACE_ICON,
PUBLIC_INTERFACE_ICON,
PROTECTED_INTERFACE_ICON,
PRIVATE_INTERFACE_ICON
};
protected static final ImageIcon[] DEFAULT_FIELD_ICONS = {
FIELD_ICON,
PUBLIC_FIELD_ICON,
PROTECTED_FIELD_ICON,
PRIVATE_FIELD_ICON
};
protected static final ImageIcon[] DEFAULT_METHOD_ICONS = {
METHOD_ICON,
PUBLIC_METHOD_ICON,
PROTECTED_METHOD_ICON,
PRIVATE_METHOD_ICON
};
// Add static icon set
protected static final ImageIcon[] STATIC_CLASS_ICONS = mergeIcons(DEFAULT_CLASS_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_INTERFACE_ICONS = mergeIcons(DEFAULT_INTERFACE_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_FIELD_ICONS = mergeIcons(DEFAULT_FIELD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_METHOD_ICONS = mergeIcons(DEFAULT_METHOD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
// Add final icon set
protected static final ImageIcon[] FINAL_STATIC_CLASS_ICONS = mergeIcons(STATIC_CLASS_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_INTERFACE_ICONS = mergeIcons(STATIC_INTERFACE_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_FIELD_ICONS = mergeIcons(STATIC_FIELD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_METHOD_ICONS = mergeIcons(STATIC_METHOD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
// Add abstract icon set
protected static final ImageIcon[] CLASS_ICONS = mergeIcons(FINAL_STATIC_CLASS_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] INTERFACE_ICONS = mergeIcons(FINAL_STATIC_INTERFACE_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] FIELD_ICONS = mergeIcons(FINAL_STATIC_FIELD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] METHOD_ICONS = mergeIcons(FINAL_STATIC_METHOD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
} }

View File

@ -16,11 +16,11 @@ import jd.gui.api.model.Container;
import jd.gui.api.model.Type; import jd.gui.api.model.Type;
import javax.swing.*; import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider { public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
@ -47,6 +47,10 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
} }
} }
public Collection<Type> make(API api, Container.Entry entry) {
return Collections.singletonList(make(api, entry, null));
}
public Type make(API api, Container.Entry entry, String fragment) { public Type make(API api, Container.Entry entry, String fragment) {
try (InputStream is = entry.getInputStream()) { try (InputStream is = entry.getInputStream()) {
ClassReader classReader = new ClassReader(is); ClassReader classReader = new ClassReader(is);
@ -110,24 +114,24 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
} }
static class JavaType implements Type { static class JavaType implements Type {
ClassNode classNode;
Container.Entry entry;
int access;
String name;
String shortName;
String superName;
String outerName;
String displayTypeName; protected ClassNode classNode;
String displayInnerTypeName; protected Container.Entry entry;
String displayPackageName; protected int access;
protected String name;
protected String superName;
protected String outerName;
List<Type> innerTypes; protected String displayTypeName;
List<Type.Field> fields; protected String displayInnerTypeName;
List<Type.Method> methods; protected String displayPackageName;
protected List<Type> innerTypes = null;
protected List<Type.Field> fields = null;
protected List<Type.Method> methods = null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
JavaType(Container.Entry entry, ClassReader classReader) { protected JavaType(Container.Entry entry, ClassReader classReader) {
this.classNode = new ClassNode(); this.classNode = new ClassNode();
this.entry = entry; this.entry = entry;
@ -161,27 +165,17 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
if (lastPackageSeparatorIndex == -1) { if (lastPackageSeparatorIndex == -1) {
this.displayPackageName = ""; this.displayPackageName = "";
this.shortName = this.name; this.displayTypeName = (this.outerName == null) ? this.name : null;
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
} else { } else {
this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.'); this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.');
this.shortName = this.name.substring(lastPackageSeparatorIndex+1); this.displayTypeName = (this.outerName == null) ? this.name.substring(lastPackageSeparatorIndex+1) : null;
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
} }
this.innerTypes = null;
this.fields = null;
this.methods = null;
} }
public int getFlags() { return access; } public int getFlags() { return access; }
public String getName() { return name; } public String getName() { return name; }
public String getShortName() { return shortName; }
public String getSuperName() { return superName; } public String getSuperName() { return superName; }
public String getOuterName() { return outerName; } public String getOuterName() { return outerName; }
public Container.Entry getOuterEntry() { return (outerName==null) ? null : getEntry(outerName); }
public String getDisplayPackageName() { return displayPackageName; } public String getDisplayPackageName() { return displayPackageName; }
public String getDisplayTypeName() { public String getDisplayTypeName() {
@ -219,7 +213,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
} }
public String getDisplayInnerTypeName() { return displayInnerTypeName; } public String getDisplayInnerTypeName() { return displayInnerTypeName; }
public Icon getIcon() { return getIcon(access); } public Icon getIcon() { return getTypeIcon(access); }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<Type> getInnerTypes() { public List<Type> getInnerTypes() {
@ -266,7 +260,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
public int getFlags() { return fieldNode.access; } public int getFlags() { return fieldNode.access; }
public String getName() { return fieldNode.name; } public String getName() { return fieldNode.name; }
public String getDescriptor() { return fieldNode.desc; } public String getDescriptor() { return fieldNode.desc; }
public Icon getIcon() { return FIELD_ICONS[accessToIndex(fieldNode.access)]; } public Icon getIcon() { return getFieldIcon(fieldNode.access); }
}); });
} }
} }
@ -285,153 +279,13 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
public int getFlags() { return methodNode.access; } public int getFlags() { return methodNode.access; }
public String getName() { return methodNode.name; } public String getName() { return methodNode.name; }
public String getDescriptor() { return methodNode.desc; } public String getDescriptor() { return methodNode.desc; }
public Icon getIcon() { return METHOD_ICONS[accessToIndex(methodNode.access)]; } public Icon getIcon() { return getMethodIcon(methodNode.access); }
}); });
} }
} }
} }
return methods; return methods;
} }
protected static ImageIcon getIcon(int access) {
if ((access & Opcodes.ACC_ANNOTATION) != 0)
return ANNOTATION_ICON;
else if ((access & Opcodes.ACC_INTERFACE) != 0)
return INTERFACE_ICONS[accessToIndex(access)];
else if ((access & Opcodes.ACC_ENUM) != 0)
return ENUM_ICON;
else
return CLASS_ICONS[accessToIndex(access)];
}
protected static int accessToIndex(int access) {
int index = 0;
if ((access & Opcodes.ACC_STATIC) != 0)
index += 4;
if ((access & Opcodes.ACC_FINAL) != 0)
index += 8;
if ((access & Opcodes.ACC_ABSTRACT) != 0)
index += 16;
if ((access & Opcodes.ACC_PUBLIC) != 0)
return index + 1;
else if ((access & Opcodes.ACC_PROTECTED) != 0)
return index + 2;
else if ((access & Opcodes.ACC_PRIVATE) != 0)
return index + 3;
else
return index;
}
// Graphic stuff ...
protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) {
int w = background.getIconWidth();
int h = background.getIconHeight();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if (x + overlay.getIconWidth() > w)
x = w - overlay.getIconWidth();
if (y + overlay.getIconHeight() > h)
y = h - overlay.getIconHeight();
Graphics2D g2 = image.createGraphics();
g2.drawImage(background.getImage(), 0, 0, null);
g2.drawImage(overlay.getImage(), x, y, null);
g2.dispose();
return new ImageIcon(image);
}
protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) {
int length = backgrounds.length;
ImageIcon[] result = new ImageIcon[length*2];
// Copy source icons
System.arraycopy(backgrounds, 0, result, 0, length);
// Add overlays
for (int i=0; i<length; i++) {
result[length+i] = mergeIcons(backgrounds[i], overlay, x, y);
}
return result;
}
protected static final ImageIcon ABSTRACT_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/abstract_ovr.png"));
protected static final ImageIcon FINAL_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/final_ovr.png"));
protected static final ImageIcon STATIC_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/static_ovr.png"));
protected static final ImageIcon CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_default_obj.png"));
protected static final ImageIcon PUBLIC_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_obj.png"));
protected static final ImageIcon PROTECTED_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_protected_obj.png"));
protected static final ImageIcon PRIVATE_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_private_obj.png"));
protected static final ImageIcon INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_default_obj.png"));
protected static final ImageIcon PUBLIC_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_obj.png"));
protected static final ImageIcon PROTECTED_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_protected_obj.png"));
protected static final ImageIcon PRIVATE_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_private_obj.png"));
protected static final ImageIcon ANNOTATION_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/annotation_obj.png"));
protected static final ImageIcon ENUM_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/enum_obj.png"));
protected static final ImageIcon FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_default_obj.png"));
protected static final ImageIcon PUBLIC_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_public_obj.png"));
protected static final ImageIcon PROTECTED_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_protected_obj.png"));
protected static final ImageIcon PRIVATE_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_private_obj.png"));
protected static final ImageIcon METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methdef_obj.png"));
protected static final ImageIcon PUBLIC_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpub_obj.png"));
protected static final ImageIcon PROTECTED_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpro_obj.png"));
protected static final ImageIcon PRIVATE_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpri_obj.png"));
// Default icon set
protected static final ImageIcon[] DEFAULT_CLASS_ICONS = {
CLASS_ICON,
PUBLIC_CLASS_ICON,
PROTECTED_CLASS_ICON,
PRIVATE_CLASS_ICON
};
protected static final ImageIcon[] DEFAULT_INTERFACE_ICONS = {
INTERFACE_ICON,
PUBLIC_INTERFACE_ICON,
PROTECTED_INTERFACE_ICON,
PRIVATE_INTERFACE_ICON
};
protected static final ImageIcon[] DEFAULT_FIELD_ICONS = {
FIELD_ICON,
PUBLIC_FIELD_ICON,
PROTECTED_FIELD_ICON,
PRIVATE_FIELD_ICON
};
protected static final ImageIcon[] DEFAULT_METHOD_ICONS = {
METHOD_ICON,
PUBLIC_METHOD_ICON,
PROTECTED_METHOD_ICON,
PRIVATE_METHOD_ICON
};
// Add static icon set
protected static final ImageIcon[] STATIC_CLASS_ICONS = mergeIcons(DEFAULT_CLASS_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_INTERFACE_ICONS = mergeIcons(DEFAULT_INTERFACE_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_FIELD_ICONS = mergeIcons(DEFAULT_FIELD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
protected static final ImageIcon[] STATIC_METHOD_ICONS = mergeIcons(DEFAULT_METHOD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
// Add final icon set
protected static final ImageIcon[] FINAL_STATIC_CLASS_ICONS = mergeIcons(STATIC_CLASS_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_INTERFACE_ICONS = mergeIcons(STATIC_INTERFACE_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_FIELD_ICONS = mergeIcons(STATIC_FIELD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
protected static final ImageIcon[] FINAL_STATIC_METHOD_ICONS = mergeIcons(STATIC_METHOD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
// Add abstract icon set
protected static final ImageIcon[] CLASS_ICONS = mergeIcons(FINAL_STATIC_CLASS_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] INTERFACE_ICONS = mergeIcons(FINAL_STATIC_INTERFACE_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] FIELD_ICONS = mergeIcons(FINAL_STATIC_FIELD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
protected static final ImageIcon[] METHOD_ICONS = mergeIcons(FINAL_STATIC_METHOD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
} }
} }

View File

@ -0,0 +1,387 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.service.type;
import jd.gui.api.API;
import jd.gui.api.model.Container;
import jd.gui.api.model.Type;
import jd.gui.util.parser.antlr.*;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class JavaFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
static {
// Early class loading
ANTLRParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
}
/**
* @return local + optional external selectors
*/
public String[] getSelectors() {
List<String> externalSelectors = getExternalSelectors();
if (externalSelectors == null) {
return new String[] { "*:file:*.java" };
} else {
int size = externalSelectors.size();
String[] selectors = new String[size+1];
externalSelectors.toArray(selectors);
selectors[size] = "*:file:*.java";
return selectors;
}
}
public Collection<Type> make(API api, Container.Entry entry) {
try (InputStream inputStream = entry.getInputStream()) {
Listener listener = new Listener(entry);
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
return listener.getRootTypes();
} catch (IOException ignore) {
return Collections.emptyList();
}
}
public Type make(API api, Container.Entry entry, String fragment) {
try (InputStream inputStream = entry.getInputStream()) {
Listener listener = new Listener(entry);
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
if ((fragment != null) && (fragment.length() > 0)) {
// Search type name in fragment. URI format : see jd.gui.api.feature.UriOpener
int index = fragment.indexOf('-');
if (index != -1) {
// Keep type name only
fragment = fragment.substring(0, index);
}
return listener.getType(fragment);
} else {
return listener.getMainType();
}
} catch (IOException ignore) {
return null;
}
}
protected static class JavaType implements Type {
protected int access;
protected String name;
protected String superName;
protected String outerName;
protected String displayTypeName;
protected String displayInnerTypeName;
protected String displayPackageName;
protected List<Type> innerTypes = new ArrayList<>();
protected List<Field> fields = new ArrayList<>();
protected List<Method> methods = new ArrayList<>();
protected JavaType outerType;
public JavaType(
int access, String name, String superName, String outerName,
String displayTypeName, String displayInnerTypeName, String displayPackageName,
JavaType outerType) {
this.access = access;
this.name = name;
this.superName = superName;
this.outerName = outerName;
this.displayTypeName = displayTypeName;
this.displayInnerTypeName = displayInnerTypeName;
this.displayPackageName = displayPackageName;
this.outerType = outerType;
}
public int getFlags() { return access; }
public String getName() { return name; }
public String getSuperName() { return superName; }
public String getOuterName() { return outerName; }
public String getDisplayTypeName() { return displayTypeName; }
public String getDisplayInnerTypeName() { return displayInnerTypeName; }
public String getDisplayPackageName() { return displayPackageName; }
public Icon getIcon() { return getTypeIcon(access); }
public JavaType getOuterType() { return outerType; }
public Collection<Type> getInnerTypes() { return innerTypes; }
public Collection<Field> getFields() { return fields; }
public Collection<Method> getMethods() { return methods; }
}
protected static class JavaField implements Type.Field {
protected int access;
protected String name;
protected String descriptor;
public JavaField(int access, String name, String descriptor) {
this.access = access;
this.name = name;
this.descriptor = descriptor;
}
public int getFlags() { return access; }
public String getName() { return name; }
public String getDescriptor() { return descriptor; }
public Icon getIcon() { return getFieldIcon(access); }
}
protected static class JavaMethod implements Type.Method {
protected int access;
protected String name;
protected String descriptor;
public JavaMethod(int access, String name, String descriptor) {
this.access = access;
this.name = name;
this.descriptor = descriptor;
}
public int getFlags() { return access; }
public String getName() { return name; }
public String getDescriptor() { return descriptor; }
public Icon getIcon() { return getMethodIcon(access); }
}
protected static class Listener extends AbstractJavaListener {
protected String displayPackageName = "";
protected JavaType mainType = null;
protected JavaType currentType = null;
protected ArrayList<Type> rootTypes = new ArrayList<>();
protected HashMap<String, Type> types = new HashMap<>();
public Listener(Container.Entry entry) {
super(entry);
}
public Type getMainType() {
return mainType;
}
public Type getType(String typeName) {
return types.get(typeName);
}
public ArrayList<Type> getRootTypes() {
return rootTypes;
}
// --- ANTLR Listener --- //
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
super.enterPackageDeclaration(ctx);
displayPackageName = packageName.replace('/', '.');
}
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx, 0); }
public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ENUM); }
public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_INTERFACE); }
public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ANNOTATION); }
public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
protected void enterTypeDeclaration(ParserRuleContext ctx, int access) {
String name = ctx.getToken(JavaParser.Identifier, 0).getText();
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
String superQualifiedTypeName;
if (superType == null) {
superQualifiedTypeName = ((access & JavaType.FLAG_INTERFACE) == 0) ? "java/lang/Object" : "";
} else {
superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
}
access += getTypeDeclarationContextAccessFlag(ctx.getParent());
if (currentType == null) {
String internalTypeName = packageName.isEmpty() ? name : packageName + "/" + name;
String outerName = null;
String displayTypeName = name;
String displayInnerTypeName = null;
currentType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, null);
types.put(internalTypeName, currentType);
rootTypes.add(currentType);
nameToInternalTypeName.put(name, internalTypeName);
if (mainType == null) {
mainType = currentType;
} else {
// Multi class definitions in the same file
String path = entry.getPath();
int index = path.lastIndexOf('/') + 1;
if (path.substring(index).startsWith(name + '.')) {
// Select the correct root type
mainType = currentType;
}
}
} else {
String internalTypeName = currentType.getName() + '$' + name;
String outerName = currentType.getName();
String displayTypeName = currentType.getDisplayTypeName() + '.' + name;
String displayInnerTypeName = name;
JavaType subType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, currentType);
currentType.getInnerTypes().add(subType);
currentType = subType;
types.put(internalTypeName, currentType);
nameToInternalTypeName.put(name, internalTypeName);
}
}
protected void exitTypeDeclaration() {
currentType = currentType.getOuterType();
}
public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
if (ctx.getChildCount() == 2) {
ParseTree first = ctx.getChild(0);
if (first instanceof TerminalNode) {
if (((TerminalNode)first).getSymbol().getType() == JavaParser.STATIC) {
currentType.getMethods().add(new JavaMethod(JavaType.FLAG_STATIC, "<clinit>", "()V"));
}
}
}
}
public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
JavaParser.TypeContext typeContext = ctx.type();
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
TerminalNode identifier = constantDeclaratorContext.Identifier();
String name = identifier.getText();
int dimensionOnVariable = countDimension(constantDeclaratorContext.children);
String descriptor = createDescriptor(typeContext, dimensionOnVariable);
currentType.getFields().add(new JavaField(access, name, descriptor));
}
}
public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
JavaParser.TypeContext typeContext = ctx.type();
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
JavaParser.VariableDeclaratorIdContext variableDeclaratorId = declaration.variableDeclaratorId();
TerminalNode identifier = variableDeclaratorId.Identifier();
String name = identifier.getText();
int dimensionOnVariable = countDimension(variableDeclaratorId.children);
String descriptor = createDescriptor(typeContext, dimensionOnVariable);
currentType.getFields().add(new JavaField(access, name, descriptor));
}
}
public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
}
public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
}
public void enterMethodDeclaration(
ParserRuleContext ctx, TerminalNode identifier,
JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
String name = identifier.getText();
String paramDescriptors = createParamDescriptors(formalParameters.formalParameterList());
String returnDescriptor = createDescriptor(returnType, 0);
String descriptor = paramDescriptors + returnDescriptor;
currentType.getMethods().add(new JavaMethod(access, name, descriptor));
}
public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
TerminalNode identifier = ctx.Identifier();
String name = identifier.getText();
String paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList());
String descriptor = paramDescriptors + "V";
currentType.getMethods().add(new JavaMethod(access, "<init>", descriptor));
}
protected String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
StringBuffer paramDescriptors = null;
if (formalParameterList != null) {
List<JavaParser.FormalParameterContext> formalParameters = formalParameterList.formalParameter();
paramDescriptors = new StringBuffer("(");
for (JavaParser.FormalParameterContext formalParameter : formalParameters) {
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children);
paramDescriptors.append(createDescriptor(formalParameter.type(), dimensionOnParameter));
}
}
return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
}
protected int getTypeDeclarationContextAccessFlag(ParserRuleContext ctx) {
int access = 0;
for (JavaParser.ClassOrInterfaceModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ClassOrInterfaceModifierContext.class)) {
access += getAccessFlag(modifierContext);
}
return access;
}
protected int getClassBodyDeclarationAccessFlag(ParserRuleContext ctx) {
int access = 0;
for (JavaParser.ModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ModifierContext.class)) {
JavaParser.ClassOrInterfaceModifierContext coimc = modifierContext.classOrInterfaceModifier();
if (coimc != null) {
access += getAccessFlag(coimc);
}
}
return access;
}
protected int getAccessFlag(JavaParser.ClassOrInterfaceModifierContext ctx) {
if (ctx.getChildCount() == 1) {
ParseTree first = ctx.getChild(0);
if (first instanceof TerminalNode) {
switch (((TerminalNode)first).getSymbol().getType()) {
case JavaParser.STATIC: return JavaType.FLAG_STATIC;
case JavaParser.FINAL: return JavaType.FLAG_FINAL;
case JavaParser.ABSTRACT: return JavaType.FLAG_ABSTRACT;
case JavaParser.PUBLIC: return JavaType.FLAG_PUBLIC;
case JavaParser.PROTECTED: return JavaType.FLAG_PROTECTED;
case JavaParser.PRIVATE: return JavaType.FLAG_PRIVATE;
}
}
}
return 0;
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.util.parser.antlr;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class ANTLRParser {
public static void parse(CharStream input, JavaListener listener) {
try {
JavaLexer lexer = new JavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
ParseTree tree = parser.compilationUnit();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(listener, tree);
} catch (StackOverflowError ignore) {
// Too complex source file, probably not written by a human.
// This error may happen on Java file generated by ANTLR for example.
}
}
}

View File

@ -0,0 +1,187 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.util.parser.antlr;
import jd.gui.api.model.Container;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
import java.util.HashMap;
import java.util.List;
public abstract class AbstractJavaListener extends JavaBaseListener {
protected Container.Entry entry;
protected String packageName = "";
protected HashMap<String, String> nameToInternalTypeName = new HashMap<>();
protected StringBuffer sb = new StringBuffer();
protected HashMap<String, String> typeNameCache = new HashMap<>();
public AbstractJavaListener(Container.Entry entry) {
this.entry = entry;
}
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
packageName = concatIdentifiers(ctx.qualifiedName().Identifier());
}
public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier();
int size = identifiers.size();
if (size > 1) {
nameToInternalTypeName.put(identifiers.get(size - 1).getText(), concatIdentifiers(identifiers));
}
}
protected String concatIdentifiers(List<TerminalNode> identifiers) {
switch (identifiers.size()) {
case 0:
return "";
case 1:
return identifiers.get(0).getText();
default:
sb.setLength(0);
for (TerminalNode identifier : identifiers) {
sb.append(identifier.getText()).append('/');
}
// Remove last separator
sb.setLength(sb.length() - 1);
return sb.toString();
}
}
protected String resolveInternalTypeName(List<TerminalNode> identifiers) {
switch (identifiers.size()) {
case 0:
return null;
case 1:
// Search in cache
String name = identifiers.get(0).getText();
String qualifiedName = typeNameCache.get(name);
if (qualifiedName != null) {
return qualifiedName;
}
// Search in imports
String imp = nameToInternalTypeName.get(name);
if (imp != null) {
// Import found
return imp;
}
// Search type in same package
String prefix = name + '.';
if (entry.getPath().indexOf('/') != -1) {
// Not in root package
Container.Entry parent = entry.getParent();
int packageLength = parent.getPath().length() + 1;
for (Container.Entry child : parent.getChildren()) {
if (!child.isDirectory() && child.getPath().substring(packageLength).startsWith(prefix)) {
qualifiedName = packageName + '/' + name;
typeNameCache.put(name, qualifiedName);
return qualifiedName;
}
}
}
// Search type in root package
for (Container.Entry child : entry.getContainer().getRoot().getChildren()) {
if (!child.isDirectory() && child.getPath().startsWith(prefix)) {
typeNameCache.put(name, name);
return name;
}
}
// Search type in 'java.lang'
try {
if (Class.forName("java.lang." + name) != null) {
qualifiedName = "java/lang/" + name;
typeNameCache.put(name, qualifiedName);
return qualifiedName;
}
} catch (ClassNotFoundException ignore) {
}
// Type not found
qualifiedName = "*/" + name;
typeNameCache.put(name, qualifiedName);
return qualifiedName;
default:
// Qualified type name -> Nothing to do
return concatIdentifiers(identifiers);
}
}
protected String createDescriptor(JavaParser.TypeContext typeContext, int dimension) {
if (typeContext == null) {
return "V";
} else {
dimension += countDimension(typeContext.children);
JavaParser.PrimitiveTypeContext primitive = typeContext.primitiveType();
String name;
if (primitive == null) {
JavaParser.ClassOrInterfaceTypeContext type = typeContext.classOrInterfaceType();
List<JavaParser.TypeArgumentsContext> typeArgumentsContexts = type.typeArguments();
if (typeArgumentsContexts.size() == 1) {
JavaParser.TypeArgumentsContext typeArgumentsContext = typeArgumentsContexts.get(0);
List<JavaParser.TypeArgumentContext> typeArguments = typeArgumentsContext.typeArgument();
} else if (typeArgumentsContexts.size() > 1) {
throw new RuntimeException("UNEXPECTED");
}
name = "L" + resolveInternalTypeName(type.Identifier()) + ";";
} else {
// Search primitive
switch (primitive.getText()) {
case "boolean": name = "Z"; break;
case "byte": name = "B"; break;
case "char": name = "C"; break;
case "double": name = "D"; break;
case "float": name = "F"; break;
case "int": name = "I"; break;
case "long": name = "J"; break;
case "short": name = "S"; break;
case "void": name = "V"; break;
default:
throw new RuntimeException("UNEXPECTED PRIMITIVE");
}
}
switch (dimension) {
case 0: return name;
case 1: return "[" + name;
case 2: return "[[" + name;
default: return new String(new char[dimension]).replace('\0', '[') + name;
}
}
}
protected int countDimension(List<ParseTree> children) {
int dimension = 0;
for (ParseTree child : children) {
if (child instanceof TerminalNodeImpl) {
if (((TerminalNodeImpl)child).getSymbol().getType() == JavaParser.LBRACK)
dimension++;
}
}
return dimension;
}
}

View File

@ -1,6 +1,7 @@
jd.gui.service.fileloader.ClassFileLoaderProvider jd.gui.service.fileloader.ClassFileLoaderProvider
jd.gui.service.fileloader.EarFileLoaderProvider jd.gui.service.fileloader.EarFileLoaderProvider
jd.gui.service.fileloader.JarFileLoaderProvider jd.gui.service.fileloader.JarFileLoaderProvider
jd.gui.service.fileloader.JavaFileLoaderProvider
jd.gui.service.fileloader.LogFileLoaderProvider jd.gui.service.fileloader.LogFileLoaderProvider
jd.gui.service.fileloader.WarFileLoaderProvider jd.gui.service.fileloader.WarFileLoaderProvider
jd.gui.service.fileloader.ZipFileLoaderProvider jd.gui.service.fileloader.ZipFileLoaderProvider

View File

@ -1,6 +1,7 @@
jd.gui.service.indexer.DirectoryIndexerProvider jd.gui.service.indexer.DirectoryIndexerProvider
jd.gui.service.indexer.ClassFileIndexerProvider jd.gui.service.indexer.ClassFileIndexerProvider
jd.gui.service.indexer.EjbJarXmlFileIndexerProvider jd.gui.service.indexer.EjbJarXmlFileIndexerProvider
jd.gui.service.indexer.JavaFileIndexerProvider
jd.gui.service.indexer.MetainfServiceFileIndexerProvider jd.gui.service.indexer.MetainfServiceFileIndexerProvider
jd.gui.service.indexer.TextFileIndexerProvider jd.gui.service.indexer.TextFileIndexerProvider
jd.gui.service.indexer.WebXmlFileIndexerProvider jd.gui.service.indexer.WebXmlFileIndexerProvider

View File

@ -7,7 +7,7 @@ jd.gui.service.treenode.EjbJarXmlFileTreeNodeFactoryProvider
jd.gui.service.treenode.FileTreeNodeFactoryProvider jd.gui.service.treenode.FileTreeNodeFactoryProvider
jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
jd.gui.service.treenode.JarFileTreeNodeFactoryProvider jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
#jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
jd.gui.service.treenode.JspFileTreeNodeFactoryProvider jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider

View File

@ -1 +1,2 @@
jd.gui.service.type.ClassFileTypeFactoryProvider jd.gui.service.type.ClassFileTypeFactoryProvider
jd.gui.service.type.JavaFileTypeFactoryProvider

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

View File

@ -7,9 +7,9 @@ package jd.gui.view.component
class ClassFilePageTest extends GroovyTestCase { class ClassFilePageTest extends GroovyTestCase {
HashMap<String, ClassFilePage.DeclarationData> initDeclarations() { HashMap<String, TypePage.DeclarationData> initDeclarations() {
def data = new ClassFilePage.DeclarationData(0, 1, "Test", "test", "I") def data = new TypePage.DeclarationData(0, 1, "Test", "test", "I")
HashMap<String, ClassFilePage.DeclarationData> declarations = [:] HashMap<String, TypePage.DeclarationData> declarations = [:]
// Init type declarations // Init type declarations
declarations.put("Test", data) declarations.put("Test", data)
@ -43,16 +43,16 @@ class ClassFilePageTest extends GroovyTestCase {
TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() { TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() {
def hyperlinks = new TreeMap<Integer, HyperlinkPage.HyperlinkData>() def hyperlinks = new TreeMap<Integer, HyperlinkPage.HyperlinkData>()
hyperlinks.put(0, new ClassFilePage.HyperlinkReferenceData(0, 1, new ClassFilePage.ReferenceData("java/lang/Integer", "MAX_VALUE", "I", "Test"))) hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "MAX_VALUE", "I", "Test")))
hyperlinks.put(0, new ClassFilePage.HyperlinkReferenceData(0, 1, new ClassFilePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test"))) hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test")))
return hyperlinks return hyperlinks
} }
ArrayList<ClassFilePage.StringData> initStrings() { ArrayList<TypePage.StringData> initStrings() {
def strings = new ArrayList<ClassFilePage.StringData>() def strings = new ArrayList<TypePage.StringData>()
strings.add(new ClassFilePage.StringData(0, 3, "abc", "Test")) strings.add(new TypePage.StringData(0, 3, "abc", "Test"))
return strings return strings
} }

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2008-2015 Emmanuel Dupuy
* This program is made available under the terms of the GPLv3 License.
*/
package jd.gui.view.component
class JavaFilePageTest extends GroovyTestCase {
HashMap<String, TypePage.DeclarationData> initDeclarations() {
def data = new TypePage.DeclarationData(0, 1, "Test", "test", "I")
HashMap<String, TypePage.DeclarationData> declarations = [:]
// Init type declarations
declarations.put("Test", data)
declarations.put("test/Test", data)
declarations.put("*/Test", data)
// Init field declarations
declarations.put("Test-attributeInt-I", data)
declarations.put("Test-attributeBoolean-Z", data)
declarations.put("Test-attributeArrayBoolean-[[Z", data)
declarations.put("Test-attributeString-Ljava/lang/String;", data)
declarations.put("test/Test-attributeInt-I", data)
declarations.put("test/Test-attributeBoolean-Z", data)
declarations.put("test/Test-attributeArrayBoolean-[[Z", data)
declarations.put("test/Test-attributeString-Ljava/lang/String;", data)
declarations.put("*/Test-attributeBoolean-?", data)
declarations.put("*/Test-attributeBoolean-Z", data)
declarations.put("test/Test-attributeBoolean-?", data)
// Init method declarations
declarations.put("*/Test-getInt-()I", data)
declarations.put("*/Test-getString-()Ljava/lang/String;", data)
declarations.put("*/Test-add-(JJ)J", data)
declarations.put("*/Test-createBuffer-(I)[C", data)
declarations.put("test/Test-getInt-(*)?", data)
declarations.put("test/Test-getString-(*)?", data)
declarations.put("test/Test-add-(*)?", data)
declarations.put("test/Test-createBuffer-(*)?", data)
declarations.put("*/Test-getInt-(*)?", data)
declarations.put("*/Test-getString-(*)?", data)
declarations.put("*/Test-add-(*)?", data)
declarations.put("*/Test-createBuffer-(*)?", data)
return declarations
}
void testMatchFragmentAndAddDocumentRange() {
}
void testMatchQueryAndAddDocumentRange() {
}
void testMatchScope() {
}
}

View File

@ -29,6 +29,16 @@
<key>LSIsAppleDefaultForType</key> <true/> <key>LSIsAppleDefaultForType</key> <true/>
<key>LSTypeIsPackage</key> <false/> <key>LSTypeIsPackage</key> <false/>
</dict> </dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>java</string>
</array>
<key>CFBundleTypeRole</key> <string>Viewer</string>
<key>CFBundleTypeName</key> <string>Java File</string>
<key>LSIsAppleDefaultForType</key> <false/>
<key>LSTypeIsPackage</key> <false/>
</dict>
<dict> <dict>
<key>CFBundleTypeExtensions</key> <key>CFBundleTypeExtensions</key>
<array> <array>