/// <summary> /// Fetches the corresponding object definition for every object reference. /// </summary> /// <param name="objects"></param> /// <param name="resOpt"></param> internal void ResolveObjectDefinitions(ResolveOptions resOpt) { ResolveContext ctx = this.Ctx as ResolveContext; resOpt.IndexingDoc = this; foreach (var obj in this.InternalObjects) { switch (obj.ObjectType) { case CdmObjectType.AttributeRef: case CdmObjectType.AttributeGroupRef: case CdmObjectType.AttributeContextRef: case CdmObjectType.DataTypeRef: case CdmObjectType.EntityRef: case CdmObjectType.PurposeRef: case CdmObjectType.TraitRef: ctx.RelativePath = obj.DeclaredPath; CdmObjectReferenceBase reff = obj as CdmObjectReferenceBase; if (CdmObjectReferenceBase.offsetAttributePromise(reff.NamedReference) < 0) { CdmObjectDefinition resNew = reff.FetchObjectDefinition <CdmObjectDefinition>(resOpt); if (resNew == null) { // It's okay if references can't be resolved when shallow validation is enabled. if (resOpt.ShallowValidation) { Logger.Warning(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, CdmLogCode.WarnResolveReferenceFailure, reff.NamedReference); } else { Logger.Error(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, CdmLogCode.ErrResolveReferenceFailure, reff.NamedReference); // don't check in this file without both of these comments. handy for debug of failed lookups // CdmObjectDefinitionBase resTest = ref.FetchObjectDefinition(resOpt); } } else { Logger.Info(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, $"resolved '{reff.NamedReference}'"); } } break; case CdmObjectType.ParameterDef: // when a parameter has a datatype that is a cdm object, validate that any default value is the // right kind object CdmParameterDefinition parameter = obj as CdmParameterDefinition; parameter.ConstTypeCheck(resOpt, this, null); break; } } resOpt.IndexingDoc = null; }
/// <summary> /// Checks if the trait argumnet value matchs the data type defined on the trait parameter /// </summary> /// <param name="resOpt"></param> /// <param name="wrtDoc"></param> /// <param name="argumentValue"></param> /// <returns></returns> internal dynamic ConstTypeCheck(ResolveOptions resOpt, CdmDocumentDefinition wrtDoc, dynamic argumentValue) { ResolveContext ctx = this.Ctx as ResolveContext; dynamic replacement = argumentValue; // if parameter type is entity, then the value should be an entity or ref to one // same is true of 'dataType' dataType if (this.DataTypeRef == null) { return(replacement); } CdmDataTypeDefinition dt = this.DataTypeRef.FetchObjectDefinition <CdmDataTypeDefinition>(resOpt); if (dt == null) { Logger.Error(ctx, Tag, nameof(ConstTypeCheck), this.AtCorpusPath, CdmLogCode.ErrUnrecognizedDataType, this.Name); return(null); } // compare with passed in value or default for parameter dynamic pValue = argumentValue; if (pValue == null) { pValue = this.DefaultValue; replacement = pValue; } if (pValue != null) { if (dt.IsDerivedFrom("cdmObject", resOpt)) { List <CdmObjectType> expectedTypes = new List <CdmObjectType>(); string expected = null; if (dt.IsDerivedFrom("entity", resOpt)) { expectedTypes.Add(CdmObjectType.ConstantEntityDef); expectedTypes.Add(CdmObjectType.EntityRef); expectedTypes.Add(CdmObjectType.EntityDef); expectedTypes.Add(CdmObjectType.ProjectionDef); expected = "entity"; } else if (dt.IsDerivedFrom("attribute", resOpt)) { expectedTypes.Add(CdmObjectType.AttributeRef); expectedTypes.Add(CdmObjectType.TypeAttributeDef); expectedTypes.Add(CdmObjectType.EntityAttributeDef); expected = "attribute"; } else if (dt.IsDerivedFrom("dataType", resOpt)) { expectedTypes.Add(CdmObjectType.DataTypeRef); expectedTypes.Add(CdmObjectType.DataTypeDef); expected = "dataType"; } else if (dt.IsDerivedFrom("purpose", resOpt)) { expectedTypes.Add(CdmObjectType.PurposeRef); expectedTypes.Add(CdmObjectType.PurposeDef); expected = "purpose"; } else if (dt.IsDerivedFrom("traitGroup", resOpt)) { expectedTypes.Add(CdmObjectType.TraitGroupRef); expectedTypes.Add(CdmObjectType.TraitGroupDef); expected = "traitGroup"; } else if (dt.IsDerivedFrom("trait", resOpt)) { expectedTypes.Add(CdmObjectType.TraitRef); expectedTypes.Add(CdmObjectType.TraitDef); expected = "trait"; } else if (dt.IsDerivedFrom("attributeGroup", resOpt)) { expectedTypes.Add(CdmObjectType.AttributeGroupRef); expectedTypes.Add(CdmObjectType.AttributeGroupDef); expected = "attributeGroup"; } if (expectedTypes.Count == 0) { Logger.Error(ctx, Tag, nameof(ConstTypeCheck), wrtDoc.FolderPath + wrtDoc.Name, CdmLogCode.ErrUnexpectedDataType, this.Name); } // if a string constant, resolve to an object ref. CdmObjectType foundType = CdmObjectType.Error; Type pValueType = pValue.GetType(); if (typeof(CdmObject).IsAssignableFrom(pValueType)) { foundType = (pValue as CdmObject).ObjectType; } string foundDesc = ctx.RelativePath; if (!(pValue is CdmObject)) { // pValue is a string or JValue pValue = (string)pValue; if (pValue == "this.attribute" && expected == "attribute") { // will get sorted out later when resolving traits foundType = CdmObjectType.AttributeRef; } else { foundDesc = pValue; int seekResAtt = CdmObjectReferenceBase.offsetAttributePromise(pValue); if (seekResAtt >= 0) { // get an object there that will get resolved later after resolved attributes replacement = new CdmAttributeReference(ctx, pValue, true); (replacement as CdmAttributeReference).Ctx = ctx; (replacement as CdmAttributeReference).InDocument = wrtDoc; foundType = CdmObjectType.AttributeRef; } else { CdmObjectBase lu = ctx.Corpus.ResolveSymbolReference(resOpt, wrtDoc, pValue, CdmObjectType.Error, retry: true); if (lu != null) { if (expected == "attribute") { replacement = new CdmAttributeReference(ctx, pValue, true); (replacement as CdmAttributeReference).Ctx = ctx; (replacement as CdmAttributeReference).InDocument = wrtDoc; foundType = CdmObjectType.AttributeRef; } else { replacement = lu; foundType = (replacement as CdmObject).ObjectType; } } } } } if (expectedTypes.IndexOf(foundType) == -1) { Logger.Error(ctx, Tag, nameof(ConstTypeCheck), wrtDoc.AtCorpusPath, CdmLogCode.ErrResolutionFailure, this.Name, expected, foundDesc, expected); } else { Logger.Info(ctx, Tag, nameof(ConstTypeCheck), wrtDoc.AtCorpusPath, $"resolved '{foundDesc}'"); } } } return(replacement); }