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); }