Package org.openquark.cal.compiler

Source Code of org.openquark.cal.compiler.LocalNameRenamer$SecondPass

/*
* 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.
*/

/*
* LocalNameRenamer.java
* Created: Sep 24, 2007
* By: Joseph Wong
*/

package org.openquark.cal.compiler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.openquark.cal.compiler.IdentifierOccurrence.Binding;
import org.openquark.cal.compiler.IdentifierOccurrence.Reference;
import org.openquark.cal.compiler.IdentifierOccurrenceFinder.FinderState;
import org.openquark.cal.compiler.IdentifierResolver.SymbolTable;
import org.openquark.cal.compiler.IdentifierResolver.VisitorArgument;
import org.openquark.cal.compiler.IdentifierResolver.SymbolTable.LocalScope;
import org.openquark.cal.compiler.SourceModel.FunctionDefn;

/**
* This class encapsulates the renaming logic for handling locally-bound names
* (let-bound functions and local pattern match variables, case-bound patterns, lambda-bound parameters,
* and parameters of top-level and local functions).
* <p>
* The renaming logic works in two passes:
* <ol>
* <li>
*  The first pass gathers the following information:
<ul>
<li>which algebraic function contains the local variable
<li>what are the other names defined locally within that algebraic function
<li>among the local definitions that are <i>shadowed</i> by the renamed definition, which ones
*      must be renamed in order to avoid a change in semantics.
*      <p>
*      For example:
*      <pre>
*      let
*          foo = 3.0;
*      in
*          let
*              bar = 4.0;
*          in
*              foo + bar;
*      </pre>
*      In the above, if bar is renamed to foo, the existing foo reference must be renamed, because
*      the reference to foo in 'foo + bar' is in the scope of the bar definition to be renamed.
*      On the other hand, given:
*      <pre>
*      let
*          foo = 3.0;
*          baz =
*              let
*                  bar = 4.0;
*              in
*                  bar;
*      in
*          foo + baz;
*      </pre>
*      If bar is renamed to foo here, the original foo does not need to be renamed, because there
*      are no references to it within the scope defining bar.
</ul>
* <li>
*  The second pass takes the information from the first pass, and calculates:
<ul>
<li>which local definitions <i>shadow</i> the renamed definition. These are to be renamed so as to
*      not conflict with the renamed definition.
*      <p>
*      For example:
*      <pre>
*      let
*          foo = 3.0;
*      in
*          let
*              bar = 4.0;
*          in
*              foo + bar;
*      </pre>
*      If foo is renamed to bar in the above, then bar needs to be renamed so as to preserve semantics.
<li>where are all the occurrences of the variable to be renamed
<li>which unqualified names refer to top-level functions or class methods and would be shadowed
*      by the renamed definition - these will be qualified to avoid conflicts
<li>which occurrences correspond to the affected shadowed definitions and the shadowing definitions
*      - these will need to be renamed to something else to avoid conflicts (these are termed "collateral damage")
</ul>
* </ol>
* The renaming algorithm takes the information gathered by the two passes to produce a set of
* required source modifications.
*
* @author Joseph Wong
*/
/*
* @history
*
* The local name renaming logic is based on the work in CALSourceGenerator.ParameterRenamer,
* which handles the renaming of lambda parameters.
*/
final class LocalNameRenamer {
   
    /**
     * The first pass gathers the following information:
     * <ul>
     * <li>which algebraic function contains the local variable
     * <li>what are the other names defined locally within that algebraic function
     * <li>among the local definitions that are <i>shadowed</i> by the renamed definition, which
     * ones must be renamed in order to avoid a change in semantics.
     * </ul>
     *
     * @author Joseph Wong
     */
    private static final class FirstPass extends IdentifierOccurrenceFinder<Void> {
       
        /**
         * The target to be renamed.
         */
        private final IdentifierInfo.Local target;
       
        /**
         * The new name for the target.
         */
        private final String newName;
       
        /**
         * The current algebraic function - it is non-null only if an algebraic function is being visited.
         */
        private FunctionDefn.Algebraic currentAlgebraicFunction;
       
