/// <summary> /// Creates a <see cref="CdmTraitReference"/> based on a <see cref="CdmTraitDefinition"/> and adds it to the collection. /// </summary> /// <param name="traitDefinition">The trait definition used to create the trait reference.</param> /// <param name="simpleRef">Used to set trait.SimpleNamedReference in the constructor.</param> /// <returns>The created trait reference that was added to the collection.</returns> public CdmTraitReference Add(CdmTraitDefinition traitDefinition, bool simpleRef = false) { this.ClearCache(); var traitReference = new CdmTraitReference(this.Ctx, traitDefinition, simpleRef, false); return(base.Add(traitReference)); }
/// <inheritdoc /> public override CdmObject Copy(ResolveOptions resOpt = null, CdmObject host = null) { if (resOpt == null) { resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives); } CdmTraitDefinition copy; if (host == null) { copy = new CdmTraitDefinition(this.Ctx, this.TraitName, null); } else { copy = host as CdmTraitDefinition; copy.Ctx = this.Ctx; copy.TraitName = this.TraitName; } copy.ExtendsTrait = (CdmTraitReference)this.ExtendsTrait?.Copy(resOpt); copy.AllParameters = null; copy.Elevated = this.Elevated; copy.Ugly = this.Ugly; copy.AssociatedProperties = this.AssociatedProperties; this.CopyDef(resOpt, copy); return(copy); }
/// <summary> /// Verifies if the trait argument data type matches what is specified on the trait definition. /// </summary> /// <param name="objects"></param> /// <param name="resOpt"></param> internal void ResolveTraitArguments(ResolveOptions resOpt) { ResolveContext ctx = this.Ctx as ResolveContext; foreach (var obj in this.InternalObjects) { if (obj is CdmTraitReference traitRef) { CdmTraitDefinition traitDef = traitRef.FetchObjectDefinition <CdmTraitDefinition>(resOpt); if (traitDef == null) { continue; } for (int argumentIndex = 0; argumentIndex < traitRef.Arguments.Count; ++argumentIndex) { CdmArgumentDefinition argument = traitRef.Arguments[argumentIndex]; try { ctx.RelativePath = argument.DeclaredPath; ParameterCollection paramCollection = traitDef.FetchAllParameters(resOpt); CdmParameterDefinition paramFound = paramCollection.ResolveParameter(argumentIndex, argument.Name); argument.ResolvedParameter = paramFound; // if parameter type is entity, then the value should be an entity or ref to one // same is true of 'dataType' dataType dynamic argumentValue = paramFound.ConstTypeCheck(resOpt, this, argument.Value); if (argumentValue != null) { argument.Value = argumentValue; } } catch (Exception e) { Logger.Error(ctx, Tag, nameof(ResolveTraitArguments), this.AtCorpusPath, CdmLogCode.ErrTraitResolutionFailure, traitDef.GetName(), e.ToString()); } } traitRef.ResolvedArguments = true; } } }
public override CdmObject Copy(ResolveOptions resOpt = null) { if (resOpt == null) { resOpt = new ResolveOptions(this); } CdmTraitDefinition copy = new CdmTraitDefinition(this.Ctx, this.TraitName, null) { ExtendsTrait = (CdmTraitReference)this.ExtendsTrait?.Copy(resOpt), AllParameters = null, Elevated = this.Elevated, Ugly = this.Ugly, AssociatedProperties = this.AssociatedProperties }; this.CopyDef(resOpt, copy); return(copy); }
internal override ResolvedTraitSet FetchResolvedTraits(ResolveOptions resOpt = null) { if (resOpt == null) { resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives); } const string kind = "rtsb"; ResolveContext ctx = this.Ctx as ResolveContext; // this may happen 0, 1 or 2 times. so make it fast CdmTraitDefinition baseTrait = null; ResolvedTraitSet baseRts = null; List <dynamic> baseValues = null; System.Action GetBaseInfo = () => { if (this.ExtendsTrait != null) { baseTrait = this.ExtendsTrait.FetchObjectDefinition <CdmTraitDefinition>(resOpt); if (baseTrait != null) { baseRts = this.ExtendsTrait.FetchResolvedTraits(resOpt); if (baseRts?.Size == 1) { ParameterValueSet basePv = baseRts.Get(baseTrait)?.ParameterValues; if (basePv != null) { baseValues = basePv.Values; } } } } }; // see if one is already cached // if this trait has parameters, then the base trait found through the reference might be a different reference // because trait references are unique per argument value set. so use the base as a part of the cache tag // since it is expensive to figure out the extra tag, cache that too! if (this.BaseIsKnownToHaveParameters == null) { GetBaseInfo(); // is a cache tag needed? then make one this.BaseIsKnownToHaveParameters = false; if (baseValues?.Count > 0) { this.BaseIsKnownToHaveParameters = true; } } string cacheTagExtra = ""; if (this.BaseIsKnownToHaveParameters == true) { cacheTagExtra = this.ExtendsTrait.Id.ToString(); } string cacheTag = ctx.Corpus.CreateDefinitionCacheTag(resOpt, this, kind, cacheTagExtra); dynamic rtsResultDynamic = null; if (cacheTag != null) { ctx.Cache.TryGetValue(cacheTag, out rtsResultDynamic); } ResolvedTraitSet rtsResult = rtsResultDynamic as ResolvedTraitSet; // store the previous reference symbol set, we will need to add it with // children found from the constructResolvedTraits call SymbolSet currSymbolRefSet = resOpt.SymbolRefSet; if (currSymbolRefSet == null) { currSymbolRefSet = new SymbolSet(); } resOpt.SymbolRefSet = new SymbolSet(); // if not, then make one and save it if (rtsResult == null) { GetBaseInfo(); if (baseTrait != null) { // get the resolution of the base class and use the values as a starting point for this trait's values if (!this.HasSetFlags) { // inherit these flags if (this.Elevated == null) { this.Elevated = baseTrait.Elevated; } if (this.Ugly == null) { this.Ugly = baseTrait.Ugly; } if (this.AssociatedProperties == null) { this.AssociatedProperties = baseTrait.AssociatedProperties; } } } this.HasSetFlags = true; ParameterCollection pc = this.FetchAllParameters(resOpt); List <dynamic> av = new List <dynamic>(); List <bool> wasSet = new List <bool>(); this.ThisIsKnownToHaveParameters = pc.Sequence.Count > 0; for (int i = 0; i < pc.Sequence.Count; i++) { // either use the default value or (higher precidence) the value taken from the base reference dynamic value = (pc.Sequence[i] as CdmParameterDefinition).DefaultValue; dynamic baseValue = null; if (baseValues != null && i < baseValues.Count) { baseValue = baseValues[i]; if (baseValue != null) { value = baseValue; } } av.Add(value); wasSet.Add(false); } // save it ResolvedTrait resTrait = new ResolvedTrait(this, pc, av, wasSet); rtsResult = new ResolvedTraitSet(resOpt); rtsResult.Merge(resTrait, false); // register set of possible symbols ctx.Corpus.RegisterDefinitionReferenceSymbols(this.FetchObjectDefinition <CdmObjectDefinitionBase>(resOpt), kind, resOpt.SymbolRefSet); // get the new cache tag now that we have the list of docs cacheTag = ctx.Corpus.CreateDefinitionCacheTag(resOpt, this, kind, cacheTagExtra); if (!string.IsNullOrWhiteSpace(cacheTag)) { ctx.Cache[cacheTag] = rtsResult; } } else { // cache found // get the SymbolSet for this cached object string key = CdmCorpusDefinition.CreateCacheKeyFromObject(this, kind); ((CdmCorpusDefinition)ctx.Corpus).DefinitionReferenceSymbols.TryGetValue(key, out SymbolSet tempSymbolRefSet); resOpt.SymbolRefSet = tempSymbolRefSet; } // merge child document set with current currSymbolRefSet.Merge(resOpt.SymbolRefSet); resOpt.SymbolRefSet = currSymbolRefSet; return(rtsResult); }
/// <summary> /// Removes the <see cref="CdmTraitReference"/> that has the same name as <see cref="CdmTraitDefinition"/>. /// If there are multiple matches, removes the first trait that is from a property. If there aren't any from properties and "onlyFromProperty" is false, removes the last trait that is not from a property. /// </summary> /// <param name="traitDefToRemove"><see cref="CdmTraitDefinition"/> whose reference to remove from the collection.</param> /// <param name="onlyFromProperty">Whether the function should only be applied for traits that originate from properties.</param> /// <returns>Whether the operation completed successfuly.</returns> public bool Remove(CdmTraitDefinition traitDefToRemove, bool onlyFromProperty = false) { var traitName = traitDefToRemove.TraitName; return(this.Remove(traitName, onlyFromProperty)); }
/// <summary> /// Retrieves the index of a trait reference with the same name as the trait definition provided. /// If there are multiple matches, returns the index of the first trait that is from a property. If there aren't any from properties and "onlyFromProperty" is false, returns the index of the last trait that is not from a property. /// </summary> /// <param name="traitDefinition">The trait definition associated with the trait reference we want to retrieve the index of.</param> /// <param name="onlyFromProperty">Whether the function should only be applied for traits that originate from properties.</param> /// <returns>The index of the trait reference or -1 if no such trait exists in the collection.</returns> public int IndexOf(CdmTraitDefinition traitDefinition, bool onlyFromProperty = false) { var traitName = traitDefinition.TraitName; return(IndexOf(traitName, onlyFromProperty)); }
internal override ResolvedTraitSet FetchResolvedTraits(ResolveOptions resOpt = null) { if (resOpt == null) { resOpt = new ResolveOptions(this); } const string kind = "rtsb"; ResolveContext ctx = this.Ctx as ResolveContext; // get referenced trait CdmTraitDefinition trait = this.FetchObjectDefinition <CdmTraitDefinition>(resOpt) as CdmTraitDefinition; ResolvedTraitSet rtsTrait = null; if (trait == null) { return(((CdmCorpusDefinition)ctx.Corpus).CreateEmptyResolvedTraitSet(resOpt)); } // see if one is already cached // cache by name unless there are parameter if (trait.ThisIsKnownToHaveParameters == null) { // never been resolved, it will happen soon, so why not now? rtsTrait = trait.FetchResolvedTraits(resOpt); } bool cacheByName = true; if (trait.ThisIsKnownToHaveParameters != null) { cacheByName = !((bool)trait.ThisIsKnownToHaveParameters); } string cacheTag = ((CdmCorpusDefinition)ctx.Corpus).CreateDefinitionCacheTag(resOpt, this, kind, "", cacheByName); dynamic rtsResult = null; if (cacheTag != null) { ctx.Cache.TryGetValue(cacheTag, out rtsResult); } // store the previous reference symbol set, we will need to add it with // children found from the constructResolvedTraits call SymbolSet currSymRefSet = resOpt.SymbolRefSet; if (currSymRefSet == null) { currSymRefSet = new SymbolSet(); } resOpt.SymbolRefSet = new SymbolSet(); // if not, then make one and save it if (rtsResult == null) { // get the set of resolutions, should just be this one trait if (rtsTrait == null) { // store current symbol ref set SymbolSet newSymbolRefSet = resOpt.SymbolRefSet; resOpt.SymbolRefSet = new SymbolSet(); rtsTrait = trait.FetchResolvedTraits(resOpt); // bubble up symbol reference set from children if (newSymbolRefSet != null) { newSymbolRefSet.Merge(resOpt.SymbolRefSet); } resOpt.SymbolRefSet = newSymbolRefSet; } if (rtsTrait != null) { rtsResult = rtsTrait.DeepCopy(); } // now if there are argument for this application, set the values in the array if (this.Arguments != null && rtsResult != null) { // if never tried to line up arguments with parameters, do that if (!this.ResolvedArguments) { this.ResolvedArguments = true; ParameterCollection param = trait.FetchAllParameters(resOpt); CdmParameterDefinition paramFound = null; dynamic aValue = null; int iArg = 0; if (this.Arguments != null) { foreach (CdmArgumentDefinition a in this.Arguments) { paramFound = param.ResolveParameter(iArg, a.Name); a.ResolvedParameter = paramFound; aValue = a.Value; aValue = ((CdmCorpusDefinition)ctx.Corpus).ConstTypeCheck(resOpt, this.InDocument, paramFound, aValue); a.Value = aValue; iArg++; } } } if (this.Arguments != null) { foreach (CdmArgumentDefinition a in this.Arguments) { rtsResult.SetParameterValueFromArgument(trait, a); } } } // register set of possible symbols ((CdmCorpusDefinition)ctx.Corpus).RegisterDefinitionReferenceSymbols(this.FetchObjectDefinition <CdmObjectDefinition>(resOpt), kind, resOpt.SymbolRefSet); // get the new cache tag now that we have the list of symbols cacheTag = ((CdmCorpusDefinition)ctx.Corpus).CreateDefinitionCacheTag(resOpt, this, kind, "", cacheByName); if (!string.IsNullOrWhiteSpace(cacheTag)) { ctx.Cache[cacheTag] = rtsResult; } } else { // cache was found // get the SymbolSet for this cached object string key = CdmCorpusDefinition.CreateCacheKeyFromObject(this, kind); ((CdmCorpusDefinition)ctx.Corpus).DefinitionReferenceSymbols.TryGetValue(key, out SymbolSet tempDocRefSet); resOpt.SymbolRefSet = tempDocRefSet; } // merge child document set with current currSymRefSet.Merge(resOpt.SymbolRefSet); resOpt.SymbolRefSet = currSymRefSet; return(rtsResult); }