Beispiel #1
0
 public VariableInfo(
     VariableSymbol variableSymbol,
     VariableStyle variableStyle,
     bool useAsReturnValue = false)
 {
     _variableSymbol   = variableSymbol;
     _variableStyle    = variableStyle;
     _useAsReturnValue = useAsReturnValue;
 }
            protected VariableInfo CreateFromSymbolCommon <T>(
                Compilation compilation,
                ISymbol symbol,
                ITypeSymbol type,
                VariableStyle style,
                HashSet <int> nonNoisySyntaxKindSet) where T : SyntaxNode
            {
                switch (symbol)
                {
                case ILocalSymbol local:
                    return(new VariableInfo(
                               new LocalVariableSymbol <T>(compilation, local, type, nonNoisySyntaxKindSet),
                               style));

                case IParameterSymbol parameter:
                    return(new VariableInfo(new ParameterVariableSymbol(compilation, parameter, type), style));

                case IRangeVariableSymbol rangeVariable:
                    return(new VariableInfo(new QueryVariableSymbol(compilation, rangeVariable, type), style));
                }

                return(Contract.FailWithReturn <VariableInfo>(FeaturesResources.Unknown));
            }
            protected VariableStyle AlwaysReturn(VariableStyle style)
            {
                if (style == VariableStyle.InputOnly)
                {
                    return(VariableStyle.Ref);
                }

                if (style == VariableStyle.MoveIn)
                {
                    return(VariableStyle.Out);
                }

                if (style == VariableStyle.SplitIn)
                {
                    return(VariableStyle.Out);
                }

                if (style == VariableStyle.SplitOut)
                {
                    return(VariableStyle.OutWithMoveOut);
                }

                return(style);
            }
            private bool TryGetVariableStyle(
                bool bestEffort,
                Dictionary <ISymbol, List <SyntaxToken> > symbolMap,
                ISymbol symbol,
                SemanticModel model,
                ITypeSymbol type,
                bool captured,
                bool dataFlowIn,
                bool dataFlowOut,
                bool alwaysAssigned,
                bool variableDeclared,
                bool readInside,
                bool writtenInside,
                bool readOutside,
                bool writtenOutside,
                bool unsafeAddressTaken,
                out VariableStyle variableStyle)
            {
                Contract.ThrowIfNull(model);
                Contract.ThrowIfNull(type);

                if (!ExtractMethodMatrix.TryGetVariableStyle(
                        bestEffort, captured, dataFlowIn, dataFlowOut, alwaysAssigned, variableDeclared,
                        readInside, writtenInside, readOutside, writtenOutside, unsafeAddressTaken,
                        out variableStyle))
                {
                    Contract.ThrowIfTrue(bestEffort, "Should never fail if bestEffort is true");
                    return(false);
                }

                if (SelectionContainsOnlyIdentifierWithSameType(type))
                {
                    return(true);
                }

                if (UserDefinedValueType(model.Compilation, type) && !this.SelectionResult.DontPutOutOrRefOnStruct)
                {
                    variableStyle = AlwaysReturn(variableStyle);
                    return(true);
                }

                // for captured variable, never try to move the decl into extracted method
                if (captured && variableStyle == VariableStyle.MoveIn)
                {
                    variableStyle = VariableStyle.Out;
                    return(true);
                }

                // check special value type cases
                if (type.IsValueType && !IsWrittenInsideForFrameworkValueType(symbolMap, model, symbol, writtenInside))
                {
                    return(true);
                }

                // don't blindly always return. make sure there is a write inside of the selection
                if (this.SelectionResult.AllowMovingDeclaration || !writtenInside)
                {
                    return(true);
                }

                variableStyle = AlwaysReturn(variableStyle);
                return(true);
            }
 /// <summary>
 /// create VariableInfo type
 /// </summary>
 protected abstract VariableInfo CreateFromSymbol(Compilation compilation, ISymbol symbol, ITypeSymbol type, VariableStyle variableStyle, bool variableDeclared);
        public static bool TryGetVariableStyle(
            bool bestEffort,
            bool captured,
            bool dataFlowIn,
            bool dataFlowOut,
            bool alwaysAssigned,
            bool variableDeclared,
            bool readInside,
            bool writtenInside,
            bool readOutside,
            bool writtenOutside,
            bool unsafeAddressTaken,
            out VariableStyle variableStyle)
        {
            // bug # 12258, 12114
            // use "out" if "&" is taken for the variable
            if (unsafeAddressTaken)
            {
                variableStyle = VariableStyle.Out;
                return(true);
            }

            var key = new Key(
                dataFlowIn,
                dataFlowOut,
                alwaysAssigned,
                variableDeclared,
                readInside,
                writtenInside,
                readOutside,
                writtenOutside);

            // special cases
            if (!s_matrix.ContainsKey(key))
            {
                // Interesting case.  Due to things like constant analysis there can be regions that
                // the compiler considers data not to flow in (because analysis proves that that
                // path will never be taken).  However, the variable can still be read/written inside
                // the region.  For purposes of extract method, we check for this case, and we
                // pretend it's as if data flowed into the region.
                if (!dataFlowIn && (readInside || writtenInside))
                {
                    key = new Key(true, dataFlowOut, alwaysAssigned, variableDeclared, readInside, writtenInside, readOutside, writtenOutside);
                }

                // another interesting case (bug # 10875)
                // basically, it can happen in malformed code where a variable is not properly assigned but used outside of the selection + unreachable code region
                // for such cases, treat it like "MoveOut"
                if (!dataFlowOut && !alwaysAssigned && variableDeclared && !writtenInside && readOutside)
                {
                    key = new Key(dataFlowIn, /*dataFlowOut*/ true, alwaysAssigned, variableDeclared, readInside, writtenInside, readOutside, writtenOutside);
                }

                // interesting case in invalid code (bug #19136)
                // variable is passed by reference, and another argument is an out variable with the same name
                if (dataFlowIn && variableDeclared)
                {
                    key = new Key(/*dataFlowIn:*/ false, dataFlowOut, alwaysAssigned, variableDeclared, readInside, writtenInside, readOutside, writtenOutside);
                }
            }

            if (s_matrix.TryGetValue(key, out variableStyle))
            {
                return(true);
            }

            if (bestEffort)
            {
                // In best effort mode, even though we didn't know precisely what to do, we still
                // allow the user to keep going, assuming that this variable is a very basic one.
                variableStyle = VariableStyle.InputOnly;
                return(true);
            }

            // Some combination we didn't anticipate.  Can't do anything here.  Log the issue
            // and bail out.
            FatalError.ReportWithoutCrash(new Exception($"extract method encountered unknown states: {key.ToString()}"));

            return(false);
        }