// ISymUnmanagedMethod public static SequencePoint[] GetSequencePoints(this ISymUnmanagedMethod symMethod, int codesize) { uint count = symMethod.GetSequencePointCount(); ISymUnmanagedDocument[] documents = new ISymUnmanagedDocument[count]; uint[] offsets = new uint[count]; uint[] lines = new uint[count]; uint[] columns = new uint[count]; uint[] endLines = new uint[count]; uint[] endColumns = new uint[count]; symMethod.GetSequencePoints( count, out count, offsets, documents, lines, columns, endLines, endColumns ); var sequencePoints = new SequencePoint[count]; var urls = documents.Distinct().ToDictionary(d => d, d => d.GetURL()); var sums = documents.Distinct().ToDictionary(d => d, d => d.GetCheckSum()); uint token = symMethod.GetToken(); for(int i = 0; i < count; i++) { sequencePoints[i] = new SequencePoint() { MethodDefToken = token, ILRanges = new [] { new ILRange((int)offsets[i], i + 1 < count ? (int)offsets[i + 1] : codesize) }, Filename = urls[documents[i]], FileCheckSum = sums[documents[i]], StartLine = (int)lines[i], StartColumn = (int)columns[i], EndLine = (int)endLines[i], EndColumn = (int)endColumns[i] }; } return sequencePoints; }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint) { if (!_result.Documents.TryGetValue(sequencePoint.Document.Url, out var document)) { document = new Document { Path = sequencePoint.Document.Url }; document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++) { if (!document.Lines.ContainsKey(i)) { document.Lines.Add(i, new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); } } var entry = (false, document.Index, sequencePoint.StartLine, sequencePoint.EndLine); _result.HitCandidates.Add(entry); return(AddInstrumentationInstructions(method, processor, instruction, _result.HitCandidates.Count - 1)); }
private ArrayAccessNode(ExpressionNode array, IReadOnlyList <ExpressionNode> indices, SequencePoint point) : base(point) { Contract.Requires(array.ExpressionReturnType is ArrayType); this.array = array; this.indices = indices; this.type = ((ArrayType)array.ExpressionReturnType).ElementType; }
private static IndexOperatorAccessNode AsIndexOp(ContextNode context, ExpressionNode array, IReadOnlyList <ExpressionNode> indices, SequencePoint point) { var itemProperty = AssemblyRegistry.GetIndexerProperty(array.ExpressionReturnType, indices.Select(i => i.ExpressionReturnType).ToArray()); if (itemProperty != null) { return(new IndexOperatorAccessNode(context, array, itemProperty, indices, point)); } else { return(null); } }
private Instruction ProcessInstruction(MethodDefinition method, Instruction instruction, SequencePoint sequencePoint) { if ((instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt) && instruction.Operand is MethodReference methodRef) { MethodDefinition resolved = methodRef.Resolve(); if (resolved == addDataMethod) { TypeReference dataType = null; Instruction back = instruction.Previous; while (true) { if (back == null || back.OpCode == OpCodes.Call || back.OpCode == OpCodes.Callvirt) { weaver.Error(sequencePoint, $"Can't determine type of {methodRef}."); return(instruction); } if (back.OpCode == OpCodes.Newarr) { weaver.Error(sequencePoint, "You can't use arrays in custom data."); return(instruction); } if (back.OpCode == OpCodes.Newobj || back.OpCode == OpCodes.Box || back.OpCode == OpCodes.Initobj) { if (back.Operand is TypeReference type) { dataType = type; break; } if (back.Operand is MethodReference ctor && ctor.Name == ".ctor") { dataType = ctor.DeclaringType; break; } } back = back.Previous; } if (dataType == null) { weaver.Error(sequencePoint, $"Couldn't find type for {methodRef}."); return(instruction); } dataType = module.ImportReference(dataType); resolverProcessor.AddCustomDataType(dataType); registerTypeProcessor.AddType(dataType); formatterProcessor.AddTypeToGenerate(dataType); resolverProcessor.AddTypeFormatter( module.GetTypeReference(typeof(DictionaryFormatter <,>)).MakeGenericInstanceType(module.GetTypeReference <string>(), dataType), module.GetTypeReference(typeof(Dictionary <,>)).MakeGenericInstanceType(module.GetTypeReference <string>(), dataType)); } } return(instruction); }
public bool TryResolveLocation(StackFrameData sfData, SeqPointInfo seqPointInfo) { if (!assembly.MainModule.HasSymbols) { return(false); } TypeDefinition type = null; string[] nested; if (sfData.TypeFullName.IndexOf('/') >= 0) { nested = sfData.TypeFullName.Split('/'); } else { nested = sfData.TypeFullName.Split('+'); } var types = assembly.MainModule.Types; foreach (var ntype in nested) { if (type == null) { // Use namespace first time. type = types.FirstOrDefault(t => t.FullName == ntype); } else { type = types.FirstOrDefault(t => t.Name == ntype); } if (type == null) { logger.LogWarning("Could not find type: {0}", ntype); return(false); } types = type.NestedTypes; } var parensStart = sfData.MethodSignature.IndexOf('('); var methodName = sfData.MethodSignature.Substring(0, parensStart).TrimEnd(); var methodParameters = sfData.MethodSignature.Substring(parensStart); var methods = type.Methods.Where(m => CompareName(m, methodName) && CompareParameters(m.Parameters, methodParameters)).ToArray(); if (methods.Length == 0) { logger.LogWarning("Could not find method: {0}", methodName); return(false); } if (methods.Length > 1) { logger.LogWarning("Ambiguous match for method: {0}", sfData.MethodSignature); return(false); } var method = methods [0]; int ilOffset; if (sfData.IsILOffset) { ilOffset = sfData.Offset; } else { if (seqPointInfo == null) { return(false); } ilOffset = seqPointInfo.GetILOffset(method.MetadataToken.ToInt32(), sfData.MethodIndex, sfData.Offset); } if (ilOffset < 0) { return(false); } if (!method.DebugInformation.HasSequencePoints) { return(false); } SequencePoint prev = null; foreach (var sp in method.DebugInformation.SequencePoints.OrderBy(l => l.Offset)) { if (sp.Offset >= ilOffset) { sfData.SetLocation(sp.Document.Url, sp.StartLine); return(true); } prev = sp; } if (prev != null) { sfData.SetLocation(prev.Document.Url, prev.StartLine); return(true); } return(false); }
public void ControlFlow_Stepping() { StartTest(); SequencePoint start = this.CurrentStackFrame.NextStatement; foreach (bool jmcEnabled in new bool[] { true, true, false }) { ObjectDump("Log", "Starting run with JMC=" + jmcEnabled.ToString()); this.CurrentStackFrame.SetIP(start.Filename, start.StartLine + 1, start.StartColumn, false); process.Options.EnableJustMyCode = jmcEnabled; process.Options.StepOverFieldAccessProperties = true; this.CurrentStackFrame.StepInto(); // 42.ToString() Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); if (jmcEnabled) { this.CurrentStackFrame.StepInto(); // StepRoot Assert.AreEqual("StepRight", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepOut(); this.CurrentStackFrame.StepOver(); // Finish the step out Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); } else { this.CurrentStackFrame.StepInto(); // StepRoot Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); } this.CurrentStackFrame.StepInto(); // Generated default constructor Assert.AreEqual("Target", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepOut(); this.CurrentStackFrame.StepOver(); // Finish the step out Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepInto(); // Property Assert.AreNotEqual("Main", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepOut(); this.CurrentStackFrame.StepOver(); // Finish the step out Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepInto(); // FieldProperty Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepInto(); // CatchExcpetion Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); if (jmcEnabled) { this.CurrentStackFrame.StepInto(); // ZigZag1 this.CurrentStackFrame.StepOver(); this.CurrentStackFrame.StepOver(); Assert.AreEqual("ZigZag2", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepInto(); Assert.AreEqual("ZigZag2", this.CurrentStackFrame.MethodInfo.Name); Assert.AreEqual(3, this.CurrentStackFrame.NextStatement.StartColumn); this.CurrentStackFrame.StepOut(); this.CurrentStackFrame.StepOver(); // Finish the step out Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); } else { this.CurrentStackFrame.StepInto(); // ZigZag1 Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); } this.CurrentStackFrame.StepInto(); // MyEvent Assert.AreEqual("Event2", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepOut(); Assert.AreEqual("Event4", this.CurrentStackFrame.MethodInfo.Name); this.CurrentStackFrame.StepOut(); this.CurrentStackFrame.StepOver(); // Finish the step out Assert.AreEqual("Main", this.CurrentStackFrame.MethodInfo.Name); } // Restore default state process.Options.EnableJustMyCode = true; EndTest(); }
public void SetSequencePoints(IEnumerable<ILSequencePoint> ilSequencePoints) { try { SequencePoint[] sequencePoints = new SequencePoint[_ilBytes.Length]; foreach (var point in ilSequencePoints) { sequencePoints[point.Offset] = new SequencePoint() { Document = point.Document, LineNumber = point.LineNumber }; } _sequencePoints = sequencePoints; } catch { } }
public void ConstructWithSingleLine() { // arrange const string input = "single line"; var source = new CodeCoverageStringTextSource(input, ""); // assert Assert.True(source.LinesCount == 1); // act var result = source.GetLine(1); // existing line index // assert Assert.True(result == input); // act result = source.GetLine(0); // invalid line index // assert Assert.True(result == string.Empty); // act var sp = new SequencePoint { StartLine = 1, StartColumn = 1, EndLine = 1, EndColumn = 7 }; result = source.GetText(sp); // assert Assert.True(result == "single"); // act with too small StartColumn sp = new SequencePoint { StartLine = 1, StartColumn = -1, EndLine = 1, EndColumn = 7 }; result = source.GetText(sp); // assert Assert.True(result == "single"); // act with too large StartColumn sp = new SequencePoint { StartLine = 1, StartColumn = 19, EndLine = 1, EndColumn = 20 }; result = source.GetText(sp); // assert Assert.True(result == ""); // act with too small EndColumn sp = new SequencePoint { StartLine = 1, StartColumn = 1, EndLine = 1, EndColumn = 0 }; result = source.GetText(sp); // assert Assert.True(result == ""); // act with too large EndColumn sp = new SequencePoint { StartLine = 1, StartColumn = 1, EndLine = 1, EndColumn = 20 }; result = source.GetText(sp); // assert Assert.True(result == "single line"); }
public void ConstructWithFiveLines() { // arrange const string input = "\tfirst line\n \n\tthird line\r\n \r fifth line\r"; var source = new CodeCoverageStringTextSource(input, ""); // assert Assert.True(source.LinesCount == 5); // act var result = source.GetLine(1); // existing line index // assert Assert.True(result == "\tfirst line\n"); // act result = source.GetLine(2); // existing line index // assert Assert.True(result == " \n"); // act result = source.GetLine(3); // existing line index // assert Assert.True(result == "\tthird line\r\n"); // act result = source.GetLine(4); // existing line index // assert Assert.True(result == " \r"); // act result = source.GetLine(5); // existing line index // assert Assert.True(result == " fifth line\r"); // act result = source.GetLine(9); // invalid line index // assert Assert.True(result == string.Empty); // act third line request var sp = new SequencePoint { StartLine = 3, StartColumn = 8, EndLine = 3, EndColumn = 12 }; result = source.GetText(sp); // assert Assert.True(result == "line"); // act invalid two lines request sp = new SequencePoint { StartLine = 1, StartColumn = 8, EndLine = 2, EndColumn = 13 }; result = source.GetText(sp); // assert Assert.True(result == "line\n \n"); // act valid two lines request sp = new SequencePoint { StartLine = 1, StartColumn = 8, EndLine = 2, EndColumn = 2 }; result = source.GetText(sp); // assert Assert.True(result == "line\n "); // act three lines request sp = new SequencePoint { StartLine = 1, StartColumn = 8, EndLine = 3, EndColumn = 12 }; result = source.GetText(sp); // assert Assert.True(result == "line\n \n\tthird line"); }
public void ConstructWithTwoLines() { // arrange const string input = "\tfirst line\n\tsecond line\r"; var source = new CodeCoverageStringTextSource(input, ""); // assert Assert.True(source.LinesCount == 2); // act with existing line index var result = source.GetLine(1); // assert Assert.True(result == "\tfirst line\n"); // act with existing line index result = source.GetLine(2); // assert Assert.True(result == "\tsecond line\r"); // act with invalid line index result = source.GetLine(0); // assert Assert.True(result == string.Empty); // act var sp = new SequencePoint { StartLine = 2, StartColumn = 9, EndLine = 2, EndColumn = 13 }; result = source.GetText(sp); // assert Assert.True(result == "line"); // act with two lines request sp = new SequencePoint { StartLine = 1, StartColumn = 8, EndLine = 2, EndColumn = 13 }; result = source.GetText(sp); // assert Assert.True(result == "line\n\tsecond line"); // act with extended two lines request sp = new SequencePoint { StartLine = 1, StartColumn = -8, EndLine = 2, EndColumn = 30 }; result = source.GetText(sp); // assert Assert.True(result == "\tfirst line\n\tsecond line\r"); // act with invalid first line request sp = new SequencePoint { StartLine = 1, StartColumn = 28, EndLine = 2, EndColumn = 30 }; result = source.GetText(sp); // assert Assert.True(result == "\tsecond line\r"); // act with invalid first line and invalid second line request sp = new SequencePoint { StartLine = 1, StartColumn = 28, EndLine = 2, EndColumn = 0 }; result = source.GetText(sp); // assert Assert.True(result == ""); }
static MethodBody CreateTestMethodWithLocalScopes(bool padILWithNulls) { var module = ModuleDefinition.CreateModule("TestILProcessor", ModuleKind.Dll); var type = new TypeDefinition("NS", "TestType", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed, module.ImportReference(typeof(object))); module.Types.Add(type); var methodBody = CreateTestMethod(OpCodes.Nop, OpCodes.Ldloc_0, OpCodes.Nop, OpCodes.Ldloc_1, OpCodes.Nop, OpCodes.Ldloc_2, OpCodes.Nop); if (padILWithNulls) { methodBody.Instructions.Capacity += 10; } var method = methodBody.Method; method.ReturnType = module.ImportReference(typeof(void)); type.Methods.Add(method); methodBody.InitLocals = true; var tempVar1 = new VariableDefinition(module.ImportReference(typeof(string))); methodBody.Variables.Add(tempVar1); var tempVar2 = new VariableDefinition(module.ImportReference(typeof(string))); methodBody.Variables.Add(tempVar2); var debug_info = method.DebugInformation; // Must add a sequence point, otherwise the native PDB writer will not actually write the method's debug info // into the PDB. foreach (var instr in methodBody.Instructions) { var sequence_point = new SequencePoint(instr, new Document(@"C:\test.cs")) { StartLine = 0, StartColumn = 0, EndLine = 0, EndColumn = 4, }; debug_info.SequencePoints.Add(sequence_point); } // The method looks like this: // | Scope | Scope.Scopes[0] | Scope.Scopes[1] | Scope.Scopes[1].Scopes[0] // #0 Nop | > | | | // #1 Ldloc_0 | . | > | | // #2 Nop | . | < | | // #3 Ldloc_1 | . | | > | // #4 Nop | . | | . | > // #5 Ldloc_2 | . | | . | < // #6 Nop | . | | . | // <end of m> | < | | < | var instructions = methodBody.Instructions; debug_info.Scope = new ScopeDebugInformation(instructions[0], null) { Scopes = { new ScopeDebugInformation(instructions[1], instructions[2]) { Variables = { new VariableDebugInformation(tempVar1,"tempVar1") } }, new ScopeDebugInformation(instructions[3], null) { Scopes = { new ScopeDebugInformation(instructions[4], instructions[5]) { Variables = { new VariableDebugInformation(tempVar2,"tempVar2") } } } } } }; return(methodBody); }
void ReadLines (PdbLine line, Document document, IDictionary instructions) { Instruction instruction = (Instruction) instructions [(int) line.offset]; if (instruction == null) return; SequencePoint point = new SequencePoint (document); point.StartLine = (int) line.lineBegin; point.StartColumn = (int) line.colBegin; point.EndLine = (int) line.lineEnd; point.EndColumn = (int) line.colEnd; instruction.SequencePoint = point; }
internal void MergeFrom(SequencePoint sequencePoint) { foreach (var appliedMutant in sequencePoint.AppliedMutants) { if (AppliedMutants.All(a => a.Description != appliedMutant.Description)) { AppliedMutants.Add(appliedMutant); } } }
private IEnumerable <RawDependency> AnalyzeInstruction([NotNull] TypeDefinition owner, [NotNull] RawUsingItem usingItem, [NotNull] Instruction instruction, [CanBeNull] SequencePoint sequencePoint, [NotNull] WorkingGraph readingGraph) { { var methodReference = instruction.Operand as MethodReference; // Durch die !IsLinked-Bedingung wird der Test MainTests.Exit0Aspects mit den Calls // zwischen Nested-Klassen in NDepCheck.TestAssembly.cs - Klasse Class14.Class13EInner2, Methode SpecialMethodOfInnerClass // rot: Weil die Calls zwischen der Class14 und der Nested Class wegen IsLinked==true hier einfach ausgefiltert // werden ... // WIESO SOLL DAS SO SEIN? - bitte um Erklärung! ==> SIehe nun temporäre Änderung an IsLinked - IST DAS OK? if (methodReference != null && !IsLinked(methodReference.DeclaringType, owner)) { foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, DOTNETMETHOD, GetMemberMarkers(Resolve(methodReference.DeclaringType), _typeDefinitionMarkers), methodReference.DeclaringType, usage: DotNetUsage._usesmember, sequencePoint: sequencePoint, memberName: methodReference.Name, readingGraph: readingGraph)) { yield return(dependency_); } // See comment at Usage._usesmemberoftype on why this is commented out //foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, // GetMemberMarkers(Resolve(methodReference.ReturnType), _typeDefinitionMarkers), // methodReference.ReturnType, usage: Usage._usesmemberoftype, sequencePoint: sequencePoint, memberName: "")) { // yield return dependency_; //} } } { var field = instruction.Operand as FieldDefinition; if (field != null && !IsLinked(field.DeclaringType, owner)) { foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, DOTNETFIELD, GetMemberMarkers(field, _fieldDefinitionMarkers), field.FieldType, usage: DotNetUsage._usesmember, sequencePoint: sequencePoint, memberName: field.Name, readingGraph: readingGraph)) { yield return(dependency_); } // See comment at Usage._usesmemberoftype on why this is commented out //foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, GetMemberMarkers(field, _fieldDefinitionMarkers), // field.DeclaringType, usage: Usage._usesmemberoftype, sequencePoint: sequencePoint, memberName: "")) { // yield return dependency_; //} } } { var property = instruction.Operand as PropertyDefinition; if (property != null && !IsLinked(property.DeclaringType, owner)) { foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, DOTNETPROPERTY, GetMemberMarkers(property, _propertyDefinitionMarkers), property.PropertyType, usage: DotNetUsage._usesmember, sequencePoint: sequencePoint, memberName: property.Name, readingGraph: readingGraph)) { yield return(dependency_); } // See comment at Usage._usesmemberoftype on why this is commented out //foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, GetMemberMarkers(property, _propertyDefinitionMarkers), // property.DeclaringType, usage: Usage._usesmemberoftype, sequencePoint: sequencePoint, memberName: "")) { // yield return dependency_; //} } } { var typeref = instruction.Operand as TypeReference; if (typeref != null && !IsLinked(typeref, owner)) { foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, DOTNETTYPE, GetMemberMarkers(Resolve(typeref), _typeDefinitionMarkers), typeref, usage: DotNetUsage._usestype, sequencePoint: sequencePoint, memberName: "", readingGraph: readingGraph)) { yield return(dependency_); } } } }
public MethodReference GetReadFunc <T>(SequencePoint sequencePoint) => GetReadFunc(module.ImportReference <T>(), sequencePoint);
public CompilationMessage(string text, SequencePoint sp) { Text = text; SequencePoint = sp ?? new SequencePoint(Instruction.Create(OpCodes.Nop), new Document(string.Empty)); }
public Instruction(SequencePoint sequencePoint) { this.m_SequencePoint = sequencePoint; }
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint) { var document = _result.Documents.FirstOrDefault(d => d.Path == sequencePoint.Document.Url); if (document == null) { document = new Document { Path = sequencePoint.Document.Url }; _result.Documents.Add(document); } for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++) { if (!document.Lines.Exists(l => l.Number == i)) { document.Lines.Add(new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); } } string marker = $"{document.Path},{sequencePoint.StartLine},{sequencePoint.EndLine}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(typeof(CoverageTracker).GetMethod("MarkExecuted"))); processor.InsertBefore(instruction, callInstr); processor.InsertBefore(callInstr, markInstr); processor.InsertBefore(markInstr, pathInstr); return(pathInstr); }
public virtual void Visit(SequencePoint node) { }
public IList <string> Merge(List <TypeDefinition> subclasses, string applicationClass, bool embed, string bundledWearApplicationName, IEnumerable <string> mergedManifestDocuments) { string applicationName = ApplicationName; var manifest = doc.Root; if (manifest == null || manifest.Name != "manifest") { throw new Exception("Root element must be 'manifest'"); } var manifest_package = (string)manifest.Attribute("package"); if (!string.IsNullOrWhiteSpace(manifest_package)) { PackageName = manifest_package; } manifest.SetAttributeValue(XNamespace.Xmlns + "android", "http://schemas.android.com/apk/res/android"); if (manifest.Attribute(androidNs + "versionCode") == null) { manifest.SetAttributeValue(androidNs + "versionCode", "1"); } if (manifest.Attribute(androidNs + "versionName") == null) { manifest.SetAttributeValue(androidNs + "versionName", "1.0"); } app = CreateApplicationElement(manifest, applicationClass, subclasses); if (app.Attribute(androidNs + "label") == null && applicationName != null) { app.SetAttributeValue(androidNs + "label", applicationName); } var existingTypes = new HashSet <string> ( app.Descendants().Select(a => (string)a.Attribute(attName)).Where(v => v != null)); if (!string.IsNullOrEmpty(bundledWearApplicationName)) { if (!app.Elements("meta-data").Any(e => e.Attributes(androidNs + "name").Any(a => a.Value == bundledWearApplicationName))) { app.Add(new XElement("meta-data", new XAttribute(androidNs + "name", "com.google.android.wearable.beta.app"), new XAttribute(androidNs + "resource", "@xml/wearable_app_desc"))); } } // If no <uses-sdk> is specified, add it with both minSdkVersion and // targetSdkVersion set to TargetFrameworkVersion if (!manifest.Elements("uses-sdk").Any()) { manifest.AddFirst( new XElement("uses-sdk", new XAttribute(androidNs + "minSdkVersion", SdkVersionName), new XAttribute(androidNs + "targetSdkVersion", SdkVersionName))); } // If no minSdkVersion is specified, set it to TargetFrameworkVersion var uses = manifest.Element("uses-sdk"); if (uses.Attribute(androidNs + "minSdkVersion") == null) { int minSdkVersion; if (!int.TryParse(SdkVersionName, out minSdkVersion)) { minSdkVersion = XABuildConfig.NDKMinimumApiAvailable; } minSdkVersion = Math.Min(minSdkVersion, XABuildConfig.NDKMinimumApiAvailable); uses.SetAttributeValue(androidNs + "minSdkVersion", minSdkVersion.ToString()); } string targetSdkVersion; var tsv = uses.Attribute(androidNs + "targetSdkVersion"); if (tsv != null) { targetSdkVersion = tsv.Value; } else { targetSdkVersion = SdkVersionName; uses.AddBeforeSelf(new XComment("suppress UsesMinSdkAttributes")); } int?tryTargetSdkVersion = MonoAndroidHelper.SupportedVersions.GetApiLevelFromId(targetSdkVersion); if (!tryTargetSdkVersion.HasValue) { throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion)); } int targetSdkVersionValue = tryTargetSdkVersion.Value; foreach (var t in subclasses) { if (t.IsAbstract) { continue; } if (PackageName == null) { PackageName = t.Namespace; } var name = JavaNativeTypeManager.ToJniName(t).Replace('/', '.'); var compatName = JavaNativeTypeManager.ToCompatJniName(t).Replace('/', '.'); if (((string)app.Attribute(attName)) == compatName) { app.SetAttributeValue(attName, name); } Func <TypeDefinition, string, int, XElement> generator = GetGenerator(t); if (generator == null) { continue; } try { // activity not present: create a launcher for it IFF it has attribute if (!existingTypes.Contains(name) && !existingTypes.Contains(compatName)) { XElement fromCode = generator(t, name, targetSdkVersionValue); if (fromCode == null) { continue; } IEnumerable <MethodDefinition> constructors = t.Methods.Where(m => m.IsConstructor).Cast <MethodDefinition> (); if (!constructors.Any(c => !c.HasParameters && c.IsPublic)) { string message = $"The type '{t.FullName}' must provide a public default constructor"; SequencePoint sourceLocation = FindSource(constructors); if (sourceLocation != null && sourceLocation.Document?.Url != null) { log.LogError( subcategory: String.Empty, errorCode: "XA4213", helpKeyword: String.Empty, file: sourceLocation.Document.Url, lineNumber: sourceLocation.StartLine, columnNumber: sourceLocation.StartColumn, endLineNumber: sourceLocation.EndLine, endColumnNumber: sourceLocation.EndColumn, message: message); } else { log.LogCodedError("XA4213", message); } continue; } app.Add(fromCode); } foreach (var d in app.Descendants().Where(a => ((string)a.Attribute(attName)) == compatName)) { d.SetAttributeValue(attName, name); } } catch (InvalidActivityNameException ex) { log.LogErrorFromException(ex); } } var icon = app.Attribute(androidNs + "icon"); if (icon == null) { var activity = app.Element("activity"); if (activity != null) { var activityIcon = activity.Attribute(androidNs + "icon"); if (activityIcon != null) { app.Add(new XAttribute(androidNs + "icon", activityIcon.Value)); } } } PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName); if (!PackageName.Contains('.')) { throw new InvalidOperationException("/manifest/@package attribute MUST contain a period ('.')."); } manifest.SetAttributeValue("package", PackageName); if (MultiDex) { app.Add(CreateMonoRuntimeProvider("mono.android.MultiDexLoader", null, initOrder: --AppInitOrder)); } var providerNames = AddMonoRuntimeProviders(app); if (Debug && !embed && InstantRunEnabled) { if (int.TryParse(SdkVersion, out int apiLevel) && apiLevel >= 19) { app.Add(CreateMonoRuntimeProvider("mono.android.ResourcePatcher", null, initOrder: --AppInitOrder)); } } if (Debug) { app.Add(new XComment("suppress ExportedReceiver")); app.Add(new XElement("receiver", new XAttribute(androidNs + "name", "mono.android.Seppuku"), new XElement("intent-filter", new XElement("action", new XAttribute(androidNs + "name", "mono.android.intent.action.SEPPUKU")), new XElement("category", new XAttribute(androidNs + "name", "mono.android.intent.category.SEPPUKU." + PackageName))))); if (app.Attribute(androidNs + "debuggable") == null) { app.Add(new XAttribute(androidNs + "debuggable", "true")); } } if (Debug || NeedsInternet) { AddInternetPermissionForDebugger(); } if (!embed) { AddFastDeployPermissions(); } // If the manifest has android:installLocation, but we are targeting // API 7 or lower, remove it for the user and show a warning if (manifest.Attribute(androidNs + "installLocation") != null) { if (targetSdkVersionValue < 8) { manifest.Attribute(androidNs + "installLocation").Remove(); Console.Error.WriteLine("monodroid: warning 1 : installLocation cannot be specified for Android versions less than 2.2. Attribute installLocation ignored."); } } AddInstrumentations(manifest, subclasses, targetSdkVersionValue); AddPermissions(app); AddPermissionGroups(app); AddPermissionTrees(app); AddUsesPermissions(app); AddUsesFeatures(app); AddSupportsGLTextures(app); ReorderActivityAliases(app); ReorderElements(app); if (mergedManifestDocuments != null) { foreach (var mergedManifest in mergedManifestDocuments) { try { MergeLibraryManifest(mergedManifest); } catch (Exception ex) { log.LogCodedWarning("XA4302", "Unhandled exception merging `AndroidManifest.xml`: {0}", ex); } } } return(providerNames); SequencePoint FindSource(IEnumerable <MethodDefinition> methods) { if (methods == null) { return(null); } SequencePoint ret = null; foreach (MethodDefinition method in methods.Where(m => m != null && m.HasBody && m.DebugInformation != null)) { foreach (Instruction ins in method.Body.Instructions) { SequencePoint seq = method.DebugInformation.GetSequencePoint(ins); if (seq == null) { continue; } if (ret == null || seq.StartLine < ret.StartLine) { ret = seq; } break; } } return(ret); } }
public static void UpdateDebugInfo(this MethodDefinition method) { var debugInfo = method.DebugInformation; var instructions = method.Body.Instructions; var scope = debugInfo.Scope; if (scope is null || instructions.Count == 0) { return; } var oldSequencePoints = debugInfo.SequencePoints; var newSequencePoints = new Collection <SequencePoint>(); // Step 1: check if all variables are present foreach (var variable in method.Body.Variables) { var hasVariable = scope.Variables.Any(x => x.Index == variable.Index); if (!hasVariable) { var variableDebugInfo = new VariableDebugInformation(variable, $"__var_{variable.Index}"); scope.Variables.Add(variableDebugInfo); } } // Step 2: Make sure the instructions point to the correct items foreach (var oldSequencePoint in oldSequencePoints) { //var isValid = false; //// Special cases we need to ignore //if (oldSequencePoint.StartLine == AddressToIgnore || // oldSequencePoint.EndLine == AddressToIgnore) //{ // continue; //} var instructionOffset = (InstructionOffset)SequencePointOffsetFieldInfo.GetValue(oldSequencePoint); var offsetInstruction = (Instruction)InstructionOffsetInstructionFieldInfo.GetValue(instructionOffset); // Fix offset for (var i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; if (instruction == offsetInstruction) { var newSequencePoint = new SequencePoint(instruction, oldSequencePoint.Document) { StartLine = oldSequencePoint.StartLine, StartColumn = oldSequencePoint.StartColumn, EndLine = oldSequencePoint.EndLine, EndColumn = oldSequencePoint.EndColumn }; newSequencePoints.Add(newSequencePoint); //isValid = true; break; } } } debugInfo.SequencePoints.Clear(); foreach (var newSequencePoint in newSequencePoints) { debugInfo.SequencePoints.Add(newSequencePoint); } // Step 3: update the scopes by setting the indices scope.Start = new InstructionOffset(instructions.First()); scope.End = new InstructionOffset(instructions.Last()); }
private Instruction ProcessInstruction(MethodDefinition md, Instruction instr, SequencePoint sequencePoint) { if (instr.OpCode == OpCodes.Stfld && instr.Operand is FieldReference opFieldst) { FieldReference resolved = opFieldst.Resolve(); if (resolved == null) { resolved = opFieldst.DeclaringType.Resolve().GetField(opFieldst.Name); } // this instruction sets the value of a field. cache the field reference. ProcessInstructionSetterField(instr, resolved); } if (instr.OpCode == OpCodes.Ldfld && instr.Operand is FieldReference opFieldld) { FieldReference resolved = opFieldld.Resolve(); if (resolved == null) { resolved = opFieldld.DeclaringType.Resolve().GetField(opFieldld.Name); } // this instruction gets the value of a field. cache the field reference. ProcessInstructionGetterField(instr, resolved); } if (instr.OpCode == OpCodes.Ldflda && instr.Operand is FieldReference opFieldlda) { FieldReference resolved = opFieldlda.Resolve(); if (resolved == null) { resolved = opFieldlda.DeclaringType.Resolve().GetField(opFieldlda.Name); } // loading a field by reference, watch out for initobj instruction // see https://github.com/vis2k/Mirror/issues/696 return(ProcessInstructionLoadAddress(md, instr, resolved)); } return(instr); }
private static ArrayAccessNode AsArray(ContextNode context, ExpressionNode array, IReadOnlyList <ExpressionNode> indices, SequencePoint point) { var type = array.ExpressionReturnType as ArrayType; if (type == null) { return(null); } foreach (var index in indices) { if (!index.ExpressionReturnType.IsAssignableTo(context.Parser.Int32) || index.ExpressionReturnType.IsAssignableTo(context.Parser.UInt32)) { ErrorCode.InvalidIndexType.ReportAndThrow(index.SequencePoint, "Invalid index, must be an integer"); } } if (indices.Count != type.Rank) { ErrorCode.InvalidIndexCount.ReportAndThrow(point, "Invalid array indexing, rank is {0}, index count is {1}", type.Rank, indices.Count); } return(new ArrayAccessNode(array, indices, point)); }
void AnalyzeMethodBody(AssemblyInfo assemblyInfo, MethodDefinition caller, Action <CallInfo> onCallFound, Action <ProjectIssue> onIssueFound) { if (!caller.DebugInformation.HasSequencePoints) { return; } Profiler.BeginSample("ScriptAuditor.AnalyzeMethodBody"); var callerNode = new CallTreeNode(caller); var perfCriticalContext = IsPerformanceCriticalContext(caller); foreach (var inst in caller.Body.Instructions.Where(i => m_OpCodes.Contains(i.OpCode))) { SequencePoint s = null; for (var i = inst; i != null; i = i.Previous) { s = caller.DebugInformation.GetSequencePoint(i); if (s != null) { break; } } Location location = null; if (s != null) { location = new Location(AssemblyHelper.ResolveAssetPath(assemblyInfo, s.Document.Url), s.StartLine); callerNode.location = location; } else { // sequence point not found. Assuming caller.IsHideBySig == true } if (inst.OpCode == OpCodes.Call || inst.OpCode == OpCodes.Callvirt) { onCallFound(new CallInfo { callee = (MethodReference)inst.Operand, caller = caller, location = location, perfCriticalContext = perfCriticalContext }); } foreach (var analyzer in m_InstructionAnalyzers) { if (analyzer.GetOpCodes().Contains(inst.OpCode)) { var projectIssue = analyzer.Analyze(caller, inst); if (projectIssue != null) { projectIssue.dependencies.perfCriticalContext = perfCriticalContext; projectIssue.dependencies.AddChild(callerNode); projectIssue.location = location; projectIssue.SetCustomProperties(new[] { assemblyInfo.name }); onIssueFound(projectIssue); } } } } Profiler.EndSample(); }
private static ArrayCreationNode AsArrayCreation(ContextNode context, ExpressionNode array, IReadOnlyList <ExpressionNode> indices, SequencePoint point) { var type = array as TypeNode; if (type == null) { return(null); } return(ArrayCreationNode.Create(context, type.ParsedType, indices, null, point)); }
private static LiteralNode ParseValue(ProjectParser parser, string value, TypeReference type, SequencePoint point) { try { switch (type.MetadataType) { case MetadataType.String: case MetadataType.Boolean: return(new LiteralNode(value, type, point)); case MetadataType.SByte: case MetadataType.Byte: case MetadataType.Int16: case MetadataType.UInt16: case MetadataType.Int32: case MetadataType.UInt32: case MetadataType.Int64: case MetadataType.UInt64: return(ParseInteger(parser, value, type, point)); case MetadataType.Char: { if (value.Length > 1) { ErrorCode.MultipleCharacterLiteral.ReportAndThrow(point, "Character literal must not be longer than one character (found: '{0}').", value); } return(new LiteralNode(value, type, point)); } case MetadataType.Single: case MetadataType.Double: return(ParseRational(parser, value, type, point)); default: ContractsHelper.AssumeUnreachable(String.Format("Unexpected literal type {0}", type.FullName)); return(null); //unreachable } } catch (OverflowException) { ErrorCode.InvalidStructure.ReportAndThrow(point, "Could not parse {0} as {1}, overflow", value, type.FullName); return(null);//unreachable } catch (FormatException) { ErrorCode.InvalidStructure.ReportAndThrow(point, "Could not parse {0} as {1}, format error", value, type.FullName); return(null);//unreachable } }
public static ExpressionNode Create(ContextNode context, ExpressionNode array, IReadOnlyList <ExpressionNode> indices, SequencePoint point) { Contract.Requires(indices.Any()); Contract.Ensures(Contract.Result <ExpressionNode>() != null); foreach (var index in indices) { if (!index.IsGettable) { ErrorCode.NotAnRValue.ReportAndThrow(index.SequencePoint, "Invalid index, must be a gettable expression"); } } if (!array.IsGettable && array.ExpressionType != ExpressionNodeType.ParserInternal) { ErrorCode.NotAnRValue.ReportAndThrow(point, "Left operand for [] operator must be gettable"); } ExpressionNode result = AsArrayCreation(context, array, indices, point); if (result != null) { return(result); } result = AsIndexOp(context, array, indices, point); if (result != null) { return(result); } result = AsArray(context, array, indices, point); if (result != null) { return(result); } ErrorCode.CannotIndex.ReportAndThrow(point, "Cannot use operator[], not type, array or object with overloaded [] operator"); return(Utils.Utils.Fail <ExpressionNode>()); }
private static LiteralNode ParseInteger(ProjectParser parser, string value, TypeReference requestedType, SequencePoint point) { try { var parsed = BigInteger.Parse(value, CultureInfo.InvariantCulture); var type = GetLowestConversion(parser, parsed); if (type == null) { ErrorCode.IntegerOverflow.ReportAndThrow(point, "Cannot fit {0} into an integer, use BigInteger.Parse", value); } else { //return what we parsed, if requested type can't fit if (type.IsAssignableTo(requestedType)) { type = requestedType; } } if (parsed.Sign >= 0) { return(new LiteralNode((ulong)parsed, type, point)); } else { return(new LiteralNode((long)parsed, type, point)); } } catch (FormatException) { ContractsHelper.AssumeUnreachable("Error parsing {0} as integer", value); } return(Utils.Utils.Fail <LiteralNode>()); }
public void CanLoadExistingFileWhenInitialising() { // arrange var moduleHash = Guid.NewGuid().ToString(); var persistence = new FilePersistance(_mockCommandLine.Object, _mockLogger.Object); persistence.Initialise(_filePath, false); var point = new SequencePoint() // BranchPoints within SequencePoint shorther than 3 characters will be removed { StartLine = 1, EndLine = 1, StartColumn = 1, EndColumn = 4 }; var branchPoint = new BranchPoint { Path = 0, OffsetPoints = new List <int>() }; var branchPoint2 = new BranchPoint { Path = 1, OffsetPoints = new List <int> { 1, 2 } }; var file = new OpenCover.Framework.Model.File(); var filref = new FileRef() { UniqueId = file.UniqueId }; persistence.PersistModule(new Module { Summary = new Summary { NumSequencePoints = 1 }, Files = new[] { file }, ModuleHash = moduleHash, Classes = new[] { new Class { Summary = new Summary { NumSequencePoints = 1 }, Files = new[] { file }, Methods = new[] { new Method { FileRef = filref, MetadataToken = 1234, Summary = new Summary { NumSequencePoints = 1 }, MethodPoint = point, SequencePoints = new[] { point }, BranchPoints = new[] { branchPoint, branchPoint2 } } } } } }); persistence.Commit(); var persistence2 = new FilePersistance(_mockCommandLine.Object, _mockLogger.Object); // act persistence2.Initialise(_filePath, true); // assert Assert.IsNotNull(persistence2.CoverageSession); Assert.AreEqual(moduleHash, persistence2.CoverageSession.Modules[0].ModuleHash); Assert.AreEqual(point.UniqueSequencePoint, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].SequencePoints[0].UniqueSequencePoint); Assert.AreEqual(point.UniqueSequencePoint, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].MethodPoint.UniqueSequencePoint); var method = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0]; var br1 = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].BranchPoints[0]; var br2 = persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].BranchPoints[1]; Assert.AreEqual(branchPoint.UniqueSequencePoint, br1.UniqueSequencePoint); Assert.AreEqual(branchPoint2.UniqueSequencePoint, br2.UniqueSequencePoint); Assert.AreEqual(0, br1.OffsetPoints.Count); Assert.AreEqual(2, br2.OffsetPoints.Count); Assert.AreEqual(1, br2.OffsetPoints[0]); Assert.AreEqual(2, br2.OffsetPoints[1]); // the method and sequence point if point to same offset need to merge Assert.AreSame(method.MethodPoint, method.SequencePoints[0]); // the loaded summary object needs to be cleared Assert.AreEqual(0, persistence2.CoverageSession.Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Classes[0].Summary.NumSequencePoints); Assert.AreEqual(0, persistence2.CoverageSession.Modules[0].Classes[0].Methods[0].Summary.NumSequencePoints); }
private static LiteralNode ParseRational(ProjectParser parser, string value, TypeReference requestedType, SequencePoint point) { try { switch (requestedType.MetadataType) { case MetadataType.Single: return(new LiteralNode(Convert.ToSingle(value, CultureInfo.InvariantCulture), requestedType, point)); case MetadataType.Double: return(new LiteralNode(Convert.ToDouble(value, CultureInfo.InvariantCulture), requestedType, point)); default: ContractsHelper.AssertUnreachable("Unexpected type {0} in ParseRational", requestedType.MetadataType); return(Utils.Utils.Fail <LiteralNode>()); } } catch (OverflowException) { ErrorCode.InvalidStructure.ReportAndThrow(point, "Could not parse {0} as {1}, overflow", value, requestedType.FullName); return(Utils.Utils.Fail <LiteralNode>()); } catch (FormatException) { ErrorCode.InvalidStructure.ReportAndThrow(point, "Could not parse {0} as {1}, format error", value, requestedType.FullName); return(Utils.Utils.Fail <LiteralNode>()); } }
/// <summary> /// Create a single dependency to the calledType or (if passed) calledType+method. /// Create additional dependencies for each generic parameter type of calledType. /// </summary> private IEnumerable <RawDependency> CreateTypeAndMethodDependencies([NotNull] RawUsingItem usingItem, [NotNull] ItemType usedItemType, [CanBeNull, ItemNotNull] string[] usedMarkers, [NotNull] TypeReference usedType, DotNetUsage usage, [CanBeNull] SequencePoint sequencePoint, [NotNull] string memberName, WorkingGraph readingGraph) { if (usedType is TypeSpecification) { // E.g. the reference type System.int&, which is used for out parameters. // or an arraytype?!? usedType = ((TypeSpecification)usedType).ElementType; } if (!(usedType is GenericInstanceType) && !(usedType is GenericParameter)) { // Currently, we do not look at generic type parameters; we would have to // untangle the usage of an actual (non-type-parameter) type's member // to get a useful Dependency_ for the user. RawUsedItem usedItem = CreateUsedItem(usedItemType, usedType, memberName, usedMarkers, readingGraph); yield return(new RawDependency(usingItem, usedItem, usage, sequencePoint, _readerGang.OfType <AbstractDotNetAssemblyDependencyReader>().FirstOrDefault(r => r.AssemblyName == usedItem.AssemblyName))); } var genericInstanceType = usedType as GenericInstanceType; if (genericInstanceType != null) { foreach (TypeReference genericArgument in genericInstanceType.GenericArguments) { foreach (var dependency_ in CreateTypeAndMethodDependencies(usingItem, DOTNETTYPE, GetMemberMarkers(Resolve(genericArgument), _typeDefinitionMarkers), genericArgument, usage: DotNetUsage._usesasgenericargument, sequencePoint: sequencePoint, memberName: genericArgument.Name, readingGraph: readingGraph)) { yield return(dependency_); } } } }
private LiteralNode(IConvertible value, TypeReference type, SequencePoint point) : base(point) { this.type = type; this.Value = new Literal(value); }
private SymbolDeclarationNode(VariableDefinition variable, bool isConst, ExpressionNode init, SequencePoint point) : base(point) { this.Variable = variable; this.initializer = init; this.IsConst = isConst; }
public static bool IsHidden(this SequencePoint sp) => sp.StartLine == 0xFEEFEE && sp.EndLine == 0xFEEFEE && sp.StartColumn == 0 && sp.EndColumn == 0;
private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor processor, Instruction instruction, SequencePoint sequencePoint) { if (!_result.Documents.TryGetValue(sequencePoint.Document.Url, out var document)) { document = new Document { Path = sequencePoint.Document.Url }; document.Index = _result.Documents.Count; _result.Documents.Add(document.Path, document); } for (int i = sequencePoint.StartLine; i <= sequencePoint.EndLine; i++) { if (!document.Lines.ContainsKey(i)) { document.Lines.Add(i, new Line { Number = i, Class = method.DeclaringType.FullName, Method = method.FullName }); } } string marker = $"L,{document.Index},{sequencePoint.StartLine},{sequencePoint.EndLine}"; var pathInstr = Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath); var markInstr = Instruction.Create(OpCodes.Ldstr, marker); var callInstr = Instruction.Create(OpCodes.Call, processor.Body.Method.Module.ImportReference(_markExecutedMethodLoader.Value)); processor.InsertBefore(instruction, callInstr); processor.InsertBefore(callInstr, markInstr); processor.InsertBefore(markInstr, pathInstr); return(pathInstr); }
void Proc(ProcedureSequence procs) { StatementSequence statements; string name; VariableSequence valArgs = new VariableSequence(); Variable resultArg = null; Expect(5); Token ptok = t; Expect(1); name = t.val; Expect(6); if (la.kind == 7 || la.kind == 8) { if (la.kind == 7) { Get(); Expect(1); Variable v = new Variable(t.val); v.IsValueArg = true; valArgs.AddVariable(v); SymbolTable.DefineArgument(t.val); if (la.kind == 12) { Args(valArgs, out resultArg); } } else { Get(); Expect(1); resultArg = new Variable(t.val); resultArg.IsResultArg = true; SymbolTable.DefineResultArgument(t.val); } } Expect(9); SequencePoint seq1 = new SequencePoint(ptok.line,ptok.col, t.line,t.col+t.val.Length); Expect(10); StmtSeq(out statements); Expect(4); SequencePoint seq2 = new SequencePoint(t.line, t.col, t.line, t.col+t.val.Length); Expect(11); if (procs.ContainsProcedure(name)) { errors.SemErr(ptok.line, ptok.col, "Procedure '" + name + "' is already declared"); } else { Procedure proc = new Procedure(name, valArgs, resultArg, statements); proc.AddSequencePoint(seq1); proc.AddSequencePoint(seq2); procs.AddProcedure(proc); } SymbolTable.Clear(); }