/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * IdentifierOccurrenceCollector.java * Created: Sep 18, 2007 * By: Joseph Wong */ package org.openquark.cal.compiler; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.openquark.cal.compiler.IdentifierInfo.DataConsFieldName; import org.openquark.cal.compiler.IdentifierInfo.Local; import org.openquark.cal.compiler.IdentifierInfo.Module; import org.openquark.cal.compiler.IdentifierInfo.TopLevel; import org.openquark.cal.compiler.IdentifierOccurrence.Binding; import org.openquark.cal.compiler.IdentifierOccurrence.ForeignDescriptor; import org.openquark.cal.compiler.IdentifierOccurrence.Reference; import org.openquark.cal.compiler.IdentifierResolver.SymbolTable; import org.openquark.cal.compiler.IdentifierResolver.TypeVariableScope; import org.openquark.cal.compiler.IdentifierResolver.SymbolTable.LocalScope; import org.openquark.cal.compiler.IdentifierResolver.SymbolTable.TopLevelScope; /** * A visitor class that traverses a source model, gathers up the bindings declared * therein, visits each source element with the appropriate symbol table passed in as a * visitation argument, and gathers up the references (non-binding occurrences) as well. * The gathered occurrences are filtered based on a number of configurable criteria, and * are <i>collected in a list</i>. * <p> * This is the base class that should be extended if one wants to analyze a * source model and collect all identifier occurrences, or only some specific ones. * * @author Joseph Wong * @author James Wright */ /* * @history * * Many of this class's source model traversal functionalities have been supported by the * class SourceMetricFinder.SearchWalker, by James Wright. */ public class IdentifierOccurrenceCollector<R> extends IdentifierOccurrenceFinder<R> { /** * Whether declared bindings should be collected. */ private final boolean shouldCollectDeclaredBindings; /** * Whether external bindings (that do not appear in the source that is analyzed) should be collected. */ private final boolean shouldCollectExternalBindings; /** * Whether references in an expression context should be collected. */ private final boolean shouldCollectExpressionContextReferences; /** * Whether references not in an expression context should be collected. */ private final boolean shouldCollectNonExpressionContextReferences; /** * Whether occurrences of foreign descriptors should be collected. */ private final boolean shouldCollectForeignDescriptors; /** * The list of collected occurrences. These occurrences are *not* in source-position order. */ private final List<IdentifierOccurrence<?>> collectedOccurrences = new ArrayList<IdentifierOccurrence<?>>(); /** * Constructs an instance of this class. * @param currentModuleName the name of the module associated with the source being visited. * @param shouldCollectDeclaredBindings whether declared bindings should be collected. * @param shouldCollectExternalBindings whether external bindings should be collected. * @param shouldCollectExpressionContextReferences whether references in an expression context should be collected. * @param shouldCollectNonExpressionContextReferences whether references not in an expression context should be collected. * @param shouldCollectForeignDescriptors whether occurrences of foreign descriptors should be collected. */ public IdentifierOccurrenceCollector( final ModuleName currentModuleName, final boolean shouldCollectDeclaredBindings, final boolean shouldCollectExternalBindings, final boolean shouldCollectExpressionContextReferences, final boolean shouldCollectNonExpressionContextReferences, final boolean shouldCollectForeignDescriptors) { super(currentModuleName); this.shouldCollectDeclaredBindings = shouldCollectDeclaredBindings; this.shouldCollectExternalBindings = shouldCollectExternalBindings; this.shouldCollectExpressionContextReferences = shouldCollectExpressionContextReferences; this.shouldCollectNonExpressionContextReferences = shouldCollectNonExpressionContextReferences; this.shouldCollectForeignDescriptors = shouldCollectForeignDescriptors; } /** * @return whether any occurrences has been collected. */ public boolean hasCollectedOccurrences() { return !collectedOccurrences.isEmpty(); } /** * @return a <i>sorted</i> copy of the list of collected occurrences. */ public List<IdentifierOccurrence<?>> getCollectedOccurrences() { final List<IdentifierOccurrence<?>> copy = new ArrayList<IdentifierOccurrence<?>>(collectedOccurrences); Collections.sort(copy, IdentifierOccurrence.SOURCE_POSITION_BASED_COMPARATOR); return copy; } /** * @return whether declared bindings should be collected. */ protected boolean shouldCollectDeclaredBindings() { return shouldCollectDeclaredBindings; } /** * @return whether external bindings (that do not appear in the source that is analyzed) should be collected. */ protected boolean shouldCollectExternalBindings() { return shouldCollectExternalBindings; } /** * Checks whether a binding should be filtered out and not be collected. * @param binding the binding to be checked. * @return true if it should be kept, false if it should be filtered out. */ protected final boolean shouldCollectBinding(final Binding<?> binding) { if (binding instanceof Binding.External<?>) { return shouldCollectExternalBindings(); } else { return shouldCollectDeclaredBindings(); } } /** * @return whether references in an expression context should be collected. */ protected boolean shouldCollectExpressionContextReferences() { return shouldCollectExpressionContextReferences; } /** * @return whether references not in an expression context should be collected. */ protected boolean shouldCollectNonExpressionContextReferences() { return shouldCollectNonExpressionContextReferences; } /** * Checks whether a reference should be filtered out and not be collected. * @param reference the reference to be checked. * @return true if it should be kept, false if it should be filtered out. */ protected final boolean shouldCollectReference(final Reference<?> reference) { final boolean isExpressionContext; if (reference instanceof Reference.Qualifiable<?>) { isExpressionContext = ((Reference.Qualifiable<?>)reference).isExpressionContext(); } else if (reference instanceof Reference.Operator<?>) { isExpressionContext = ((Reference.Operator<?>)reference).isExpressionContext(); } else { isExpressionContext = false; } if (isExpressionContext) { return shouldCollectExpressionContextReferences(); } else { return shouldCollectNonExpressionContextReferences(); } } /** * Checks whether the occurrence should be filtered out because it does not match certain criteria. * The default implementation returns true (no filtering). * @param occurrence the occurrence to be checked. * @return true if it should be kept, false if it should be filtered out. */ protected boolean matchesDesiredIdentifiers(final IdentifierOccurrence<?> occurrence) { return true; } /** * Processes a binding and collects it if it satisfies all criteria. * @param binding the binding to process. */ protected void processBinding(final Binding<?> binding) { if (shouldCollectBinding(binding) && matchesDesiredIdentifiers(binding)) { collectedOccurrences.add(binding); } } /** * Processes a reference and collects it if it satisfies all criteria. * @param reference the reference to process. */ protected void processReference(final Reference<?> reference) { if (shouldCollectReference(reference) && matchesDesiredIdentifiers(reference)) { collectedOccurrences.add(reference); } } /** * Processes a foreign descriptor and collects it if it satisfies all criteria. * @param descriptorOccurrence the occurrence to process. */ protected void processForeignDescriptor(final ForeignDescriptor<?> descriptorOccurrence) { if (shouldCollectForeignDescriptors && matchesDesiredIdentifiers(descriptorOccurrence)) { collectedOccurrences.add(descriptorOccurrence); } } //// /// Overridden handler methods // /** * {@inheritDoc} */ @Override protected void handleModuleNameBinding(final Binding<Module> binding, final TopLevelScope scope) { processBinding(binding); super.handleModuleNameBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleModuleNameReference(final Reference<Module> reference, final Binding<Module> binding, final SymbolTable scope) { processReference(reference); super.handleModuleNameReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTopLevelFunctionOrClassMethodBinding(final Binding<TopLevel.FunctionOrClassMethod> binding, final TopLevelScope scope) { processBinding(binding); super.handleTopLevelFunctionOrClassMethodBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleLocalVariableBinding(final Binding<Local> binding, final LocalScope scope) { processBinding(binding); super.handleLocalVariableBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleVarNameReference(final Reference<? extends IdentifierInfo> reference, final Binding<? extends IdentifierInfo> binding, final SymbolTable scope) { processReference(reference); super.handleVarNameReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTopLevelFunctionOrClassMethodOperatorReference(final Reference.Operator<TopLevel.FunctionOrClassMethod> reference, final Binding<TopLevel.FunctionOrClassMethod> binding, final SymbolTable scope) { processReference(reference); super.handleTopLevelFunctionOrClassMethodOperatorReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleDataConsBinding(final Binding<TopLevel.DataCons> binding, final TopLevelScope scope) { processBinding(binding); super.handleDataConsBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleDataConsNameReference(final Reference<TopLevel.DataCons> reference, final Binding<TopLevel.DataCons> binding, final SymbolTable scope) { processReference(reference); super.handleDataConsNameReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleDataConsOperatorReference(final Reference.Operator<TopLevel.DataCons> reference, final Binding<TopLevel.DataCons> binding, final SymbolTable scope) { processReference(reference); super.handleDataConsOperatorReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeConsBinding(final Binding<TopLevel.TypeCons> binding, final TopLevelScope scope) { processBinding(binding); super.handleTypeConsBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeConsNameReference(final Reference<TopLevel.TypeCons> reference, final Binding<TopLevel.TypeCons> binding, final SymbolTable scope) { processReference(reference); super.handleTypeConsNameReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeConsOperatorReference(final Reference.Operator<TopLevel.TypeCons> reference, final Binding<TopLevel.TypeCons> binding, final SymbolTable scope) { processReference(reference); super.handleTypeConsOperatorReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeClassBinding(final Binding<TopLevel.TypeClass> binding, final TopLevelScope scope) { processBinding(binding); super.handleTypeClassBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeClassNameReference(final Reference<TopLevel.TypeClass> reference, final Binding<TopLevel.TypeClass> binding, final SymbolTable scope) { processReference(reference); super.handleTypeClassNameReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleDataConsFieldNameBinding(final Binding<DataConsFieldName> binding, final TopLevelScope scope) { processBinding(binding); super.handleDataConsFieldNameBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleDataConsFieldNameReference(final Reference.DataConsFieldName reference, final List<Binding<DataConsFieldName>> bindings, final SymbolTable scope) { processReference(reference); super.handleDataConsFieldNameReference(reference, bindings, scope); } /** * {@inheritDoc} */ @Override protected void handleRecordFieldNameReference(final Reference.RecordFieldName reference) { processReference(reference); super.handleRecordFieldNameReference(reference); } /** * {@inheritDoc} */ @Override protected void handleTypeVariableBinding(final Binding<IdentifierInfo.TypeVariable> binding, final TypeVariableScope scope) { processBinding(binding); super.handleTypeVariableBinding(binding, scope); } /** * {@inheritDoc} */ @Override protected void handleTypeVariableReference(final Reference<IdentifierInfo.TypeVariable> reference, final Binding<IdentifierInfo.TypeVariable> binding, final TypeVariableScope scope) { processReference(reference); super.handleTypeVariableReference(reference, binding, scope); } /** * {@inheritDoc} */ @Override protected void handleForeignFunctionDescriptor(final ForeignDescriptor<IdentifierInfo.TopLevel.FunctionOrClassMethod> descriptorOccurrence) { processForeignDescriptor(descriptorOccurrence); super.handleForeignFunctionDescriptor(descriptorOccurrence); } /** * {@inheritDoc} */ @Override protected void handleForeignTypeDescriptor(final ForeignDescriptor<IdentifierInfo.TopLevel.TypeCons> descriptorOccurrence) { processForeignDescriptor(descriptorOccurrence); super.handleForeignTypeDescriptor(descriptorOccurrence); } }