Edit

kc3-lang/angle/src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-10-24 12:55:08
    Hash : 859ca039
    Message : Enable "-Wshadow-field". This warning verifies we don't give variables names that shadow fields. This is another good warning to enable that Skia requires. This CL also fixes a small number of points in code that used this bad pattern. We have to disable the warning for Glslang for now. Bug: angleproject:4046 Change-Id: I072a686e3023b60cfafa778525fe712ce1fb5a50 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1877476 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/tree_util/ReplaceShadowingVariables.cpp
  • //
    // Copyright 2019 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // ReplaceShadowingVariables.cpp: Replace all references to any variable in the AST that is
    // a redefinition of a variable in a nested scope. This is a useful for ESSL 1.00 shaders
    // where the spec section "4.2.3. Redeclaring Variables" states "However, a nested scope can
    // override an outer scope's declaration of a particular variable name." This is changed in
    // later spec versions, such as ESSL 3.20 spec which states "If [a variable] is declared as
    // a parameter in a function definition, it is scoped until the end of that function
    // definition. A function's parameter declarations and body together form a single scope."
    //
    // So this class is useful when translating from ESSL 1.00 shaders, where function body var
    // redefinition is allowed, to later shader versions where it's not allowed.
    //
    
    #include "compiler/translator/tree_util/ReplaceShadowingVariables.h"
    #include "compiler/translator/tree_util/ReplaceVariable.h"
    
    #include "compiler/translator/Compiler.h"
    #include "compiler/translator/IntermNode.h"
    #include "compiler/translator/Symbol.h"
    #include "compiler/translator/SymbolTable.h"
    #include "compiler/translator/tree_util/IntermNode_util.h"
    #include "compiler/translator/tree_util/IntermTraverse.h"
    
    #include <unordered_set>
    
    namespace sh
    {
    
    namespace
    {
    
    // Custom struct to queue up any replacements until after AST traversal
    struct DeferredReplacementBlock
    {
        const TVariable *originalVariable;  // variable to be replaced
        TVariable *replacementVariable;     // variable to replace originalVar with
        TIntermBlock *functionBody;         // function body where replacement occurs
    };
    
    class ReplaceShadowingVariablesTraverser : public TIntermTraverser
    {
      public:
        ReplaceShadowingVariablesTraverser(TSymbolTable *symbolTable)
            : TIntermTraverser(true, true, true, symbolTable), mParameterNames{}, mFunctionBody(nullptr)
        {}
    
        bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
        {
            // In pre-visit of function, record params
            if (visit == PreVisit)
            {
                ASSERT(mParameterNames.size() == 0);
                const TFunction *func = node->getFunctionPrototype()->getFunction();
                // Grab all of the parameter names from the function prototype
                size_t paramCount = func->getParamCount();
                for (size_t i = 0; i < paramCount; ++i)
                {
                    mParameterNames.emplace(std::string(func->getParam(i)->name().data()));
                }
                if (mParameterNames.size() > 0)
                    mFunctionBody = node->getBody();
            }
            else if (visit == PostVisit)
            {
                // Clear data saved from function definition
                mParameterNames.clear();
                mFunctionBody = nullptr;
            }
            return true;
        }
        bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
        {
            if (visit == PreVisit && mParameterNames.size() != 0)
            {
                TIntermSequence *decls = node->getSequence();
                for (auto &declVector : *decls)
                {
                    // no init case
                    TIntermSymbol *symNode = declVector->getAsSymbolNode();
                    if (symNode == nullptr)
                    {
                        // init case
                        TIntermBinary *binaryNode = declVector->getAsBinaryNode();
                        ASSERT(binaryNode->getOp() == EOpInitialize);
                        symNode = binaryNode->getLeft()->getAsSymbolNode();
                    }
                    ASSERT(symNode != nullptr);
                    std::string varName = std::string(symNode->variable().name().data());
                    if (mParameterNames.count(varName) > 0)
                    {
                        // We found a redefined var so queue replacement
                        mReplacements.emplace_back(DeferredReplacementBlock{
                            &symNode->variable(),
                            CreateTempVariable(mSymbolTable, &symNode->variable().getType()),
                            mFunctionBody});
                    }
                }
            }
            return true;
        }
        // Perform replacement of vars for any deferred replacements that were identified
        ANGLE_NO_DISCARD bool executeReplacements(TCompiler *compiler)
        {
            for (DeferredReplacementBlock &replace : mReplacements)
            {
                if (!ReplaceVariable(compiler, replace.functionBody, replace.originalVariable,
                                     replace.replacementVariable))
                {
                    return false;
                }
            }
            mReplacements.clear();
            return true;
        }
    
      private:
        std::unordered_set<std::string> mParameterNames;
        TIntermBlock *mFunctionBody;
        std::vector<DeferredReplacementBlock> mReplacements;
    };
    
    }  // anonymous namespace
    
    // Replaces every occurrence of a variable with another variable.
    ANGLE_NO_DISCARD bool ReplaceShadowingVariables(TCompiler *compiler,
                                                    TIntermBlock *root,
                                                    TSymbolTable *symbolTable)
    {
        ReplaceShadowingVariablesTraverser traverser(symbolTable);
        root->traverse(&traverser);
        if (!traverser.executeReplacements(compiler))
        {
            return false;
        }
        return traverser.updateTree(compiler, root);
    }
    
    }  // namespace sh