static void Demo5(CodeCompileUnit ccu) { // once again, we need one of these var res = new CodeDomResolver(); res.CompileUnits.Add(ccu); res.Refresh(); // we happen to know Program is the 1st type in the 2nd namespace* var prg = ccu.Namespaces[1].Types[0]; // we need the scope where we're at var scope = res.GetScope(prg); // because our binder attaches to it var binder = new CodeDomBinder(scope); // now get all the methods with the specified name and flags var members = binder.GetMethodGroup(prg, "TestOverload", BindingFlags.Public | BindingFlags.Static); Console.WriteLine("There are {0} TestOverload method overloads.", members.Length); // try selecting one that takes a single string parameter var argTypes1 = new CodeTypeReference[] { new CodeTypeReference(typeof(string)) }; var m = binder.SelectMethod(BindingFlags.Public | BindingFlags.Static, members, argTypes1, null); if (null != m) { Console.WriteLine("Select TestOverload(string) returned:"); _DumpMethod(m); } else { Console.WriteLine("Unable to bind to method"); } // try selecting one that takes a single it parameter var argTypes2 = new CodeTypeReference[] { new CodeTypeReference(typeof(int)) }; m = binder.SelectMethod(BindingFlags.Public | BindingFlags.Static, members, argTypes2, null); if (null != m) { Console.WriteLine("Select TestOverload(int) returned:"); _DumpMethod(m); } else { Console.WriteLine("Unable to bind to method"); } Console.WriteLine("Press any key..."); Console.ReadKey(); Console.Clear(); }
static void RunBinding() { // we'll need the resolver in a bit var res = new CodeDomResolver(); // read the binding sample into the compile unit CodeCompileUnit ccu; using (var stm = File.OpenRead(@"..\..\Binding.cs")) ccu = SlangParser.ReadCompileUnitFrom(stm); // add the compile unit to the resolver res.CompileUnits.Add(ccu); // prepare the resolver res.Refresh(); // get the first class available var tdecl = ccu.Namespaces[1].Types[0]; // capture the scope at the typedecl level var scope = res.GetScope(tdecl); // create a new binder with that scope var binder = new CodeDomBinder(scope); // get the method group for Test(...) var methodGroup = binder.GetMethodGroup(tdecl, "Test", BindingFlags.Public | BindingFlags.Instance); // select the method that can take a string value var m = binder.SelectMethod(BindingFlags.Public, methodGroup, new CodeTypeReference[] { new CodeTypeReference(typeof(string)) }, null); Console.WriteLine(CU.ToString((CodeMemberMethod)m)); // select the method that can take a short value // (closest match accepts int) m = binder.SelectMethod(BindingFlags.Public, methodGroup, new CodeTypeReference[] { new CodeTypeReference(typeof(short)) }, null); Console.WriteLine(CU.ToString((CodeMemberMethod)m)); }
static void _Patch(CodeFieldReferenceExpression fr, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != fr) { // this probably means part of our field has been resolved, or at the very least // it does not come from a rooted var ref. if (!fr.TargetObject.UserData.Contains("slang:unresolved")) { var scope = resolver.GetScope(fr); var binder = new CodeDomBinder(scope); var t = resolver.GetTypeOfExpression(fr.TargetObject, scope); if (null != t && CodeDomResolver.IsNullOrVoidType(t) && fr.TargetObject is CodeVariableReferenceExpression) { return; // can't patch this field yet - it's part of a var reference that hasn't been filled in } var isStatic = false; var tre = fr.TargetObject as CodeTypeReferenceExpression; if (null != tre) { isStatic = true; } var tt = resolver.TryResolveType(isStatic ? tre.Type : t, scope, true); if (null == tt) { throw new InvalidOperationException(_AppendLineInfo(string.Format("The type {0} could not be resolved", t.BaseType), t)); } var td = tt as CodeTypeDeclaration; // TODO: This code could be a lot faster if we added some functionality to the binder // we're just checking to see if the method, property or field exists var m = binder.GetField(tt, fr.FieldName, _BindFlags); if (null != m) { fr.UserData.Remove("slang:unresolved"); return; } m = binder.GetEvent(tt, fr.FieldName, _BindFlags); if (null != m) { var er = new CodeEventReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, er); return; } var ml = binder.GetMethodGroup(tt, fr.FieldName, _BindFlags); if (0 < ml.Length) { var mr = new CodeMethodReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, mr); return; } ml = binder.GetPropertyGroup(tt, fr.FieldName, _BindFlags); if (0 < ml.Length) { var pr = new CodePropertyReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, pr); return; } throw new InvalidProgramException(_AppendLineInfo(string.Format("Cannot deterimine the target reference {0}", fr.FieldName), fr)); } // TODO: This used to be first but I moved it here. // This shouldn't be done first because it's resolving types before fields and // that is a no no. I still need to make sure it doesn't break things var path = _GetUnresRootPathOfExpression(fr); if (null != path) { // now we have something to work with. var scope = resolver.GetScope(fr); var sa = path.Split('.'); if (1 == sa.Length) { System.Diagnostics.Debugger.Break(); throw new NotImplementedException(); } else { object t = null; string tn = null; CodeExpression tf = fr; CodeExpression ptf = null; CodeTypeReference ctr = null; for (var i = sa.Length - 1; i >= 1; --i) { tn = string.Join(".", sa, 0, i); ptf = tf; tf = _GetTargetOfExpression(tf); ctr = new CodeTypeReference(tn); t = resolver.TryResolveType(ctr, scope); if (null != t) { break; } } if (null != t) { var tt = t as Type; if (null != tt) { ctr = new CodeTypeReference(tt); } else { ctr = resolver.GetQualifiedType(ctr, scope); } // we found a type reference _SetTargetOfExpression(ptf, new CodeTypeReferenceExpression(ctr)); return; //args.Cancel = true; } } } } }
static void _Patch(CodeMemberMethod meth, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != meth) { // TODO: make sure the member is actually public if (null == meth.PrivateImplementationType) { var scope = resolver.GetScope(meth); var td = scope.DeclaringType; var binder = new CodeDomBinder(scope); for (int ic = td.BaseTypes.Count, i = 0; i < ic; ++i) { var ctr = td.BaseTypes[i]; var t = resolver.TryResolveType(ctr, scope); if (null != t) { var ma = binder.GetMethodGroup(t, meth.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); if (0 < ma.Length) { var isIface = false; var ttd = t as CodeTypeDeclaration; if (null != ttd) { isIface = ttd.IsInterface; } else { var rrt = t as Type; isIface = rrt.IsInterface; } if (isIface) { var m = binder.SelectMethod(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, ma, _GetParameterTypes(meth.Parameters), null); if (null != m) { meth.ImplementationTypes.Add(ctr); } } } } } } meth.UserData.Remove("slang:unresolved"); if ("Main" == meth.Name && (meth.Attributes & MemberAttributes.ScopeMask) == MemberAttributes.Static) { if (0 == meth.Parameters.Count && null == meth.ReturnType || "System.Void" == meth.ReturnType.BaseType) { var epm = new CodeEntryPointMethod(); epm.Attributes = meth.Attributes; epm.LinePragma = meth.LinePragma; epm.StartDirectives.AddRange(meth.StartDirectives); epm.EndDirectives.AddRange(meth.EndDirectives); epm.Comments.AddRange(meth.Comments); epm.CustomAttributes.AddRange(meth.CustomAttributes); epm.ReturnTypeCustomAttributes.AddRange(meth.ReturnTypeCustomAttributes); epm.TypeParameters.AddRange(meth.TypeParameters); epm.PrivateImplementationType = meth.PrivateImplementationType; epm.ImplementationTypes.AddRange(meth.ImplementationTypes); epm.Name = meth.Name; epm.Statements.AddRange(meth.Statements); CodeDomVisitor.ReplaceTarget(ctx, epm); } } //return; } }