Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(shadow): Build shadow element from class object. #569

Merged
merged 8 commits into from
Apr 22, 2016
8 changes: 8 additions & 0 deletions doc/first_processor.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ keywords: start, begin, hello world, processor, spoon
last_updated: October 1, 2015
---

Spoon analyzes source code. However, this source code may refer to libraries (as a field, parameter, or method return type). Those library may be or not in the classpath. The boundary between source and libraries is handled by the reference mechanism.

When you're consider a reference object (say, a TypeReference), there are three cases:

- Case 1: the reference points to a code element for which the source code is present. In this case, reference.getDeclaration() returns this code element (e.g. TypeReference.getDeclaration returns the CtType representing the given java file). reference.getTypeDeclaration() is identical to reference.getDeclaration().
- Case 2: the reference points to a code element for which the source code is NOT present, but for which the binary class is in the classpath (either the JVM classpath or the --source-classpath argument). In this case, reference.getDeclaration() returns null and reference.getTypeDeclaration returns a partial CtType built using runtime reflection. Those objects built using runtime reflection are called shadow objects; and you can identify them with method isShadow. (This also holds for getFieldDeclaration and getExecutableDeclaration)
- Case 3: : the reference points to a code element for which the source code is NOT present, but for which the binary class is NOT in the classpath. This is called in Spoon the noclasspath mode. In this case, both reference.getDeclaration() and reference.getTypeDeclaration() return null. (This also holds for getFieldDeclaration and getExecutableDeclaration)

## Creation of the processor