        /**
         * The set of local names defined in the current algebraic function.
         */
        private final Set<String> localNamesInCurrentAlgebraicFunction = new HashSet<String>();
       
        /**
         * The algebraic function containing the target - this is null until the target is found.
         */
        private FunctionDefn.Algebraic algebraicFunctionContainingTarget;
       
        /**
         * The set of local names defined in the algebraic function containing the target - this is empty until
         * the target is found.
         */
        private final Set<String> localNamesInAlgebraicFunctionContainingTarget = new HashSet<String>();
       
        /**
         * A map of all local definitions that are shadowed by the new name for the target.
         */
        private final Map<IdentifierInfo.Local, Binding<IdentifierInfo.Local>> shadowedLocalDefinitions =
            new HashMap<IdentifierInfo.Local, Binding<IdentifierInfo.Local>>();
       
        /**
         * A submap of {@link #shadowedLocalDefinitions} containing only those shadowed local definitions
         * that <i>must</i> be renamed to avoid conflicts.
         */
        private final Map<IdentifierInfo.Local, Binding<IdentifierInfo.Local>> affectedShadowedLocalDefinitions =
            new HashMap<IdentifierInfo.Local, Binding<IdentifierInfo.Local>>();
       
        /**
         * The scope that defines the target - this is null until the target is found.
         */
        private LocalScope definingScopeOfTarget;

        /**
         * Construct an instance of this class.
         * @param currentModuleName the name of the module associated with the source being visited.
         * @param target the target to be renamed.
         * @param newName the new name for the target.
         */
        FirstPass(final ModuleName currentModuleName, final IdentifierInfo.Local target, final String newName) {
            super(currentModuleName);
            if (target == null || newName == null) {
                throw new NullPointerException();
            }
            this.target = target;
            this.newName = newName;
        }

        /**
         * @return the algebraic function containing the target - this is null until the target is found.
         */
        FunctionDefn.Algebraic getAlgebraicFunctionContainingTarget() {
            return algebraicFunctionContainingTarget;
        }

        /**
         * @return the set of local names defined in the algebraic function containing the target - this is null until the target is found.
         */
        Set<String> getLocalNamesInAlgebraicFunctionContainingTarget() {
            return localNamesInAlgebraicFunctionContainingTarget;
        }

