/// <summary> /// Check that the given variable is definitely assigned. If not, produce an error. /// </summary> /// <param name="local"></param> /// <param name="node"></param> protected void CheckAssigned(Symbol local, SyntaxNode node) { if (local != null && state.Reachable && !state.IsAssigned(VariableSlot(local))) { ReportUnassigned(local, node); } NoteRead(local); }
/// <summary> /// Perform a single pass of flow analysis. Note that after this pass, /// this.backwardBranchChanged indicates if a further pass is required. /// </summary> protected virtual void Scan() { // the entry point of a method is assumed reachable state = FlowAnalysisLocalState.ReachableState(); // label out parameters as not assigned. foreach (var parameter in method.Parameters) { if (parameter.RefKind == RefKind.Out) { SetSlotState(MakeSlot(parameter), initiallyAssignedVariables != null && initiallyAssignedVariables.Contains(parameter)); } else { // this code has no effect except in the region analysis APIs, which assign // variable slots to all parameters. int slot = VariableSlot(parameter); SetSlotState(slot, true); } } // TODO: if this is the body of an initial struct constructor, mark "this" as unassigned. this.backwardBranchChanged = false; if (this.Diagnostics != null) { this.Diagnostics.Free(); } this.Diagnostics = DiagnosticBag.GetInstance(); // clear reported diagnostics this.alreadyReported = BitArray.Empty; // no variables yet reported unassigned VisitStatement(block); // check that each local variable is used somewhere (or warn if it isn't) foreach (var symbol in variableBySlot) { if (symbol != null && symbol.Kind == SymbolKind.Local && !readVariables.Contains(symbol)) { Diagnostics.Add(writtenVariables.Contains(symbol) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.Locations[0], symbol.Name); } } // check that each out parameter is definitely assigned at the end of the method if // there's more than one location, then the method is partial and we prefer to report an // out parameter in partial method error if (method.Locations.Count == 1) { foreach (ParameterSymbol parameter in method.Parameters) { if (parameter.RefKind == RefKind.Out) { var slot = VariableSlot(parameter); if (!state.IsAssigned(slot)) { ReportUnassignedOutParameter(parameter, null, method.Locations[0]); } foreach (PendingBranch returnBranch in pendingBranches) { if (!returnBranch.State.IsAssigned(slot)) { ReportUnassignedOutParameter(parameter, returnBranch.Branch.Syntax, null); } } } } } // TODO: handle "this" in struct constructor. }
/// <summary> /// Perform a single pass of flow analysis. Note that after this pass, /// this.backwardBranchChanged indicates if a further pass is required. /// </summary> protected virtual void Scan() { // the entry point of a method is assumed reachable state = FlowAnalysisLocalState.ReachableState(); // label out parameters as not assigned. foreach (var parameter in method.Parameters) { if (parameter.RefKind == RefKind.Out) { SetSlotState(MakeSlot(parameter), initiallyAssignedVariables != null && initiallyAssignedVariables.Contains(parameter)); } else { // this code has no effect except in the region analysis APIs, which assign // variable slots to all parameters. int slot = VariableSlot(parameter); SetSlotState(slot, true); } } // TODO: if this is the body of an initial struct constructor, mark "this" as unassigned. this.backwardBranchChanged = false; if (this.Diagnostics != null) this.Diagnostics.Free(); this.Diagnostics = DiagnosticBag.GetInstance(); // clear reported diagnostics this.alreadyReported = BitArray.Empty; // no variables yet reported unassigned VisitStatement(block); // check that each local variable is used somewhere (or warn if it isn't) foreach (var symbol in variableBySlot) { if (symbol != null && symbol.Kind == SymbolKind.Local && !readVariables.Contains(symbol)) { Diagnostics.Add(writtenVariables.Contains(symbol) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.Locations[0], symbol.Name); } } // check that each out parameter is definitely assigned at the end of the method if // there's more than one location, then the method is partial and we prefer to report an // out parameter in partial method error if (method.Locations.Count == 1) { foreach (ParameterSymbol parameter in method.Parameters) { if (parameter.RefKind == RefKind.Out) { var slot = VariableSlot(parameter); if (!state.IsAssigned(slot)) { ReportUnassignedOutParameter(parameter, null, method.Locations[0]); } foreach (PendingBranch returnBranch in pendingBranches) { if (!returnBranch.State.IsAssigned(slot)) { ReportUnassignedOutParameter(parameter, returnBranch.Branch.Syntax, null); } } } } } // TODO: handle "this" in struct constructor. }