In Spoon, a processor is a combination of query and analysis code.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtAnnotation.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* @param <A>
* type of represented annotation
*/
public interface CtAnnotation<A extends Annotation> extends CtExpression<A> {
public interface CtAnnotation<A extends Annotation> extends CtExpression<A>, CtShadowable {

/**
* Returns the actual annotation (a dynamic proxy for this element).
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtConstructor.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/**
* This element defines a constructor declaration.
*/
public interface CtConstructor<T> extends CtExecutable<T>, CtTypeMember, CtGenericElement {
public interface CtConstructor<T> extends CtExecutable<T>, CtTypeMember, CtGenericElement, CtShadowable {

/**
* Always returns "&lt;init&gt;".
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtField.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/**
* This element defines a field declaration.
*/
public interface CtField<T> extends CtVariable<T>, CtTypeMember, CtRHSReceiver<T> {
public interface CtField<T> extends CtVariable<T>, CtTypeMember, CtRHSReceiver<T>, CtShadowable {

/**
* The separator for a string representation of a field.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/**
* This element defines a method declaration.
*/
public interface CtMethod<T> extends CtExecutable<T>, CtTypeMember, CtGenericElement {
public interface CtMethod<T> extends CtExecutable<T>, CtTypeMember, CtGenericElement, CtShadowable {
/**
* Checks if the method is a default method. Default method can be in interfaces from
* Java 8: http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html.
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/spoon/reflect/declaration/CtPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
*/
package spoon.reflect.declaration;

import java.util.Set;

import spoon.reflect.reference.CtPackageReference;

import java.util.Set;

/**
* This element defines a package declaration. The packages are represented by a
* tree.
*/
public interface CtPackage extends CtNamedElement {
public interface CtPackage extends CtNamedElement, CtShadowable {

/**
* The separator for a string representation of a package.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtParameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* @see CtExecutable
*/
public interface CtParameter<T> extends CtVariable<T> {
public interface CtParameter<T> extends CtVariable<T>, CtShadowable {

/**
* Gets the executable that is the parent declaration of this parameter
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/spoon/reflect/declaration/CtShadowable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.declaration;

import spoon.reflect.reference.CtTypeReference;

public interface CtShadowable {
/**
* When an element isn't present in the factory (created in another factory),
* this element is considered as "shadow". e.g., a shadow element can be a
* CtType of java.lang.Class built when we call {@link CtTypeReference#getTypeDeclaration()}
* on a reference of java.lang.Class.
*
* @return true if the element is a shadow element, otherwise false.
*/
boolean isShadow();

/**
* Marks an element as shadow. To know what is a shadow element, see the javadoc of
* {@link #isShadow()}.
*/
<E extends CtShadowable> E setShadow(boolean isShadow);
}
2 changes: 1 addition & 1 deletion src/main/java/spoon/reflect/declaration/CtType.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
*
* The type parameter T refers to the actual class that this type represents.
*/
public interface CtType<T> extends CtNamedElement, CtTypeInformation, CtTypeMember, CtGenericElement {
public interface CtType<T> extends CtNamedElement, CtTypeInformation, CtTypeMember, CtGenericElement, CtShadowable {
/**
* The string separator in a Java innertype qualified name.
*/
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/spoon/reflect/factory/TypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
import spoon.reflect.reference.CtTypeParameterReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.visitor.java.JavaReflectionTreeBuilder;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static spoon.testing.utils.ModelUtils.createFactory;

/**
* The {@link CtType} sub-factory.
*/
Expand Down Expand Up @@ -260,7 +263,9 @@ private void addNestedType(List<CtType<?>> list, CtType<?> t) {
}

/**
* Gets a type from its runtime Java class.
* Gets a type from its runtime Java class. If the class isn't in the spoon path,
* the class will be build from the Java reflection and will be marked as
* shadow (see {@link spoon.reflect.declaration.CtShadowable}).
*
* @param <T>
* actual type of the class
Expand All @@ -270,7 +275,11 @@ private void addNestedType(List<CtType<?>> list, CtType<?> t) {
*/
Copy link
Collaborator

@monperrus monperrus Apr 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add new behavior in javadoc, and also get(String )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@SuppressWarnings("unchecked")
public <T> CtType<T> get(Class<?> cl) {
return (CtType<T>) get(cl.getName());
final CtType<T> aType = get(cl.getName());
if (aType == null) {
return new JavaReflectionTreeBuilder(createFactory()).scan((Class<T>) cl);
}
return aType;
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/spoon/reflect/reference/CtExecutableReference.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,18 @@ public interface CtExecutableReference<T> extends CtReference, CtGenericElementR
*/
Constructor<?> getActualConstructor();

@Override
CtExecutable<T> getDeclaration();

/**
* Returns a subtype {@link CtExecutable} that corresponds to the reference
* even if its declaring type isn't in the Spoon source path (in this case,
* the Spoon elements are built with runtime reflection).
*
* @return the executable declaration that corresponds to the reference.
*/
CtExecutable<T> getExecutableDeclaration();

/**
* Gets the reference to the type that declares this executable.
*/
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/spoon/reflect/reference/CtFieldReference.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
*/
package spoon.reflect.reference;

import java.lang.reflect.Member;

import spoon.reflect.declaration.CtField;

import java.lang.reflect.Member;

/**
* This interface defines a reference to a
* {@link spoon.reflect.declaration.CtField}.
Expand All @@ -32,8 +32,18 @@ public interface CtFieldReference<T> extends CtVariableReference<T> {
*/
Member getActualField();

@Override
CtField<T> getDeclaration();

/**
* Returns the {@link CtField} that corresponds to the reference
* even if its declaring type isn't in the Spoon source path (in this case,
* the Spoon elements are built with runtime reflection)
*
* @return the field declaration that corresponds to the reference.
*/
CtField<T> getFieldDeclaration();

/**
* Gets the type in which the field is declared.
*/
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/spoon/reflect/reference/CtTypeReference.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
package spoon.reflect.reference;

import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypeInformation;

/**
* This interface defines a reference to a
* {@link spoon.reflect.declaration.CtType} or sub-type.
*/
public interface CtTypeReference<T> extends CtReference, CtGenericElementReference, CtTypeInformation {
public interface CtTypeReference<T> extends CtReference, CtGenericElementReference, CtTypeInformation, CtShadowable {

/**
* The name of the null type ("&lt;nulltype&gt;").
Expand Down Expand Up @@ -59,6 +60,15 @@ public interface CtTypeReference<T> extends CtReference, CtGenericElementReferen
*/
CtType<T> getDeclaration();

/**
* Returns the {@link CtType} that corresponds to the reference even if the
* type isn't in the Spoon source path (in this case, the Spoon elements are
* built with runtime reflection)
*
* @return the type declaration that corresponds to the reference.
*/
CtType<T> getTypeDeclaration();

/**
* Gets the type that declares the referenced type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3410,7 +3410,7 @@ public boolean visit(SingleNameReference singleNameReference, BlockScope scope)
} else {
va = factory.Core().createFieldRead();
}
va.setVariable(references.getVariableReference(singleNameReference.fieldBinding()));
va.setVariable(references.getVariableReference(singleNameReference.fieldBinding().original()));
if (va.getVariable() instanceof CtFieldReference) {
final CtFieldReference<Object> ref = (CtFieldReference<Object>) va.getVariable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.eval.PartialEvaluator;
import spoon.reflect.reference.CtFieldReference;
Expand Down Expand Up @@ -439,4 +440,17 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
}
return (A) Proxy.newProxyInstance(annotationType.getActualClass().getClassLoader(), new Class[] { annotationType.getActualClass() }, new AnnotationInvocationHandler(this));
}

boolean isShadow;

@Override
public boolean isShadow() {
return isShadow;
}

@Override
public <E extends CtShadowable> E setShadow(boolean isShadow) {
this.isShadow = isShadow;
return (E) this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import spoon.reflect.declaration.CtGenericElement;
import spoon.reflect.declaration.CtModifiable;
import spoon.reflect.declaration.CtNamedElement;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypedElement;
import spoon.reflect.declaration.ModifierKind;
Expand Down Expand Up @@ -169,4 +170,17 @@ public ModifierKind getVisibility() {
}
return null;
}

boolean isShadow;

@Override
public boolean isShadow() {
return isShadow;
}

@Override
public <E extends CtShadowable> E setShadow(boolean isShadow) {
this.isShadow = isShadow;
return (E) this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,6 @@ public Set<String> getMetadataKeys() {
return metadata.keySet();
}


@Override
public List<CtComment> getComments() {
return Collections.unmodifiableList(comments);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,13 @@ public List<CtField<?>> getFields() {
result.addAll(super.getFields());
return result;
}

@Override
public CtField<?> getField(String name) {
final CtField<?> field = super.getField(name);
if (field == null) {
return getEnumValue(name);
}
return field;
}
}
14 changes: 14 additions & 0 deletions src/main/java/spoon/support/reflect/declaration/CtFieldImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtModifiable;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypedElement;
import spoon.reflect.declaration.CtVariable;
Expand Down Expand Up @@ -164,4 +165,17 @@ public <C extends CtRHSReceiver<T>> C setAssignment(CtExpression<T> assignment)
setDefaultExpression(assignment);
return (C) this;
}

boolean isShadow;

@Override
public boolean isShadow() {
return isShadow;
}

@Override
public <E extends CtShadowable> E setShadow(boolean isShadow) {
this.isShadow = isShadow;
return (E) this;
}
}
14 changes: 14 additions & 0 deletions src/main/java/spoon/support/reflect/declaration/CtMethodImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import spoon.reflect.declaration.CtGenericElement;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtModifiable;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypedElement;
import spoon.reflect.declaration.ModifierKind;
Expand Down Expand Up @@ -187,4 +188,17 @@ public ModifierKind getVisibility() {
public <R extends T> void replace(CtMethod<T> element) {
replace((CtElement) element);
}

boolean isShadow;

@Override
public boolean isShadow() {
return isShadow;
}

@Override
public <E extends CtShadowable> E setShadow(boolean isShadow) {
this.isShadow = isShadow;
return (E) this;
}
}
Loading