Skip to content

Commit

Permalink
refactor: introduce ModifierTarget for better dealing with modifiers (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
SirYwell authored Oct 13, 2021
1 parent 1322bf6 commit aa26d0d
Show file tree
Hide file tree
Showing 9 changed files with 497 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ private <T, U extends CtVariable<T>> U getVariableDeclaration(
EnumSet.noneOf(ModifierKind.class),
referenceBuilder.getTypeReference(fieldBinding.type),
name);
return field.setExtendedModifiers(JDTTreeBuilderQuery.getModifiers(fieldBinding.modifiers, true, false));
return field.setExtendedModifiers(JDTTreeBuilderQuery.getModifiers(fieldBinding.modifiers, true, ModifierTarget.FIELD));
}
}
// add super class if any
Expand Down
16 changes: 8 additions & 8 deletions src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1071,10 +1071,10 @@ public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
m.setSimpleName(CharOperation.charToString(methodDeclaration.selector));

if (methodDeclaration.binding != null) {
m.setExtendedModifiers(getModifiers(methodDeclaration.binding.modifiers, true, true));
m.setExtendedModifiers(getModifiers(methodDeclaration.binding.modifiers, true, ModifierTarget.METHOD));
}

for (CtExtendedModifier extendedModifier : getModifiers(methodDeclaration.modifiers, false, true)) {
for (CtExtendedModifier extendedModifier : getModifiers(methodDeclaration.modifiers, false, ModifierTarget.METHOD)) {
m.addModifier(extendedModifier.getKind()); // avoid to keep implicit AND explicit modifier of the same kind.
}
m.setDefaultMethod(methodDeclaration.isDefaultMethod());
Expand Down Expand Up @@ -1105,11 +1105,11 @@ public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope s
c.setImplicit(scope.referenceContext.sourceStart() == constructorDeclaration.sourceStart());
}
if (constructorDeclaration.binding != null) {
c.setExtendedModifiers(getModifiers(constructorDeclaration.binding.modifiers, true, true));
c.setExtendedModifiers(getModifiers(constructorDeclaration.binding.modifiers, true, ModifierTarget.CONSTRUCTOR));
}
// avoid to add explicit modifier to implicit constructor
if (!c.isImplicit()) {
for (CtExtendedModifier extendedModifier : getModifiers(constructorDeclaration.modifiers, false, true)) {
for (CtExtendedModifier extendedModifier : getModifiers(constructorDeclaration.modifiers, false, ModifierTarget.CONSTRUCTOR)) {
c.addModifier(extendedModifier.getKind()); // avoid to keep implicit AND explicit modifier of the same kind.
}
}
Expand Down Expand Up @@ -1208,9 +1208,9 @@ public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
}
field.setSimpleName(CharOperation.charToString(fieldDeclaration.name));
if (fieldDeclaration.binding != null) {
field.setExtendedModifiers(getModifiers(fieldDeclaration.binding.modifiers, true, false));
field.setExtendedModifiers(getModifiers(fieldDeclaration.binding.modifiers, true, ModifierTarget.FIELD));
}
for (CtExtendedModifier extendedModifier : getModifiers(fieldDeclaration.modifiers, false, false)) {
for (CtExtendedModifier extendedModifier : getModifiers(fieldDeclaration.modifiers, false, ModifierTarget.FIELD)) {
field.addModifier(extendedModifier.getKind()); // avoid to keep implicit AND explicit modifier of the same kind.
}

Expand Down Expand Up @@ -1302,9 +1302,9 @@ public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
}
v.setSimpleName(CharOperation.charToString(localDeclaration.name));
if (localDeclaration.binding != null) {
v.setExtendedModifiers(getModifiers(localDeclaration.binding.modifiers, true, false));
v.setExtendedModifiers(getModifiers(localDeclaration.binding.modifiers, true, ModifierTarget.LOCAL_VARIABLE));
}
for (CtExtendedModifier extendedModifier : getModifiers(localDeclaration.modifiers, false, false)) {
for (CtExtendedModifier extendedModifier : getModifiers(localDeclaration.modifiers, false, ModifierTarget.LOCAL_VARIABLE)) {
v.addModifier(extendedModifier.getKind()); // avoid to keep implicit AND explicit modifier of the same kind.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ static String createQualifiedTypeName(char[][] typeName) {
*/
CtCatchVariable<Throwable> createCatchVariable(TypeReference typeReference, Scope scope) {
final Argument jdtCatch = (Argument) jdtTreeBuilder.getContextBuilder().stack.peekFirst().node;
final Set<CtExtendedModifier> modifiers = getModifiers(jdtCatch.modifiers, false, false);
final Set<CtExtendedModifier> modifiers = getModifiers(jdtCatch.modifiers, false, ModifierTarget.LOCAL_VARIABLE);

CtCatchVariable<Throwable> result = jdtTreeBuilder.getFactory().Core().createCatchVariable();
result.<CtCatchVariable>setSimpleName(CharOperation.charToString(jdtCatch.name)).setExtendedModifiers(modifiers);
Expand Down Expand Up @@ -688,7 +688,7 @@ <T> CtParameter<T> createParameter(Argument argument) {
CtParameter<T> p = jdtTreeBuilder.getFactory().Core().createParameter();
p.setSimpleName(CharOperation.charToString(argument.name));
p.setVarArgs(argument.isVarArgs());
p.setExtendedModifiers(getModifiers(argument.modifiers, false, false));
p.setExtendedModifiers(getModifiers(argument.modifiers, false, ModifierTarget.PARAMETER));
if (argument.binding != null && argument.binding.type != null && argument.type == null) {
p.setType(jdtTreeBuilder.getReferencesBuilder().<T>getTypeReference(argument.binding.type));
p.getType().setImplicit(argument.type == null);
Expand Down Expand Up @@ -740,13 +740,12 @@ CtType<?> createType(TypeDeclaration typeDeclaration) {

// Setting modifiers
if (typeDeclaration.binding != null) {
type.setExtendedModifiers(getModifiers(typeDeclaration.binding.modifiers, true, false));
type.setExtendedModifiers(getModifiers(typeDeclaration.binding.modifiers, true, ModifierTarget.TYPE));
}
for (CtExtendedModifier modifier : getModifiers(typeDeclaration.modifiers, false, false)) {
for (CtExtendedModifier modifier : getModifiers(typeDeclaration.modifiers, false, ModifierTarget.TYPE)) {
type.addModifier(modifier.getKind()); // avoid to keep implicit AND explicit modifier of the same kind.
}


jdtTreeBuilder.getContextBuilder().enter(type, typeDeclaration);

if (typeDeclaration.superInterfaces != null) {
Expand Down
23 changes: 18 additions & 5 deletions src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,11 @@ static BinaryOperatorKind getBinaryOperatorKind(int operator) {
* @param modifier
* Identifier of the modifier.
* @param implicit True if the modifier is not explicit in the source code (e.g. a missing 'public' in an interface)
* @return Set of enum value of {@link CtExtendedModifier}.
* @param target the target the modifiers belong to. Used to distinguish between flags used multiple times in
* different contexts.
* @return Set of {@link CtExtendedModifier}s.
*/
static Set<CtExtendedModifier> getModifiers(int modifier, boolean implicit, boolean isMethod) {
static Set<CtExtendedModifier> getModifiers(int modifier, boolean implicit, Set<ModifierTarget> target) {
Set<CtExtendedModifier> modifiers = new HashSet<>();
if ((modifier & ClassFileConstants.AccPublic) != 0) {
modifiers.add(new CtExtendedModifier(ModifierKind.PUBLIC, implicit));
Expand All @@ -349,9 +351,8 @@ static Set<CtExtendedModifier> getModifiers(int modifier, boolean implicit, bool
if ((modifier & ClassFileConstants.AccVolatile) != 0) {
modifiers.add(new CtExtendedModifier(ModifierKind.VOLATILE, implicit));
}
// a method can never be transient, but it can have the flag because of varArgs.
// source: https://stackoverflow.com/questions/16233910/can-transient-keywords-mark-a-method
if (!isMethod && (modifier & ClassFileConstants.AccTransient) != 0) {
// AccVarargs == AccTransient, so checking context is needed
if ((modifier & ClassFileConstants.AccTransient) != 0 && target.contains(ModifierTarget.FIELD)) {
modifiers.add(new CtExtendedModifier(ModifierKind.TRANSIENT, implicit));
}
if ((modifier & ClassFileConstants.AccAbstract) != 0) {
Expand All @@ -365,4 +366,16 @@ static Set<CtExtendedModifier> getModifiers(int modifier, boolean implicit, bool
}
return modifiers;
}

/**
* Shorthand method for {@link #getModifiers(int, boolean, Set)}, making the {@code target} to a set.
*
* @param modifier the modifier bits
* @param implicit whether the modifiers are implicit
* @param target the target the modifiers belong to
* @return Set of {@link CtExtendedModifier}s.
*/
static Set<CtExtendedModifier> getModifiers(int modifier, boolean implicit, ModifierTarget target) {
return getModifiers(modifier, implicit, target.asSingleton());
}
}
153 changes: 153 additions & 0 deletions src/main/java/spoon/support/compiler/jdt/ModifierTarget.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* SPDX-License-Identifier: (MIT OR CECILL-C)
*
* Copyright (C) 2006-2019 INRIA and contributors
*
* Spoon is available either under the terms of the MIT License (see LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the user are entitled to choose the terms under which to adopt Spoon.
*/
package spoon.support.compiler.jdt;

import spoon.reflect.declaration.ModifierKind;

import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

/**
* Defines the elements that can have modifiers assigned to them.
* <p>
* Each target as a set of modifiers that are allowed on it. For example,
* a local variable can only have the {@code final} modifier, while this modifier
* is not allowed on constructors.
*/
enum ModifierTarget {
/**
* JLS $ 8.3.1
*/
FIELD(
ModifierKind.PUBLIC,
ModifierKind.PROTECTED,
ModifierKind.PRIVATE,
ModifierKind.STRICTFP,
ModifierKind.FINAL,
ModifierKind.TRANSIENT,
ModifierKind.VOLATILE
),
/**
* JLS $ 8.4.1
*/
LOCAL_VARIABLE(ModifierKind.FINAL),
/**
* JLS $ 8.4.3
*/
METHOD(
ModifierKind.PUBLIC,
ModifierKind.PROTECTED,
ModifierKind.PRIVATE,
ModifierKind.ABSTRACT,
ModifierKind.STATIC,
ModifierKind.FINAL,
ModifierKind.SYNCHRONIZED,
ModifierKind.NATIVE,
ModifierKind.STRICTFP
),
/**
* JLS $ 8.8.3
*/
CONSTRUCTOR(
ModifierKind.PUBLIC,
ModifierKind.PROTECTED,
ModifierKind.PRIVATE
),
/**
* JLS $ 8.1.1
*/
CLASS(
ModifierKind.PUBLIC,
ModifierKind.PROTECTED,
ModifierKind.PRIVATE,
ModifierKind.ABSTRACT,
ModifierKind.STATIC,
ModifierKind.FINAL,
ModifierKind.STRICTFP
),

/**
* JLS $ 9.1.1
*/
INTERFACE(
ModifierKind.PUBLIC,
ModifierKind.PROTECTED,
ModifierKind.PRIVATE,
ModifierKind.ABSTRACT,
ModifierKind.STATIC,
ModifierKind.STRICTFP
),
/**
* JLS $ 8.4.1
*/
PARAMETER(ModifierKind.FINAL);

private Set<ModifierTarget> singleton;
private final Set<ModifierKind> allowedKinds;

/**
* Two parameters to make easy use of {@link EnumSet#of(Enum, Enum[])}.
*
* @param firstAllowed the first kind
* @param allowedKinds the remaining kind
*/
ModifierTarget(ModifierKind firstAllowed, ModifierKind... allowedKinds) {
this.allowedKinds = Collections.unmodifiableSet(
EnumSet.of(firstAllowed, allowedKinds)
);
}

/**
* Empty Set, used if no other target is fitting.
*/
public static final Set<ModifierTarget> NONE = Collections.emptySet();

/**
* A Set to target all kinds of variables.
*/
public static final Set<ModifierTarget> VARIABLE = Collections.unmodifiableSet(
EnumSet.of(FIELD, LOCAL_VARIABLE)
);

/**
* A set to target all kinds of executables.
*/
public static final Set<ModifierTarget> EXECUTABLE = Collections.unmodifiableSet(
EnumSet.of(METHOD, CONSTRUCTOR)
);

/**
* A set to target all kinds of types.
*/
public static final Set<ModifierTarget> TYPE = Collections.unmodifiableSet(
EnumSet.of(CLASS, INTERFACE)
);

/**
* Returns an unmodifiable set containing only this target.
*
* @return a Set containing only this target.
*/
public Set<ModifierTarget> asSingleton() {
if (singleton == null) {
singleton = Collections.singleton(this);
}
return singleton;
}


/**
* Returns a set of {@link ModifierKind}s that are allowed on this target.
*
* @return a set of allowed modifier kinds.
*/
public Set<ModifierKind> getAllowedKinds() {
return allowedKinds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ SourcePosition buildPositionCtElement(CtElement e, ASTNode node) {
}
}

if (getModifiers(methodDeclaration.modifiers, false, true).isEmpty()) {
if (getModifiers(methodDeclaration.modifiers, false, ModifierTarget.METHOD).isEmpty()) {
modifiersSourceEnd = modifiersSourceStart - 1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private boolean isTypeArgumentExplicit(TypeReference[][] typeArguments) {
* @return a type reference.
*/
<T> CtTypeReference<T> getQualifiedTypeReference(char[][] tokens, TypeBinding receiverType, ReferenceBinding enclosingType, JDTTreeBuilder.OnAccessListener listener) {
if (enclosingType != null && Collections.disjoint(PUBLIC_PROTECTED, JDTTreeBuilderQuery.getModifiers(enclosingType.modifiers, false, false))) {
if (enclosingType != null && Collections.disjoint(PUBLIC_PROTECTED, JDTTreeBuilderQuery.getModifiers(enclosingType.modifiers, false, ModifierTarget.NONE))) {
String access = "";
int i = 0;
final CompilationUnitDeclaration[] units = ((TreeBuilderCompiler) this.jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.scope.environment.typeRequestor).unitsToProcess;
Expand Down
Loading

0 comments on commit aa26d0d

Please sign in to comment.