public virtual UnitOptionRow Serialize() { var row = new UnitOptionRow(); if (sourceScriptGuids.Count == 0) { // Important to set to null here, because the code relies on // null checks, not empty string checks. row.sourceScriptGuids = null; } else { row.sourceScriptGuids = string.Join(",", sourceScriptGuids.ToArray()); } row.optionType = Codebase.SerializeType(GetType()); row.unitType = Codebase.SerializeType(unitType); row.unit = unit.Serialize().json; row.category = category?.fullName; row.labelHuman = labelHuman; row.labelProgrammer = labelProgrammer; row.order = order; row.haystackHuman = haystackHuman; row.haystackProgrammer = haystackProgrammer; row.favoriteKey = favoriteKey; row.controlInputCount = controlInputCount; row.controlOutputCount = controlOutputCount; row.valueInputTypes = valueInputTypes.Select(Codebase.SerializeType).ToSeparatedString("|").NullIfEmpty(); row.valueOutputTypes = valueOutputTypes.Select(Codebase.SerializeType).ToSeparatedString("|").NullIfEmpty(); return(row); }
private static Codebase GetCodebase(params string[] projects) { var codebase = new Codebase(new ProjectFactory()); codebase.Discover(projects); return(codebase); }
public override UnitOptionRow Serialize() { var row = base.Serialize(); row.tag1 = Codebase.SerializeType(structType); return(row); }
private static void WriteProjects(IConsole console, Codebase codebase, IEnumerable <IProject> projects) { foreach (var project in projects) { var relativePath = Path.GetRelativePath(codebase.FullPath, project.FullPath); console.Out.WriteLine(relativePath); } }
protected override void UpdateTools(IList <ITool> tools) { tools.Add(modeTool); var tabTypes = ListPool <Type> .New(); try { foreach (var tabInLayout in PeekPlugin.Configuration.tabsInLayout) { if (!Codebase.TryDeserializeType(tabInLayout, out var tabType)) { continue; } if (PeekPlugin.Configuration.tabsBlacklist.Contains(tabType)) { continue; } if (!tabTypes.Contains(tabType)) { tabTypes.Add(tabType); } } foreach (var tabType in PeekPlugin.Configuration.tabsWhitelist) { if (tabType == null) { continue; } if (!tabTypes.Contains(tabType)) { tabTypes.Add(tabType); } } tabTypes.Sort(compareTabTypes); foreach (var tabType in tabTypes) { var tabTool = tabTools[tabType]; tools.Add(tabTool); } } finally { tabTypes.Free(); } }
static void Ncca_Is_Used_Properly(Codebase codebase, IScope scope, int maxInstructions) { var methods = codebase.Methods .Where(m => m.HasBody && m.Body.Instructions.Count > maxInstructions) .Where(m => m.Has<NoCodeCoverageAttribute>() || m.DeclaringType.Has<NoCodeCoverageAttribute>()); foreach (var method in methods) { scope.Error("Method is too complex to be marked with NCCA: {0}", method); } }
private static void CreateSolutionFilter(IConsole console, string[] projects, FileInfo solution, string destination) { var codebase = new Codebase(new ProjectFactory()); if (string.IsNullOrEmpty(destination)) { var solutionFilter = codebase.CreateSolutionFilter(solution, projects); console.Out.Write(solutionFilter); } else { codebase.CreateSolutionFilter(destination, solution, projects); } }
/// <summary> /// Ensures that classes marked with <see cref="ImmutableAttribute"/> have only /// readonly fields /// </summary> /// <param name="codebase">The codebase to run against.</param> /// <param name="scope">The scope to report to.</param> public static void Immutable_Types_Should_Be_Immutable(Codebase codebase, IScope scope) { var decorated = codebase.Types .Where(t => t.Has<ImmutableAttribute>()); var failing = decorated .Where(t => t.GetAllFields(codebase) .Count(f => !f.IsInitOnly && !f.IsStatic) > 0); foreach (var definition in failing) { scope.Error("Type should be immutable: {0}", definition); } }
public List <ICodebaseAlert> GenerateAlerts(Codebase codebase) { var alerts = new List <CodebaseAlert>(); foreach (var projectDirectory in codebase.ProjectDirectories) { if (projectDirectory.ProjectFiles.Count > 1) { var alert = new CodebaseAlert("MultipleProjectAlert", CodebaseAlertPriority.Warning, projectDirectory) .AddDetail("Multiple project files detected in directory"); } } return(alerts.ToList <ICodebaseAlert>()); }
private static void UpdateCodebase(IEnumerable <Type> typeSet = null) { if (typeSet == null) { typeSet = Codebase.settingsTypes; } else { typeSet = typeSet.Where(t => Codebase.settingsTypes.Contains(t)); } Codebase.UpdateSettings(); codebase = Codebase.Subset(typeSet, TypeFilter.Any.Configured(), MemberFilter.Any.Configured(), TypeFilter.Any.Configured(false)); codebase.Cache(); }
public IUnitOption ToOption() { using (ProfilingUtility.SampleBlock("Row to option")) { var optionType = Codebase.DeserializeType(this.optionType); IUnitOption option; option = (IUnitOption)Activator.CreateInstance(optionType); option.Deserialize(this); return(option); } }
public TabTool(Type windowType) { Ensure.That(nameof(windowType)).IsNotNull(windowType); this.windowType = windowType; tabKey = Codebase.SerializeType(windowType); try { FromTitleContent((GUIContent)UnityEditorDynamic.EditorWindow.GetLocalizedTitleContentFromType(windowType)); } catch { label = windowType.DisplayName(); icon = windowType.Icon()?[IconSize.Small]; tooltip = windowType.DisplayName(); } }
private static void BuildBoltUnitOptions() { #if (UNITY_BOLT_EXIST) DictionaryAsset projectSettings = AssetDatabase.LoadAssetAtPath(PathUtility.FromProject(LudiqCore.Paths.projectSettings), typeof(DictionaryAsset)) as DictionaryAsset; List <LooseAssemblyName> assemblyOptions = projectSettings.dictionary["assemblyOptions"] as List <LooseAssemblyName>; #else List <LooseAssemblyName> assemblyOptions = BoltCore.Configuration.assemblyOptions; #endif if (!assemblyOptions.Contains("FMODUnity")) { assemblyOptions.Add("FMODUnity"); } if (!assemblyOptions.Contains("FMODUnityResonance")) { assemblyOptions.Add("FMODUnityResonance"); } #if (UNITY_BOLT_EXIST) List <Type> typeOptions = projectSettings.dictionary["typeOptions"] as List <Type>; #else List <Type> typeOptions = BoltCore.Configuration.typeOptions; #endif Assembly fmodUnityAssembly = Assembly.Load("FMODUnity"); Assembly fmodUnityResonanceAssembly = Assembly.Load("FMODUnityResonance"); List <Type> allTypes = new List <Type>(GetTypesForNamespace(fmodUnityAssembly, "FMOD")); allTypes.AddRange(GetTypesForNamespace(fmodUnityAssembly, "FMOD.Studio")); foreach (Type type in allTypes) { if (!typeOptions.Contains(type)) { typeOptions.Add(type); } } Codebase.UpdateSettings(); #if (UNITY_BOLT_EXIST) UnitBase.Build(); #else UnitBase.Rebuild(); #endif }
public List <ICodebaseAlert> GenerateAlerts(Codebase codebase) { var alerts = new List <CodebaseAlert>(); foreach (var projectDirectory in codebase.ProjectDirectories) { foreach (var projectFile in projectDirectory.ProjectFiles) { foreach (var dllReference in projectFile.ReferencedDlls) { //We only care about NuGet packages here if (!dllReference.IsNuGetDllReference()) { continue; } //TODO - we need to make this configurable a bit somehow var expectedPackageName = dllReference.FileReferenced.NameWithoutExtension().Normalised(); if (projectDirectory.PackagesFile == null) { var alert = new CodebaseAlert("Missing Packages.config Alert", CodebaseAlertPriority.Bad, projectDirectory) .AddDetail("Packages.config file missing - expected for dll reference {0}", dllReference.HintPath); alerts.Add(alert); } else { var packageReference = projectDirectory.PackagesFile.PackageReferences.FirstOrDefault(p => p.PackageNameNormalised == expectedPackageName); if (packageReference == null) { var alert = new CodebaseAlert("Missing Packages.config Reference Alert", CodebaseAlertPriority.Bad, projectDirectory) .AddDetail("Reference to NuGet package {0} should be in packages.config for dll refernece {1}", expectedPackageName, dllReference.HintPath); alerts.Add(alert); } } } } } return(alerts.ToList <ICodebaseAlert>()); }
public virtual void Deserialize(UnitOptionRow row) { source = row; if (row.sourceScriptGuids != null) { sourceScriptGuids = row.sourceScriptGuids.Split(',').ToHashSet(); } unitType = Codebase.DeserializeType(row.unitType); category = row.category == null ? null : new UnitCategory(row.category); labelHuman = row.labelHuman; labelProgrammer = row.labelProgrammer; order = row.order; haystackHuman = row.haystackHuman; haystackProgrammer = row.haystackProgrammer; favoriteKey = row.favoriteKey; controlInputCount = row.controlInputCount; controlOutputCount = row.controlOutputCount; }
protected override void OnContentGUI() { GUILayout.BeginVertical(Styles.background, GUILayout.ExpandHeight(true)); LudiqGUI.FlexibleSpace(); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); var text = "Choose the assemblies in which you want to look for units.\n" + "By default, all project and Unity assemblies are included.\n" + "Unless you use a third-party plugin distributed as a DLL, you shouldn't need to change this."; GUILayout.Label(text, LudiqStyles.centeredLabel, GUILayout.MaxWidth(370)); LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.Space(10); var height = LudiqGUI.GetInspectorHeight(null, assemblyOptionsMetadata, Styles.optionsWidth, GUIContent.none); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); EditorGUI.BeginChangeCheck(); var position = GUILayoutUtility.GetRect(Styles.optionsWidth, height); LudiqGUI.Inspector(assemblyOptionsMetadata, position, GUIContent.none); if (EditorGUI.EndChangeCheck()) { assemblyOptionsMetadata.Save(); Codebase.UpdateSettings(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.Space(10); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); if (GUILayout.Button("Reset to Defaults", Styles.defaultsButton)) { assemblyOptionsMetadata.Reset(true); assemblyOptionsMetadata.Save(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.FlexibleSpace(); LudiqGUI.Space(10); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); if (GUILayout.Button(completeLabel, Styles.completeButton)) { Complete(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.FlexibleSpace(); LudiqGUI.EndVertical(); }
private static void AnalyzeWindowLayout() { var tabs = ListPool <EditorWindow> .New(); try { foreach (var window in Resources.FindObjectsOfTypeAll <EditorWindow>()) { // Skip invalid windows if (window == null) { continue; } // Abort the operation if any window is maximized, we don't want to save that layout if (window.maximized) { return; } // Skip windows that are invalid or not part of the layout dynamic dWindow = window.AsDynamic(); if (dWindow.m_Parent == null || dWindow.m_Parent.window == null || dWindow.m_Parent.window.m_DontSaveToLayout) { continue; } var parentWindowShowMode = (int)dWindow.m_Parent.window.showMode; // Skip windows not in the main window (4 in the ShowMode enum) if (parentWindowShowMode != 4) { continue; } tabs.Add(window); } // Sort tabs by screen position tabs.Sort(compareLayoutTab); // Store the tabs in the configuration // To minimize serialization operations, first check if changed from last time var config = PeekPlugin.Configuration; var tabsChanged = tabs.Count != config.tabsInLayout.Count; var positionsChanged = false; var dataChanged = false; // Store the fact that this tab is in the layout, which we'll need as fallback // in case the assembly reloads while the scene view is already maximized if (!tabsChanged) { for (int i = 0; i < tabs.Count; i++) { var tabKey = Codebase.SerializeType(tabs[i].GetType()); var configTabKey = config.tabsInLayout[i]; if (tabKey != configTabKey) { tabsChanged = true; break; } } } if (tabsChanged) { config.tabsInLayout.Clear(); foreach (var tab in tabs) { var tabKey = Codebase.SerializeType(tab.GetType()); config.tabsInLayout.Add(tabKey); } config.Save(nameof(PeekConfiguration.tabsInLayout)); } foreach (var tab in tabs) { var tabKey = Codebase.SerializeType(tab.GetType()); // Store the position if the user hasn't configured it already if (!config.tabsPositions.ContainsKey(tabKey)) { config.tabsPositions[tabKey] = tab.position; positionsChanged = true; } // Store the data if the user hasn't configured it already if (!config.tabsData.ContainsKey(tabKey)) { config.tabsData[tabKey] = EditorJsonUtility.ToJson(tab); dataChanged = true; } } if (positionsChanged) { config.Save(nameof(PeekConfiguration.tabsPositions)); } if (dataChanged) { config.Save(nameof(PeekConfiguration.tabsData)); } } catch (Exception ex) { Debug.LogWarning($"Failed to analyze window layout:\n{ex}"); } finally { tabs.Free(); } }
public List <ICodebaseAlert> GenerateAlerts(Codebase codebase) { var alerts = new List <CodebaseAlert>(); foreach (var projectDirectory in codebase.ProjectDirectories) { Dictionary <string, List <ProjectDirectory> > qaOnlyPackages = new Dictionary <string, List <ProjectDirectory> >(); Dictionary <string, List <ProjectDirectory> > versionMismatchPackages = new Dictionary <string, List <ProjectDirectory> >(); Dictionary <string, string> packagesUsingProdVersion = new Dictionary <string, string>(); Dictionary <string, string> notFoundPackages = new Dictionary <string, string>(); if (projectDirectory.PackagesFile == null) { continue; } foreach (var packageReference in projectDirectory.PackagesFile.PackageReferences) { if (packageReference.PackageName == null) { continue; } var packageNameNormalised = packageReference.PackageName.Normalised(); var packageNameAndVersionNormalised = packageNameNormalised + "_" + packageReference.Version; //Already checked as in prod - OK if (packagesUsingProdVersion.ContainsKey(packageNameAndVersionNormalised)) { continue; } if (notFoundPackages.ContainsKey(packageNameAndVersionNormalised)) { continue; } //We are not the first project directory to use this QA package List <ProjectDirectory> directoriesWithQaPackageAlready = new List <ProjectDirectory>(); if (qaOnlyPackages.TryGetValue(packageNameAndVersionNormalised, out directoriesWithQaPackageAlready)) { directoriesWithQaPackageAlready.Add(projectDirectory); continue; } //We are the first to check this package essentially NuGetPackage latestInProd; NuGetPackage latestInQa; codebase.NuGetSourceProduction.LatestVersionLookup.TryGetValue(packageNameNormalised, out latestInProd); codebase.NuGetSourceQa.LatestVersionLookup.TryGetValue(packageNameNormalised, out latestInQa); //Not in either feed! Better log this if (latestInProd == null && latestInQa == null) { notFoundPackages.Add(packageNameAndVersionNormalised, packageNameAndVersionNormalised); continue; } //If it is in prod - add to that index if (latestInProd != null && packageReference.Version <= latestInProd.Version) { if (!packagesUsingProdVersion.ContainsKey(packageNameAndVersionNormalised)) { packagesUsingProdVersion.Add(packageNameAndVersionNormalised, packageNameAndVersionNormalised); } continue; } directoriesWithQaPackageAlready.Add(projectDirectory); qaOnlyPackages.Add(packageNameAndVersionNormalised, directoriesWithQaPackageAlready); } foreach (var notFoundPackage in notFoundPackages.Keys.OrderBy(k => k)) { var alert = new CodebaseAlert("Phantom NuGet Package Reference Alert", CodebaseAlertPriority.Critical, null) .AddDetail("Package {0} is not found in either QA or Production Feeds", notFoundPackage); alerts.Add(alert); } foreach (var qaOnlyPackage in qaOnlyPackages.Keys.OrderBy(k => k)) { var alert = new CodebaseAlert("QA NuGet Package Reference Alert", CodebaseAlertPriority.Warning, null) .AddDetail("Package {0} is currently only found in QA feed", qaOnlyPackage); alerts.Add(alert); } foreach (var versionMismatchPackage in versionMismatchPackages.Keys.OrderBy(k => k)) { PackageVersion expectedVersion = null; var alert = new CodebaseAlert("NuGet Package Version Anomaly Alert", CodebaseAlertPriority.Critical, null) .AddDetail("Package {0} is referenced instead of the standard version {1}", versionMismatchPackage, expectedVersion.ToString()); var affectedProjects = versionMismatchPackages[versionMismatchPackage]; foreach (var project in affectedProjects) { alert.AddDetail(" - {0}", project.DisplayPath(codebase.RootSourceDirectory)); } alerts.Add(alert); } } return(alerts.ToList <ICodebaseAlert>()); }
protected override void OnContentGUI() { GUILayout.BeginVertical(Styles.background, GUILayout.ExpandHeight(true)); LudiqGUI.FlexibleSpace(); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); var text = "Choose the types you want to use for variables and units.\n" + "MonoBehaviour types are always included."; GUILayout.Label(text, LudiqStyles.centeredLabel, GUILayout.MaxWidth(370)); LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.Space(10); var height = LudiqGUI.GetInspectorHeight(null, typeOptionsMetadata, Styles.optionsWidth, GUIContent.none); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); EditorGUI.BeginChangeCheck(); var position = GUILayoutUtility.GetRect(Styles.optionsWidth, height); LudiqGUI.Inspector(typeOptionsMetadata, position, GUIContent.none); if (EditorGUI.EndChangeCheck()) { typeOptionsMetadata.Save(); Codebase.UpdateSettings(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.Space(10); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); if (GUILayout.Button("Reset to Defaults", Styles.defaultsButton)) { typeOptionsMetadata.Reset(true); typeOptionsMetadata.Save(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.FlexibleSpace(); LudiqGUI.Space(10); LudiqGUI.BeginHorizontal(); LudiqGUI.FlexibleSpace(); if (GUILayout.Button("Generate", Styles.completeButton)) { Complete(); } LudiqGUI.FlexibleSpace(); LudiqGUI.EndHorizontal(); LudiqGUI.FlexibleSpace(); LudiqGUI.EndVertical(); }
private Expression Expand(Expression expr) { if (expr == null) { return(null); } else if (expr is Addr) { var addr = (Addr)expr; var target = Expand(addr.Target); return(new Addr(target)); } else if (expr is Assign) { var ass = (Assign)expr; var prop = ass.InvokedProp(); if (prop != null) { return(Expand(prop)); } else { var rhs = Expand(ass.Rhs); var lhs = Expand(ass.Lhs); return(new Assign(lhs, rhs)); } } else if (expr is Operator) { var op = (Operator)expr; if (op.OperatorType.IsAssign()) { var prop = op.Children.AssertFirst().InvokedProp(); if (prop != null) { return(Expand(prop)); } else { // todo. implement this with the use of SafeExpandOpAssign var args = op.Args.Select(arg => Expand(arg)); return(Operator.Create(op.OperatorType, args)); } } else { var args = op.Args.Select(arg => Expand(arg)); return(Operator.Create(op.OperatorType, args)); } } else if (expr is Conditional) { var cond = (Conditional)expr; var test = Expand(cond.Test); var iftrue = Expand(cond.IfTrue); var iffalse = Expand(cond.IfFalse); return(new Conditional(test, iftrue, iffalse)); } else if (expr is Const) { // do nothing - nowhere to drill into return(expr); } else if (expr is Convert) { var cvt = (Convert)expr; var source = Expand(cvt.Source); return(new Convert(cvt.Type, source)); } else if (expr is Deref) { var deref = (Deref)expr; var target = Expand(deref.Target); return(new Deref(target)); } else if (expr is Fld) { var fld = (Fld)expr; var @this = Expand(fld.This); return(new Fld(fld.Field, @this)); } else if (expr is Prop) { // basic investigations var prop = (Prop)expr; var is_instance = prop.Property.IsInstance(); var parent = prop.Parent; var app = parent as Apply; var is_indexer = app != null && app.Callee == prop; if (is_indexer) { parent = parent.Parent; } // we have 5 different cases: // 1) foo.P; // 2) foo.P = bar; // 3) qux = (foo.P = bar); // 4) foo.P += bar; // 4') foo.P++; // 5) qux = (foo.P += bar); // 5') qux = (foo.P++); var ass = parent as Assign; var is_assigned = ass != null && (ass.Lhs == prop || ass.Lhs == app); var op = parent as Operator; var is_opassigned = op != null && op.OperatorType.IsAssign(); is_assigned |= is_opassigned; var is_rhs_reused = is_assigned && parent.Parent is Expression; if (!is_assigned) { var impl = prop.Property.GetGetMethod(true); var this_args = is_instance ? prop.This.MkArray() : Seq.Empty <Expression>(); var indexer_args = is_indexer ? app.Args : Seq.Empty <Expression>(); var args = Seq.Concat(this_args, indexer_args).ToReadOnly(); var style = prop.InvokedAsVirtual ? InvocationStyle.Virtual : InvocationStyle.NonVirtual; return(Expand(new Eval(new Apply(new Lambda(impl, style), args)))); } else { // abstract away the root // todo. implement this with the use of SafeExpandOpAssign var root = prop.This; if (is_opassigned && !root.IsLvalue()) { var opassroot = DeclareLocal("$opassroot", prop.This.Type()); Emit(new Assign(opassroot, prop.This)); root = opassroot; } // abstract away the RHS var rhs = null as Expression; if (ass != null) { rhs = ass.Rhs; } if (is_opassigned) { if (op.IsUnary()) { rhs = new Const(1); } else if (op.IsBinary()) { rhs = op.Children.AssertSecond().AssertCast <Expression>(); } else { throw AssertionHelper.Fail(); } } // abstract away the equivalence transform Func <Expression> equiv = () => { Func <Expression> equivGetter = () => { var impl = prop.Property.GetGetMethod(true); var this_args = is_instance ? root.MkArray() : Seq.Empty <Expression>(); var indexer_args = is_indexer ? app.Args : Seq.Empty <Expression>(); var args = Seq.Concat(this_args, indexer_args).ToReadOnly(); var style = prop.InvokedAsVirtual ? InvocationStyle.Virtual : InvocationStyle.NonVirtual; return(new Eval(new Apply(new Lambda(impl, style), args))); }; Func <Expression, Expression> equivSetter = assigned_value => { var impl = prop.Property.GetSetMethod(true); var this_args = is_instance ? root.MkArray() : Seq.Empty <Expression>(); var indexer_args = is_indexer ? app.Args : Seq.Empty <Expression>(); var args = Seq.Concat(this_args, indexer_args, assigned_value.MkArray()).ToReadOnly(); var style = prop.InvokedAsVirtual ? InvocationStyle.Virtual : InvocationStyle.NonVirtual; return(new Eval(new Apply(new Lambda(impl, style), args))); }; if (is_opassigned) { return(equivSetter(Operator.Create(op.OperatorType, equivGetter(), rhs))); } else { return(equivSetter(rhs)); } }; // final transform if (is_rhs_reused) { var cached_rhs = DeclareLocal("$opassrhs", rhs.Type()); Emit(new Assign(cached_rhs, rhs)); rhs = cached_rhs; Emit(equiv()); return(cached_rhs); } else { return(Expand(equiv())); } } } else if (expr is Ref) { var @ref = (Ref)expr; var env = Env.GetOrDefault(@ref.Sym); return(Expand(env) ?? @ref); } else if (expr is SizeOf) { // do nothing - nowhere to drill into return(expr); } else if (expr is TypeAs) { var typeAs = (TypeAs)expr; var target = Expand(typeAs.Target); return(new TypeAs(typeAs.Type, target)); } else if (expr is TypeIs) { var typeIs = (TypeIs)expr; var target = Expand(typeIs.Target); return(new TypeAs(typeIs.Type, target)); } else if (expr is Default) { // do nothing - nowhere to drill into return(expr); } else if (expr is CollectionInit) { var ci = (CollectionInit)expr; if (ci.Elements.IsEmpty()) { return(Expand(ci.Ctor)); } else { var ctor_coll = ci.InvokedMethod().AssertThat(mb => mb.IsConstructor()); var t_coll = ctor_coll.DeclaringType; var l_coll = DeclareLocal("$", t_coll); Emit(new Assign(l_coll, ci.Ctor)); ci.Elements.ForEach((el, i) => { if (t_coll.IsArray) { (t_coll.GetArrayRank() == 1).AssertTrue(); var m_set = t_coll.ArraySetter().AssertNotNull(); Emit(new Eval(new Apply(new Lambda(m_set), l_coll, new Const(i), el))); } else { var m_add = t_coll.GetMethods(BF.All).AssertSingle(m => m.Name == "Add"); Emit(new Eval(new Apply(new Lambda(m_add), l_coll, el))); } }); return(l_coll); } } else if (expr is ObjectInit) { var oi = (ObjectInit)expr; if (oi.Members.IsEmpty()) { return(Expand(oi.Ctor)); } else { var ctor_obj = oi.InvokedMethod().AssertThat(mb => mb.IsConstructor()); var t_obj = ctor_obj.DeclaringType; var l_obj = DeclareLocal("$", t_obj); Emit(new Assign(l_obj, oi.Ctor)); foreach (var mi in oi.Members) { if (mi is FieldInfo) { var fi = mi as FieldInfo; Emit(new Assign(new Fld(fi, l_obj), oi.MemberInits[mi])); } else if (mi is PropertyInfo) { var pi = mi as PropertyInfo; // todo. what about virtuality?! Emit(new Assign(new Prop(pi, l_obj), oi.MemberInits[mi])); } else { throw AssertionHelper.Fail(); } } return(l_obj); } } else if (expr is Eval) { var eval = (Eval)expr; var lam = eval.InvokedLambda(); var m = eval.InvokedMethod(); var child_ctx = Ctx.SpinOff(m); var status = Codebase.Classify(m); (status != MethodStatus.MustNotBeExecutedOnDevice).AssertTrue(); var is_redirected = status == MethodStatus.IsRedirected; if (is_redirected) { var redir = Codebase.Redirect(eval); if (redir == null) { return(null); } else { var m_redir = redir.InvokedMethod(); if (m_redir.HasBody()) { var raw_body = m_redir.ParseBody().Where(op => !(op is CilNop)).ToReadOnly(); if (raw_body.Count() == 2) { var first = raw_body.First() as CilNew; var second = raw_body.Second() as CilThrow; var tni_ctor = typeof(NotImplementedException).GetConstructor(Type.EmptyTypes); if (first != null && first.Ctor == tni_ctor && second != null) { throw AssertionHelper.Fail(); } } } return(Expand(redir)); } } else { var needsExpansion = status == MethodStatus.CanBeExecutedOnDevice; var doesntNeedExpansion = status == MethodStatus.HasSpecialSemantics; (needsExpansion ^ doesntNeedExpansion).AssertTrue(); if (needsExpansion) { // todo. think about what we can do here (lam.InvocationStyle == InvocationStyle.Virtual).AssertFalse(); m.DeclaringType.IsInterface.AssertFalse(); } var md = m.Decompile(); needsExpansion.AssertImplies(m.HasBody()); var p_ret = Seq.Empty <ParameterInfo>(); var mi = m as MethodInfo; if (mi != null) { p_ret = mi.ReturnParameter.MkArray(); } m.GetParameters().Concat(p_ret).ForEach(pi => pi.IsOptional.AssertFalse()); var args = eval.InvocationArgs(); var args_include_this = !lam.InvokedAsCtor && m.IsInstance(); var @params = m.GetParameters().AsEnumerable(); var p_fakethis = null as ParameterInfo; if (args_include_this) { @params = p_fakethis.Concat(@params).ToReadOnly(); } var l_args = @params.Zip(args, (p, actual_arg) => { var p_sig = p == null ? md.Sig.Params.First() : md.Sig.Params.AssertSingle(p1 => p1.Metadata == p); var p_type = p_sig.Type; Func <Expression, Expression> expand_arg = null; expand_arg = arg => { Func <Expression, String, Expression> default_expand1 = (e, postfix) => { var prefix = (m.IsConstructor() ? m.DeclaringType.Name : m.Name).ToLower(); var name = p_sig.Name + (postfix == null ? null : ("_" + postfix.ToLower())); var full_name = String.Format("${0}_{1}", prefix, name); var l_stub = DeclareLocal(full_name, p_type); Emit(new Assign(l_stub, Expand(arg))); return(l_stub); }; Func <Expression, Expression> default_expand = e => default_expand1(e, null); if (doesntNeedExpansion) { if (p_type.IsArray && p.IsVarargs()) { var ctor = arg.InvokedCtor(); if (ctor != null && ctor.DeclaringType.IsArray) { var arg_eval = arg as Eval; if (arg_eval != null) { var rank = ctor.DeclaringType.GetArrayRank(); if (rank == 1) { var sole_arg = arg.InvocationArgs().AssertSingle() as Const; if (sole_arg != null && sole_arg.Value is int && (int)sole_arg.Value == 0) { return(arg); } } } var arg_ci = arg as CollectionInit; if (arg_ci != null) { p_type.IsArray().AssertTrue(); (p_type.GetArrayRank() == 1).AssertTrue(); try { p_type = p_type.GetElementType(); var els = arg_ci.Elements.Select(expand_arg).ToReadOnly(); return(new CollectionInit(arg_ci.Ctor, els)); } finally { p_type = p_type.MakeArrayType(); } } } } var needs_expansion = arg.Family().Any(c => c is Eval || c is Apply || c is Lambda || c is Prop || c is CollectionInit || c is ObjectInit); if (!needs_expansion) { return(arg); } else { // todo. the stuff below works incorrectly in general case // since it might disrupt evaluation order of parameters // // however for now I trade off introducing a potential bug // for the ease of debugging and looking at traces var old_stmtc = Stmts.Count(); var expanded = default_expand(arg).AssertCast <Ref>(); var new_stmtc = Stmts.Count(); (new_stmtc > old_stmtc).AssertTrue(); // todo. fix possible semantic disruption at the next line if (new_stmtc - old_stmtc > 1) { return(expanded); } else { var ass = Stmts.Last().AssertCast <Assign>(); ass.Lhs.Equiv(expanded).AssertTrue(); Stmts.RemoveLast(); RemoveLocal(expanded); return(ass.Rhs); } } } else { var p_reads = md.Body.Family().OfType <Ref>().Where(r => r.Sym == p_sig.Sym).ToReadOnly(); var p_asses = md.Body.Family().OfType <Assign>().Select(ass => { var r_lhs = ass.Lhs as Ref; var is_write = r_lhs != null && r_lhs.Sym == p_sig.Sym; return(is_write ? ass : null); }).Where(ass => ass != null).ToReadOnly(); var p_byref = md.Body.Family().OfType <Apply>().Select(app => { var passes_byref = app.ArgsInfo.Zip((e, pi) => { var e_ref = e as Ref; var is_read = e_ref != null && e_ref.Sym == p_sig.Sym; var is_byref = pi.Type.IsByRef; return(is_read && is_byref); }).Any(); return(passes_byref ? app : null); }).Where(app => app != null).ToReadOnly(); var p_writes = Seq.Concat(p_asses.Cast <Expression>(), p_byref.Cast <Expression>()).ToReadOnly(); var p_usages = Seq.Concat(p_reads.Cast <Expression>(), p_writes.Cast <Expression>()).ToReadOnly(); // todo. below we might disrupt evaluation order // by totally inlining an arg expression if it has a single usage // strictly speaking, before doing that // we need perform additional checks that eval-order is preserved // // note. this semi-correct solution is introduced // solely for the convenience of the back-end // and for the convenience of reading the resulting traces var passed_by_ref = p == null || p.PassedByRef(); if (passed_by_ref) { var @ref = arg as Ref; if (@ref != null) { return(arg); } var fld = arg as Fld; if (fld != null) { fld.Field.IsInstance().AssertTrue(); // todo. fix possible semantic disruption at the next line if (p_usages.Count() <= 1) { return(arg); } else { var root = fld.This; var is_atom = root is Ref || root is Const; if (is_atom) { return(arg); } else { var root_expanded = default_expand1(root, "root"); return(new Fld(fld.Field, root_expanded)); } } } var eval1 = arg as Eval; if (eval1 != null) { var m1 = eval1.InvokedMethod(); m1.IsArrayGetter().AssertTrue(); var args1 = eval1.InvocationArgs(); var lam1 = eval1.InvokedLambda(); var r_ee = eval1.Expand(Ctx.SpinOff(m1)); r_ee.Stmts.ForEach(Stmts.Add); var ee = r_ee.Result.AssertCast <Eval>().AssertNotNull(); // todo. fix possible semantic disruption at the next line if (p_usages.Count() <= 1) { return(ee); } else { var root = ee.Callee.Callee; Func <Expression, bool> is_atom = e => e is Ref || e is Const; if (is_atom(root) && ee.Callee.Args.All(is_atom)) { return(ee); } else { var root_expanded = default_expand1(root, "root"); return(new Eval(new Apply(new Lambda(m1, lam1.InvocationStyle), root_expanded.Concat(args1)))); } } } // arg isn't an lvalue, so it can't be passed by reference throw AssertionHelper.Fail(); } else { if (p_writes.IsEmpty()) { // todo. fix possible semantic disruption at the next line if (p_usages.Count() <= 1) { return(arg); } else { var is_atom = arg is Ref || arg is Const; if (is_atom) { var is_value_type = p_type.IsValueType; var is_primitive = p_type.IsPrimitive; var needs_copying = is_value_type && !is_primitive; return(needs_copying ? default_expand(arg) : arg); } else { return(default_expand(arg)); } } } else { return(default_expand(arg)); } } } }; var preprocessed_arg = actual_arg.Transform((Ref @ref) => { var env = Env.GetOrDefault(@ref.Sym); return(env ?? @ref); }).AssertCast <Expression>(); var expanded_arg = expand_arg(preprocessed_arg); expanded_arg = expanded_arg.Transform((Ref @ref) => { var env = Env.GetOrDefault(@ref.Sym); return(env ?? @ref); }).AssertCast <Expression>(); if (needsExpansion) { child_ctx.Env.Add(p_sig.Sym, expanded_arg); } return(expanded_arg); }).ToReadOnly(); if (needsExpansion) { var env_locals = lam.Body.LocalsRecursive().ToDictionary(l => l as Sym, l => { var frames = Stack.Reverse().Skip(1).Concat(m); var qualifier = frames.Select(sf => sf.Name.ToLower()).StringJoin("_"); var full_name = String.Format("${0}_{1}", qualifier, l.Name); return(DeclareLocal(full_name, l.Type) as Expression); }).ToReadOnly(); child_ctx.Env.AddElements(env_locals); Action <Block> import_locals = blk => { foreach (var local in blk.Locals.ToArray()) { var env_ref = env_locals.GetOrDefault(local) as Ref; var env = env_ref == null ? null : (Local)env_ref.Sym; if (env != null) { blk.Locals.Remove(local); blk.Locals.Add(env); } else { Scope.Locals.Add(local); } } // todo. also import locals from embedded blocks // here we need to take inlined stuff into account }; if (lam.InvokedAsCtor) { var l_this = DeclareLocal(String.Format("${0}_this", m.DeclaringType.Name.ToLower()), m.DeclaringType); child_ctx.Env.Add(lam.Sig.Syms[0], l_this); var malloc = typeof(Ctm).GetMethod("Malloc", new [] { typeof(Type) }).AssertNotNull(); var malloc_type = new Const(m.DeclaringType); Emit(new Assign(l_this, new Eval(new Apply(new Lambda(malloc), malloc_type)))); var body = lam.Body.Expand(child_ctx); import_locals(body); if (body.IsEmpty()) { var last_stmt = Stmts.Last() as Assign; var last_invoked = last_stmt == null ? null : last_stmt.Rhs.InvokedMethod(); (last_invoked == malloc).AssertTrue(); RemoveLocal(l_this); Stmts.RemoveLast(); return(last_stmt.Rhs); } else { body.ForEach(Stmts.Add); return(l_this); } } else if (m.Ret() == typeof(void)) { var body = lam.Body.Expand(child_ctx).AssertNotEmpty(); import_locals(body); if (body.IsNotEmpty()) { body.ForEach(Stmts.Add); } return(null); } else { (m.Ret().IsByRef || m.Ret().IsPointer).AssertFalse(); var name = String.Format("${0}_ret", m.Name.ToLower()); var l_ret = DeclareLocal(name, m.Ret()); child_ctx.Ret = l_ret; var body = lam.Body.Expand(child_ctx).AssertNotEmpty(); import_locals(body); var body_last = body.LastOrDefault(); if (body_last is Label) { body.ForEach(Stmts.Add); return(l_ret); } else { var ass = body.AssertLast().AssertCast <Assign>(); ass.Lhs.Equiv(l_ret).AssertTrue(); RemoveLocal(l_ret); body.SkipLast(1).ForEach(Stmts.Add); return(ass.Rhs); } } } else { return(new Eval(new Apply(lam, l_args.Cast <Expression>()))); } } } else { var app = expr as Apply; var app_prop = app == null ? null : app.Callee as Prop; if (app_prop != null) { return(Expand(app_prop)); } // todo. also support indirect calls and partial applications // i.e. process cases when Apply/Lambda nodes ain't wrapped in an Eval throw AssertionHelper.Fail(); } }
public override void Deserialize(UnitOptionRow row) { base.Deserialize(row); structType = Codebase.DeserializeType(row.tag1); }
private void Load(string path = null) { if (string.IsNullOrEmpty(path)) { var dlg = new OpenFileDialog { Filter = "All Files|*.*", CheckFileExists = true, Multiselect = false, Title = "Please choose UMDH delta file" }; if (dlg.ShowDialog().Value) { path = dlg.FileName; } else { return; } } try { var loadingWindow = new ProgressWindow(); loadingWindow.Title = "Loading - " + path; bool continueWithLoading = true; loadingWindow.Closed += (s, e) => { continueWithLoading = false; }; Codebase codebase = null; Task.Factory.StartNew(() => { try { codebase = UMDHParser.Parse(path, (progress) => { Dispatcher.BeginInvoke(new Action(() => { loadingWindow.progressBar.Value = progress; })); }); codebase.Normalize(); Dispatcher.BeginInvoke(new Action(() => { if (continueWithLoading) { codebase.Owner = this; Codebase = codebase; Title = "UMDH Visualize - " + path; SelectedTab = tabRawView; } loadingWindow.Close(); })); } catch (Exception ex) { MessageBox.Show(string.Format("Cannot parse file \"{0}\":\r\n{1}", path, ex)); } }); loadingWindow.ShowDialog(); } catch (Exception ex) { MessageBox.Show(string.Format("Cannot parse file \"{0}\":\r\n{1}", path, ex)); } }