in objectModel/CSharp/Microsoft.CommonDataModel.ObjectModel/Cdm/CdmCorpusDefinition.cs [257:531]
internal CdmObjectBase ResolveSymbolReference(ResolveOptions resOpt, CdmDocumentDefinition fromDoc, string symbolDef, CdmObjectType expectedType, bool retry)
{
ResolveContext ctx = this.Ctx as ResolveContext;
// given a symbolic name, find the 'highest prirority' definition of the object from the point of view of a given document (with respect to, wrtDoc)
// (meaning given a document and the things it defines and the files it imports and the files they import, where is the 'last' definition found)
if (resOpt?.WrtDoc == null || symbolDef == null)
{
return null; // no way to figure this out
}
CdmDocumentDefinition wrtDoc = resOpt.WrtDoc;
if (wrtDoc.NeedsIndexing && !wrtDoc.CurrentlyIndexing)
{
var indexTask = Task.Run(async () => await wrtDoc.IndexIfNeeded(resOpt, true));
// if the wrtDoc needs to be indexed (like it was just modified) then do that first
if (!indexTask.Result)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), wrtDoc.AtCorpusPath, CdmLogCode.ErrIndexFailed);
return null;
}
}
if (wrtDoc.NeedsIndexing && resOpt.ImportsLoadStrategy == ImportsLoadStrategy.DoNotLoad)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), wrtDoc.AtCorpusPath, CdmLogCode.ErrSymbolNotFound, symbolDef, "because the ImportsLoadStrategy is set to DoNotLoad");
return null;
}
// save the symbol name as it got here
string initialSymbol = symbolDef;
// when trying to find a reference, first find the definition that contains it
// and then look for the reference inside it.
bool isReference = symbolDef?.EndsWith("(ref)") == true;
if (isReference)
{
int defIndex = symbolDef.IndexOf("/");
symbolDef = symbolDef.Substring(0, defIndex);
}
// get the array of documents where the symbol is defined
DocsResult symbolDocsResult = this.DocsForSymbol(resOpt, wrtDoc, fromDoc, symbolDef);
CdmDocumentDefinition docBest = symbolDocsResult.DocBest;
symbolDef = symbolDocsResult.NewSymbol;
if (!isReference)
{
initialSymbol = symbolDef;
}
List<CdmDocumentDefinition> docs = symbolDocsResult.DocList;
if (docs != null)
{
// add this symbol to the set being collected in resOpt, we will need this when caching
if (resOpt.SymbolRefSet == null)
{
resOpt.SymbolRefSet = new SymbolSet();
}
resOpt.SymbolRefSet.Add(symbolDef);
// for the given doc, there is a sorted list of imported docs (including the doc itself as item 0).
// find the lowest number imported document that has a definition for this symbol
if (wrtDoc.ImportPriorities == null)
{
return null;
}
IDictionary<CdmDocumentDefinition, ImportInfo> importPriority = wrtDoc.ImportPriorities.ImportPriority;
if (importPriority.Count == 0)
{
return null;
}
if (docBest == null)
{
docBest = FetchPriorityDocument(docs, importPriority);
}
}
// perhaps we have never heard of this symbol in the imports for this document?
if (docBest == null)
{
return null;
}
// return the definition found in the best document
docBest.InternalDeclarations.TryGetValue(symbolDef, out CdmObjectBase found);
// in case we are trying to find a reference, the object we found previously is the definition that contains the reference.
// look inside the definition now.
if (found != null && isReference)
{
CdmObjectBase foundRef = null;
// try to find the reference
found.Visit("", new VisitCallback
{
Invoke = (obj, objPath) =>
{
if (string.Equals(initialSymbol, objPath))
{
foundRef = obj as CdmObjectBase;
return true;
}
return false;
}
}, null);
found = foundRef;
}
if (found == null && retry == true)
{
// maybe just locatable from here not defined here.
// this happens when the symbol is monikered, but the moniker path doesn't lead to the document where the symbol is defined.
// it leads to the document from where the symbol can be found.
// Ex.: resolvedFrom/Owner, while resolvedFrom is the Account that imports Owner.
found = this.ResolveSymbolReference(resOpt, docBest, initialSymbol, expectedType, retry: false);
}
if (found != null && expectedType != CdmObjectType.Error)
{
switch (expectedType)
{
case CdmObjectType.TraitRef:
if (found.ObjectType != CdmObjectType.TraitDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "trait", symbolDef);
found = null;
}
break;
case CdmObjectType.DataTypeRef:
if (found.ObjectType != CdmObjectType.DataTypeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "dataType", symbolDef);
found = null;
}
break;
case CdmObjectType.EntityRef:
if (found.ObjectType != CdmObjectType.EntityDef && found.ObjectType != CdmObjectType.ProjectionDef && found.ObjectType != CdmObjectType.ConstantEntityDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "entity or type projection or type constant entity", symbolDef);
found = null;
}
break;
case CdmObjectType.ParameterDef:
if (found.ObjectType != CdmObjectType.ParameterDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "parameter", symbolDef);
found = null;
}
break;
case CdmObjectType.PurposeRef:
if (found.ObjectType != CdmObjectType.PurposeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "purpose", symbolDef);
found = null;
}
break;
case CdmObjectType.TraitGroupRef:
if (found.ObjectType != CdmObjectType.TraitGroupDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "traitGroup", symbolDef);
found = null;
}
break;
case CdmObjectType.AttributeGroupRef:
if (found.ObjectType != CdmObjectType.AttributeGroupDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "attributeGroup", symbolDef);
found = null;
}
break;
case CdmObjectType.ProjectionDef:
if (found.ObjectType != CdmObjectType.ProjectionDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "projection", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAddCountAttributeDef:
if (found.ObjectType != CdmObjectType.OperationAddCountAttributeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "add count attribute operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAddSupportingAttributeDef:
if (found.ObjectType != CdmObjectType.OperationAddSupportingAttributeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "add supporting attribute operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAddTypeAttributeDef:
if (found.ObjectType != CdmObjectType.OperationAddTypeAttributeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "type attribute operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationExcludeAttributesDef:
if (found.ObjectType != CdmObjectType.OperationExcludeAttributesDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "exclude attributes operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationArrayExpansionDef:
if (found.ObjectType != CdmObjectType.OperationArrayExpansionDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "array expansion operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationCombineAttributesDef:
if (found.ObjectType != CdmObjectType.OperationCombineAttributesDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "combine attributes operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationRenameAttributesDef:
if (found.ObjectType != CdmObjectType.OperationRenameAttributesDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "rename attributes operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationReplaceAsForeignKeyDef:
if (found.ObjectType != CdmObjectType.OperationReplaceAsForeignKeyDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "replace as foreign key operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationIncludeAttributesDef:
if (found.ObjectType != CdmObjectType.OperationIncludeAttributesDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "include attributes operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAddAttributeGroupDef:
if (found.ObjectType != CdmObjectType.OperationAddAttributeGroupDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "add attribute group operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAlterTraitsDef:
if (found.ObjectType != CdmObjectType.OperationAlterTraitsDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "alter traits operation", symbolDef);
found = null;
}
break;
case CdmObjectType.OperationAddArtifactAttributeDef:
if (found.ObjectType != CdmObjectType.OperationAddArtifactAttributeDef)
{
Logger.Error(ctx, Tag, nameof(ResolveSymbolReference), found.AtCorpusPath, CdmLogCode.ErrUnexpectedType, "add artifact attribute operation", symbolDef);
found = null;
}
break;
}
}
if (resOpt.SymbolRefToObjects != null && found is CdmObjectDefinitionBase foundDef)
{
resOpt.SymbolRefToObjects.Add(Tuple.Create(symbolDef, foundDef));
}
return found;
}