        /**
         * @return a map containing only those shadowed local definitions that must be renamed to avoid conflicts.
         */
        Map<IdentifierInfo.Local, Binding<IdentifierInfo.Local>> getAffectedShadowedLocalDefinitions() {
            return affectedShadowedLocalDefinitions;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Void visit_FunctionDefn_Algebraic(final FunctionDefn.Algebraic algebraic, final VisitorArgument<FinderState> arg) {
            // optimization: if already found the function containing the target, just return
            if (algebraicFunctionContainingTarget != null) {
                return null;
            }
           
            currentAlgebraicFunction = algebraic;
            localNamesInCurrentAlgebraicFunction.clear();
           
            super.visit_FunctionDefn_Algebraic(algebraic, arg);
           
            if (algebraicFunctionContainingTarget == algebraic) {
                // we have found the right function, so copy so the local names
                localNamesInAlgebraicFunctionContainingTarget.addAll(localNamesInCurrentAlgebraicFunction);
            }
           
            // reset the state
            currentAlgebraicFunction = null;
            localNamesInCurrentAlgebraicFunction.clear();
           
            return null;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleNewLocalScope(final LocalScope scope) {
           
            // first loop: set the definingScopeOfTarget if the target is indeed defined in this scope
            for (final Binding<IdentifierInfo.Local> binding : scope.getBindings()) {
                if (target.equals(binding.getIdentifierInfo())) {
                    algebraicFunctionContainingTarget = currentAlgebraicFunction;
                    definingScopeOfTarget = scope;
                }
            }
           
            // second loop - done by superclass implementation:
            super.handleNewLocalScope(scope);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleLocalVariableBinding(final Binding<IdentifierInfo.Local> binding, final LocalScope scope) {

            if (target.equals(binding.getIdentifierInfo())) {
                // find all the local definitions that are shadowed
                SymbolTable scopeToCheck = scope;
                while (scopeToCheck instanceof LocalScope) {
                    final LocalScope localAncestorScope = (LocalScope)scopeToCheck;
                    for (final Binding<IdentifierInfo.Local> bindingInAncestor : localAncestorScope.getBindings()) {
                        if (newName.equals(bindingInAncestor.getIdentifierInfo().getVarName())) {
                            shadowedLocalDefinitions.put(bindingInAncestor.getIdentifierInfo(), bindingInAncestor);
                        }
                    }
                   
                    if (scopeToCheck instanceof LocalScope) {
                        scopeToCheck = ((LocalScope)scopeToCheck).getParent();
                    } else {
                        break;
                    }
                }
            }
           
            localNamesInCurrentAlgebraicFunction.add(binding.getIdentifierInfo().getVarName());
           
            super.handleLocalVariableBinding(binding, scope);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleVarNameReference(final Reference<? extends IdentifierInfo> reference, final Binding<? extends IdentifierInfo> binding, final SymbolTable scope) {

            if (scope instanceof LocalScope) {
                if (isSameOrDescendantScope((LocalScope)scope, definingScopeOfTarget)) {
                    if (binding.getIdentifierInfo() instanceof IdentifierInfo.Local) {
                        // If the reference appears in the scope of the target, and the definition is shadowed,
                        // then the definition is affected.
                       
                        final Binding<IdentifierInfo.Local> shadowedLocalDefinition = shadowedLocalDefinitions.get(binding.getIdentifierInfo());
                        if (shadowedLocalDefinition != null) {
                            affectedShadowedLocalDefinitions.put(shadowedLocalDefinition.getIdentifierInfo(), shadowedLocalDefinition);
                        }
                    }
                }
            }
           
            super.handleVarNameReference(reference, binding, scope);
        }
    }
   
    /**
     * The second pass takes the information from the first pass, and calculates:
     * <ul>
     * <li>which local definitions <i>shadows</i> the renamed definition. These are to be renamed
     * so as to not conflict with the renamed definition.
     * <li>where are all the occurrences of the variable to be renamed
     * <li>which unqualified names refer to top-level functions or class methods and would be
     * shadowed by the renamed definition - these will be qualified to avoid conflicts
     * <li>which occurrences correspond to the affected shadowed definitions and the shadowing
     * definitions - these will need to be renamed to something else to avoid conflicts (these are
     * termed "collateral damage")
     * </ul>
     *
     * @author Joseph Wong
     */
    private static final class SecondPass extends IdentifierOccurrenceFinder<Void> {
       
        /**
         * The target to be renamed.
         */
        private final IdentifierInfo.Local target;
       
        /**
         * The new name for the target.
         */
        private final String newName;
       
        /**
         * A map containing only those shadowed local definitions that <i>must</i> be renamed to avoid conflicts.
         * Can *not* be null.
         */
        private final Map<IdentifierInfo.Local, Binding<IdentifierInfo.Local>> affectedShadowedLocalDefinitions;
       
        /**
         * The scope that defines the target. Can *not* be null.
         */
        private LocalScope definingScopeOfTarget;
       
        /**
         * A set for collecting the local definitions that would shadow the renamed target.
         */
        private final Set<IdentifierInfo.Local> shadowingLocalDefinitions = new HashSet<IdentifierInfo.Local>();

        /**
         * The algebraic function containing the target. Can *not* be null.
         */
        private final FunctionDefn.Algebraic algebraicFunctionContainingTarget;
       
        /**
         * A list of the occurrences of the target to be renamed.
         */
        private final List<IdentifierOccurrence<?>> occurrencesToRename = new ArrayList<IdentifierOccurrence<?>>();
       
        /**
         * A list of the unqualified name occurrences referring to top-level functions or class
         * methods that would be shadowed by the renamed target.
         */
        private final List<Reference.Qualifiable<?>> occurrencesToQualify = new ArrayList<Reference.Qualifiable<?>>();
       
        /**
         * A list of the occurrences corresponding to the affected shadowed definitions and the
         * shadowing definitions - these will need to be renamed to something else to avoid
         * conflicts (these are termed "collateral damage").
         */
        private final List<IdentifierOccurrence<?>> collaterallyDamagedLocalNameOccurrences = new ArrayList<IdentifierOccurrence<?>>();

        /**
         * Constructs an instance of this class.
         * @param currentModuleName the name of the module associated with the source being visited.
         * @param target the target to be renamed.
         * @param newName the new name for the target.
         * @param algebraicFunctionContainingTarget the algebraic function containing the target. Can *not* be null.
         * @param affectedShadowedLocalDefinitions a map containing only those shadowed local definitions that must be renamed to avoid conflicts. Can *not* be null.
         */
        SecondPass(final ModuleName currentModuleName, final IdentifierInfo.Local target, final String newName, final FunctionDefn.Algebraic algebraicFunctionContainingTarget, final Map<IdentifierInfo.Local, Binding<IdentifierInfo.Local>> affectedShadowedLocalDefinitions) {
            super(currentModuleName);
            if (target == null || newName == null || algebraicFunctionContainingTarget == null || affectedShadowedLocalDefinitions == null) {
                throw new NullPointerException();
            }
            this.target = target;
            this.newName = newName;
            this.algebraicFunctionContainingTarget = algebraicFunctionContainingTarget;
            this.affectedShadowedLocalDefinitions = affectedShadowedLocalDefinitions;
        }
       
        /**
         * @return a list of the occurrences of the target to be renamed.
         */
        List<IdentifierOccurrence<?>> getOccurrencesToRename() {
            return occurrencesToRename;
        }

        /**
         * @return a list of the unqualified name occurrences referring to top-level functions or
         *         class methods that would be shadowed by the renamed target.
         */
        List<Reference.Qualifiable<?>> getOccurrencesToQualify() {
            return occurrencesToQualify;
        }

        /**
         * @return a list of the occurrences corresponding to the affected shadowed definitions and
         *         the shadowing definitions - these will need to be renamed to something else to
         *         avoid conflicts (these are termed "collateral damage").
         */
        List<IdentifierOccurrence<?>> getCollaterallyDamagedLocalNameOccurrences() {
            return collaterallyDamagedLocalNameOccurrences;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Void visit_FunctionDefn_Algebraic(final FunctionDefn.Algebraic algebraic, final VisitorArgument<FinderState> arg) {
            // optimization: skip everything except the function containing the target
            if (algebraic != algebraicFunctionContainingTarget) {
                return null;
            }
            return super.visit_FunctionDefn_Algebraic(algebraic, arg);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleNewLocalScope(final LocalScope scope) {
           
            // first loop: set the definingScopeOfTarget if the target is indeed defined in this scope
            for (final Binding<IdentifierInfo.Local> binding : scope.getBindings()) {
                if (target.equals(binding.getIdentifierInfo())) {
                    definingScopeOfTarget = scope;
                }
            }

            // second loop - done by superclass implementation:
            // determining if the binding corresponds to the one needing to be renamed
            // or to one of the "collaterally damaged" names that need to be renamed to something else
            super.handleNewLocalScope(scope);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleLocalVariableBinding(final Binding<IdentifierInfo.Local> binding, final LocalScope scope) {
            if (target.equals(binding.getIdentifierInfo())) {
                occurrencesToRename.add(binding);

            } else if (affectedShadowedLocalDefinitions.containsKey(binding.getIdentifierInfo())) {
                collaterallyDamagedLocalNameOccurrences.add(binding);
               
            } else if (isSameOrDescendantScope(scope, definingScopeOfTarget) && newName.equals(binding.getIdentifierInfo().getVarName())) {
                // check to see if this definition shadows the target
                shadowingLocalDefinitions.add(binding.getIdentifierInfo());
                collaterallyDamagedLocalNameOccurrences.add(binding);
            }
           
            super.handleLocalVariableBinding(binding, scope);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void handleVarNameReference(final Reference<? extends IdentifierInfo> reference, final Binding<? extends IdentifierInfo> binding, final SymbolTable scope) {

            if (target.equals(reference.getIdentifierInfo())) {
                occurrencesToRename.add(reference);
               
            } else if (shadowingLocalDefinitions.contains(reference.getIdentifierInfo())) {
                collaterallyDamagedLocalNameOccurrences.add(reference);
               
            } else if (affectedShadowedLocalDefinitions.containsKey(reference.getIdentifierInfo())) {
                collaterallyDamagedLocalNameOccurrences.add(reference);
               
            } else if (reference instanceof Reference.Qualifiable<?>) {
                final Reference.Qualifiable<?> qualifiableReference = (Reference.Qualifiable<?>)reference;
                if (qualifiableReference.getModuleNameOccurrence() == null) {
                    if (newName.equals(qualifiableReference.getIdentifierInfo().getResolvedName().getUnqualifiedName())) {
                        // unqualified occurrence to a top-level entity with the same name as the new name, so need
                        // to qualify it
                        occurrencesToQualify.add(qualifiableReference);
                    }
                }
            }
           
            super.handleVarNameReference(reference, binding, scope);
        }
    }

    /** Private constructor. */
    private LocalNameRenamer() {}
   
    /**
     * Helper method for determining whether a scope is the same, or is a descendant of, another scope.
     * @param potentialDescendantScope the potential descendant scope.
     * @param potentialAncestorScope the potential ancestor scope.
     * @return true if the first scope is the same, or a descendant of, the second scope.
     */
    private static boolean isSameOrDescendantScope(final LocalScope potentialDescendantScope, final LocalScope potentialAncestorScope) {
        if (potentialAncestorScope == null) {
            return false;
        }
       
        if (potentialDescendantScope == potentialAncestorScope) {
            return true;
        }
       
        SymbolTable parent = potentialDescendantScope.getParent();
        while (parent instanceof LocalScope) {
            if (parent == potentialAncestorScope) {
                return true;
            }
           
            if (parent instanceof LocalScope) {
                parent = ((LocalScope)parent).getParent();
            } else {
                break;
            }
        }
       
        return false;
    }
   
    /**
     * Runs the renaming logic for a local variable and returns the necessary modifications in
     * a {@link SourceModifier}.
     *
     * @param moduleTypeInfo ModuleTypeInfo for the module to process
     * @param oldName the identifier being renamed
     * @param newName the name name
     * @param messageLogger CompilerMessageLogger for logging failures
     * @return a SourceModifier that will apply the renaming to the source.
     */
    static SourceModifier getSourceModifier(final ModuleTypeInfo moduleTypeInfo, final String sourceText, final IdentifierInfo.Local oldName, final String newName, final CompilerMessageLogger messageLogger) {

        final SourceModifier sourceModifier = new SourceModifier();
       
        // if the module is a sourceless module, then there is not much we can do with it.
        if (sourceText.length() == 0) {
            return sourceModifier;
        }

        final ModuleName moduleName = moduleTypeInfo.getModuleName();       

        final SourceModel.ModuleDefn moduleDefn = SourceModelUtilities.TextParsing.parseModuleDefnIntoSourceModel(sourceText, messageLogger);
       
        if (moduleDefn == null) {
            return sourceModifier;
        }
       
        final FirstPass firstPass = new FirstPass(moduleName, oldName, newName);
        moduleDefn.accept(firstPass, VisitorArgument.make(SymbolTable.makeRoot(moduleName, IdentifierResolver.makeContext(moduleTypeInfo)), FinderState.make()));
       
        final Set<String> localNamesInAlgebraicFunctionContainingTarget = firstPass.getLocalNamesInAlgebraicFunctionContainingTarget();
       
        final SecondPass secondPass = new SecondPass(moduleName, oldName, newName, firstPass.getAlgebraicFunctionContainingTarget(), firstPass.getAffectedShadowedLocalDefinitions());
        moduleDefn.accept(secondPass, VisitorArgument.make(SymbolTable.makeRoot(moduleName, IdentifierResolver.makeContext(moduleTypeInfo)), FinderState.make()));

        for (final IdentifierOccurrence<?> occurrenceToRename : secondPass.getOccurrencesToRename()) {
            addLocalNameRenameModification(sourceModifier, sourceText, occurrenceToRename, newName);
        }
       
        for (final Reference.Qualifiable<?> occurrenceToQualify : secondPass.getOccurrencesToQualify()) {
            final QualifiedName fullyQualifiedName = occurrenceToQualify.getIdentifierInfo().getResolvedName();
            final ModuleName moduleNameOfReference = fullyQualifiedName.getModuleName();
            final ModuleName minimallyQualifiedModuleNameOfReference = moduleTypeInfo.getModuleNameResolver().getMinimallyQualifiedModuleName(moduleNameOfReference);
            final QualifiedName qualifiedName = QualifiedName.make(minimallyQualifiedModuleNameOfReference, fullyQualifiedName.getUnqualifiedName());
           
            sourceModifier.addSourceModification(IdentifierRenamer.makeReplaceText(sourceText, occurrenceToQualify.getSourceRange(), qualifiedName.toSourceText()));
        }
       
        if (!secondPass.getCollaterallyDamagedLocalNameOccurrences().isEmpty()) {
            final String newNameForCollateralDamage = getNewNameForCollateralDamage(newName, localNamesInAlgebraicFunctionContainingTarget);
            for (final IdentifierOccurrence<?> collateralDamage : secondPass.getCollaterallyDamagedLocalNameOccurrences()) {
                addLocalNameRenameModification(sourceModifier, sourceText, collateralDamage, newNameForCollateralDamage);
            }
        }

        return sourceModifier;
    }

    /**
     * Produces a non-conflicting name for definitions deemed "collateral damage".
     * @param newName the new name of the target.
     * @param localNamesInAlgebraicFunctionContainingTarget the other names in the algebraic function containing the target <i>to be avoided</i>.
     * @return a non-conflicting name.
     */
    private static String getNewNameForCollateralDamage(final String newName, final Set<String> localNamesInAlgebraicFunctionContainingTarget) {
        String newNameForCollateralDamage;
        int disambiguator = 1;
        do {
            newNameForCollateralDamage = newName + "_" + disambiguator;
            disambiguator++;
        } while (localNamesInAlgebraicFunctionContainingTarget.contains(newNameForCollateralDamage));
        return newNameForCollateralDamage;
    }

    /**
     * Adds a source modification corresponding to a local name renaming.
     * @param sourceModifier the source modifier to add to.
     * @param sourceText the source text.
     * @param occurrenceToRename the occurrence to rename.
     * @param newName the new name.
     */
    private static void addLocalNameRenameModification(final SourceModifier sourceModifier, final String sourceText, final IdentifierOccurrence<?> occurrenceToRename, final String newName) {
        if (occurrenceToRename instanceof Binding.PunnedTextualDataConsFieldName<?>) {
            final Binding.PunnedTextualDataConsFieldName<?> punnedBinding = (Binding.PunnedTextualDataConsFieldName<?>)occurrenceToRename;
            // need to unpun the pattern
            sourceModifier.addSourceModification(IdentifierRenamer.makeReplaceText(sourceText, occurrenceToRename.getSourceRange(), punnedBinding.getIdentifierInfo().getVarName() + " = " + newName));
           
        } else if (occurrenceToRename instanceof Binding.PunnedTextualRecordFieldName<?>) {
            final Binding.PunnedTextualRecordFieldName<?> punnedBinding = (Binding.PunnedTextualRecordFieldName<?>)occurrenceToRename;
            // need to unpun the pattern
            sourceModifier.addSourceModification(IdentifierRenamer.makeReplaceText(sourceText, occurrenceToRename.getSourceRange(), punnedBinding.getIdentifierInfo().getVarName() + " = " + newName));
           
        } else {
            sourceModifier.addSourceModification(IdentifierRenamer.makeReplaceText(sourceText, occurrenceToRename.getSourceRange(), newName));
        }
    }
}
TOP

Related Classes of org.openquark.cal.compiler.LocalNameRenamer$SecondPass

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.