blob: 8207070c3925535ee396764354514f50a071faaf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.ast.decompiled;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.MixinNode;
import org.codehaus.groovy.classgen.Verifier;
import java.lang.reflect.Modifier;
import java.util.List;
/**
* A {@link ClassNode} kind representing the classes coming from *.class files decompiled using ASM.
*
* @see AsmDecompiler
*/
public class DecompiledClassNode extends ClassNode {
private final ClassStub classData;
private final AsmReferenceResolver resolver;
private boolean supersInitialized = false;
private boolean membersInitialized = false;
public DecompiledClassNode(ClassStub data, AsmReferenceResolver resolver) {
super(data.className, getFullModifiers(data), null, null, MixinNode.EMPTY_ARRAY);
classData = data;
this.resolver = resolver;
isPrimaryNode = false;
}
/**
* Handle the case of inner classes returning the correct modifiers from
* the INNERCLASS reference since the top-level modifiers for inner classes
* wont include static or private/protected.
*/
private static int getFullModifiers(ClassStub data) {
return (data.innerClassModifiers == -1)
? data.accessModifiers : data.innerClassModifiers;
}
public long getCompilationTimeStamp() {
if (classData.fields != null) {
for (FieldStub field : classData.fields) {
if (Modifier.isStatic(field.accessModifiers)) {
Long timestamp = Verifier.getTimestampFromFieldName(field.fieldName);
if (timestamp != null) {
return timestamp;
}
}
}
}
return Long.MAX_VALUE;
}
@Override
public GenericsType[] getGenericsTypes() {
lazyInitSupers();
return super.getGenericsTypes();
}
@Override
public boolean isUsingGenerics() {
lazyInitSupers();
return super.isUsingGenerics();
}
@Override
public List<FieldNode> getFields() {
lazyInitMembers();
return super.getFields();
}
@Override
public ClassNode[] getInterfaces() {
lazyInitSupers();
return super.getInterfaces();
}
@Override
public List<MethodNode> getMethods() {
lazyInitMembers();
return super.getMethods();
}
@Override
public List<ConstructorNode> getDeclaredConstructors() {
lazyInitMembers();
return super.getDeclaredConstructors();
}
@Override
public FieldNode getDeclaredField(String name) {
lazyInitMembers();
return super.getDeclaredField(name);
}
@Override
public List<MethodNode> getDeclaredMethods(String name) {
lazyInitMembers();
return super.getDeclaredMethods(name);
}
@Override
public ClassNode getUnresolvedSuperClass(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedSuperClass(useRedirect);
}
@Override
public ClassNode[] getUnresolvedInterfaces(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedInterfaces(useRedirect);
}
@Override
public List<AnnotationNode> getAnnotations() {
lazyInitSupers();
return super.getAnnotations();
}
@Override
public List<AnnotationNode> getAnnotations(ClassNode type) {
lazyInitSupers();
return super.getAnnotations(type);
}
@Override
public void setRedirect(ClassNode cn) {
throw new UnsupportedOperationException();
}
@Override
public void setGenericsPlaceHolder(boolean b) {
throw new UnsupportedOperationException();
}
@Override
public void setUsingGenerics(boolean b) {
throw new UnsupportedOperationException();
}
@Override
public String setName(String name) {
throw new UnsupportedOperationException();
}
@Override
public boolean isResolved() {
return true;
}
@Override
public Class getTypeClass() {
return resolver.resolveJvmClass(getName());
}
private void lazyInitSupers() {
synchronized (lazyInitLock) {
if (!supersInitialized) {
ClassSignatureParser.configureClass(this, this.classData, this.resolver);
addAnnotations(classData, this);
supersInitialized = true;
}
}
}
private void lazyInitMembers() {
synchronized (lazyInitLock) {
if (!membersInitialized) {
if (classData.methods != null) {
for (MethodStub method : classData.methods) {
MethodNode node = addAnnotations(method, MemberSignatureParser.createMethodNode(resolver, method));
if (node instanceof ConstructorNode) {
addConstructor((ConstructorNode) node);
} else {
addMethod(node);
}
}
}
if (classData.fields != null) {
for (FieldStub field : classData.fields) {
addField(addAnnotations(field, MemberSignatureParser.createFieldNode(field, resolver, this)));
}
}
membersInitialized = true;
}
}
}
private <T extends AnnotatedNode> T addAnnotations(MemberStub stub, T node) {
List<AnnotationStub> annotations = stub.annotations;
if (annotations != null) {
for (AnnotationStub annotation : annotations) {
AnnotationNode annotationNode = Annotations.createAnnotationNode(annotation, resolver);
if (annotationNode != null) {
node.addAnnotation(annotationNode);
}
}
}
return node;
}
}