001package de.monochromata.anaphors.ast.strategy;
002
003import static java.util.Arrays.asList;
004import static java.util.Collections.emptyList;
005import static java.util.Collections.singletonList;
006
007import java.util.List;
008import java.util.Optional;
009
010import de.monochromata.anaphors.ast.ASTBasedAnaphora;
011import de.monochromata.anaphors.ast.AnaphorPart;
012import de.monochromata.anaphors.ast.DefaultAnaphorPart;
013import de.monochromata.anaphors.ast.DefaultRelatedExpressionPart;
014import de.monochromata.anaphors.ast.RelatedExpressionPart;
015import de.monochromata.anaphors.ast.reference.AbstractReferent;
016import de.monochromata.anaphors.ast.reference.Referent;
017import de.monochromata.anaphors.ast.reference.strategy.ReferentializationStrategy;
018import de.monochromata.anaphors.ast.relatedexp.RelatedExpression;
019import de.monochromata.anaphors.ast.relatedexp.strategy.ClassInstanceCreationStrategy;
020import de.monochromata.anaphors.ast.relatedexp.strategy.LocalVariableDeclarationStrategy;
021import de.monochromata.anaphors.ast.relatedexp.strategy.ParameterDeclarationStrategy;
022import de.monochromata.anaphors.ast.relatedexp.strategy.RelatedExpressionStrategy;
023import de.monochromata.anaphors.ast.spi.AnaphoraResolutionSpi;
024import de.monochromata.anaphors.ast.spi.AnaphorsSpi;
025import de.monochromata.anaphors.ast.spi.RelatedExpressionsSpi;
026import de.monochromata.anaphors.perspectivation.Perspectivation;
027
028/**
029 * A simple direct anaphora resolution strategy that is based on the various
030 * forms of recurrence that can be implemented using the available
031 * {@link ReferentializationStrategy} implementations.
032 *
033 * @param <N>  The node type in the AST
034 * @param <E>  The expression type
035 * @param <T>  The type type
036 * @param <B>  The binding type
037 * @param <VB> The variable binding type
038 * @param <FB> The field binding type
039 * @param <MB> The method binding type
040 * @param <TB> The type binding type
041 * @param <S>  The scope type (optional)
042 * @param <I>  The type used to represent identifiers
043 * @param <QI> The type used to represent qualified identifiers
044 * @param <EV> The type of the event contained in the condition that is
045 *             evaluated to check when the perspectivations shall be applied.
046 * @param <PP> The type used for positions that carry perspectivations
047 * @param <R>  The sub-type of related expression to use
048 * @param <A>  The sub-type of AST-based anaphora to use
049 */
050public class DA1ReStrategy<N, E, T, B, VB extends B, FB extends B, MB extends B, TB extends B, S, I, QI, EV, PP, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>>
051        extends AbstractAnaphorResolutionStrategy<N, E, T, B, VB, FB, MB, TB, S, I, QI, EV, PP, R, A>
052        implements StoresReferentInLocalTempVariable<N, E, T, B, TB, S, I, QI, R, A> {
053
054    public static final String DA1Re_KIND = "DA1Re";
055    public static final List<Class<? extends RelatedExpressionStrategy>> DA1Re_SUPPORTED_RELATED_EXPRESSION_STRATEGIES = asList(
056            ClassInstanceCreationStrategy.class, ParameterDeclarationStrategy.class,
057            LocalVariableDeclarationStrategy.class);
058
059    /**
060     * Used in contract testing.
061     */
062    @SuppressWarnings("unused")
063    protected DA1ReStrategy() {
064    }
065
066    public DA1ReStrategy(final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi,
067            final RelatedExpressionsSpi<N, E, T, B, MB, TB, S, I, QI, EV, PP, R> relatedExpressionsSpi,
068            final AnaphoraResolutionSpi<N, E, T, B, VB, FB, MB, TB, S, I, QI, R, A> anaphoraResolutionSpi) {
069        super(DA1Re_SUPPORTED_RELATED_EXPRESSION_STRATEGIES, anaphorsSpi, relatedExpressionsSpi, anaphoraResolutionSpi);
070    }
071
072    @Override
073    protected List<Referent<TB, S, I, QI>> createPotentialReferents(final S scope, final R potentialRelatedExpression) {
074        return singletonList(createReferent(potentialRelatedExpression));
075    }
076
077    @Override
078    public Referent<TB, S, I, QI> createReferent(final S scope, final R relatedExpression, final Object memento) {
079        return createReferent(relatedExpression);
080    }
081
082    protected Referent<TB, S, I, QI> createReferent(final R relatedExpression) {
083        return new DA1Referent<>(relatedExpression, relatedExpressionsSpi, anaphoraResolutionSpi);
084    }
085
086    @Override
087    public A createAnaphora(final S scope, final String anaphor, final E anaphorExpression,
088            final R potentialRelatedExpression, final Referent<TB, S, I, QI> potentialReferent,
089            final ReferentializationStrategy<E, TB, S, I, QI> refStrategy) {
090        final DefaultRelatedExpressionPart<N, E, T, B, VB, TB, S, I, QI, R> relatedExpressionPart = new DefaultRelatedExpressionPart<>(
091                potentialRelatedExpression);
092        final DefaultAnaphorPart<N, E, T, B, VB, TB, S, I, QI, R, A> anaphorPart = new DefaultAnaphorPart<>(anaphor,
093                anaphorExpression, potentialReferent, this, refStrategy,
094                potentialRelatedExpression.resolveNameBinding(scope));
095        return anaphoraResolutionSpi.createDirectAnaphora(relatedExpressionPart, anaphorPart, false);
096    }
097
098    @Override
099    public E realize(final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart,
100            final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final E replacee,
101            final Optional<I> guessedTempName, final Object... support) {
102        return anaphoraResolutionSpi.realizeDA1Re(relatedExpressionPart, anaphorPart, replacee, guessedTempName,
103                support);
104    }
105
106    @Override
107    public String getKind() {
108        return DA1Re_KIND;
109    }
110
111    @Override
112    public List<Perspectivation> underspecifyAnaphor(final R relatedExpression, final String anaphor,
113            final E anaphorExpression, final Referent<TB, S, I, QI> referent, final S scope) {
114        // No perspectivation necessary
115        return emptyList();
116    }
117
118    @Override
119    public String getAnaphorToBeRealized(final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart,
120            final List<AnaphorPart<N, E, T, B, TB, S, I, QI, R, A>> allAnaphorPartsRelatedToTheRelatedExpression,
121            final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final S scope) {
122        return AnaphorCreationForReferentInLocalTempVariable.getAnaphorToBeRealized(relatedExpressionPart,
123                allAnaphorPartsRelatedToTheRelatedExpression, anaphorPart, scope, relatedExpressionsSpi);
124    }
125
126    public static class DA1Referent<N, E, T, B, VB extends B, FB extends B, MB extends B, TB extends B, S, I, QI, EV, PP, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>>
127            extends AbstractReferent<N, E, T, B, VB, FB, MB, TB, S, I, QI, R, A> {
128
129        private QI name;
130        private TB typeBinding;
131
132        /**
133         * Used in contract testing.
134         */
135        @SuppressWarnings("unused")
136        protected DA1Referent() {
137        }
138
139        public DA1Referent(final R relatedExpression,
140                final RelatedExpressionsSpi<N, E, T, B, MB, TB, S, I, QI, EV, PP, R> relatedExpressionsSpi,
141                final AnaphoraResolutionSpi<N, E, T, B, VB, FB, MB, TB, S, I, QI, R, A> anaphorResolutionSpi) {
142            super(relatedExpression, relatedExpression.getDescription(), relatedExpressionsSpi, anaphorResolutionSpi);
143        }
144
145        @Override
146        public boolean canBeUsedInsteadOf(final Referent<TB, S, I, QI> other) {
147            // TODO: improve alias analysis, maybe use
148            // org.eclipse.jdt.internal.corext.refactoring.code.flow
149            return false;
150        }
151
152        @Override
153        public boolean hasName() {
154            return getRelatedExpression().hasName();
155        }
156
157        @Override
158        public QI getName() {
159            return getRelatedExpression().getName();
160        }
161
162        @Override
163        public boolean hasMethodName() {
164            return false;
165        }
166
167        @Override
168        public I getMethodName() {
169            throw new UnsupportedOperationException("DA1Referent has no method name");
170        }
171
172        @Override
173        public TB resolveType(final S scope) {
174            if (this.typeBinding == null) {
175                this.typeBinding = getRelatedExpression().resolveType(scope);
176            }
177            return this.typeBinding;
178        }
179
180        @Override
181        public Object getMemento() {
182            return "";
183        }
184
185        @Override
186        public int hashCode() {
187            final int prime = 31;
188            int result = super.hashCode();
189            result = prime * result + ((name == null) ? 0 : name.hashCode());
190            result = prime * result + ((typeBinding == null) ? 0 : typeBinding.hashCode());
191            return result;
192        }
193
194        @Override
195        public boolean equals(final Object obj) {
196            if (this == obj) {
197                return true;
198            }
199            if (!super.equals(obj)) {
200                return false;
201            }
202            if (getClass() != obj.getClass()) {
203                return false;
204            }
205            final DA1Referent other = (DA1Referent) obj;
206            if (name == null) {
207                if (other.name != null) {
208                    return false;
209                }
210            } else if (!name.equals(other.name)) {
211                return false;
212            }
213            if (typeBinding == null) {
214                if (other.typeBinding != null) {
215                    return false;
216                }
217            } else if (!typeBinding.equals(other.typeBinding)) {
218                return false;
219            }
220            return true;
221        }
222
223        @Override
224        public String toString() {
225            // The type binding is not output because it can be quite long.
226            return "DA1Referent [name=" + name + ", getDescription()=" + getDescription() + ", getFeatures()="
227                    + getFeatures() + "]";
228        }
229
230    }
231}