# Copyright (c) Meta Platforms, Inc. and affiliates. schema codemarkup.cxx.4 { import src import code.cxx import codemarkup.types import cxx1 import fbthrift import code.24 # Resolving locations to entities # Resolve locations for all traces in a Cxx file predicate CxxResolveLocation: { location: codemarkup.types.Location, entity: code.cxx.Entity, } { { Str, File, Range, Destination }, Entity } where Trace = cxx1.Trace { file = File }; CxxResolveTraceLocation { Trace, { Str, File, Range, Destination }, Entity }; # Resolve locations for Cxx, but for only a specific trace # We'll need to pick the trace on the client predicate CxxResolveTraceLocation: { trace : cxx1.Trace, location: codemarkup.types.Location, entity: code.cxx.Entity, } { Trace, Location, Entity } where Trace = cxx1.Trace { file = File, declarations = cxx1.Declarations Decls }; Decl = Decls[..]; # most declarations (their definition if present) ( if ( cxx1.DeclarationLocationNameSpan { Decl, Range, Str, NameFile, NameSpan } ) then ( # if we have a 'destination' name span Destination = { just = { NameFile, NameSpan } }; Location = codemarkup.types.Location { Str, File, { range = Range }, Destination } ) else ( # use the entity span only (usingDirectives, usingDeclarations) cxx1.DeclarationLocationName { Decl, Range, Str }; Location = codemarkup.types.Location { Str, File, { range = Range }, nothing } ); CxxResolveDeclarationToEntity { Decl, Entity }; # and find some extra enumerators: extracted from the enum decl ) | ( { enum_ = EnumDecl } = Decl; cxx1.EnumDefinition { declaration = EnumDecl, enumerators = Es }; Enumerator = Es[..]; { cxx1.Name Name, _, Range } = Enumerator; { file = File } = Range; Location = codemarkup.types.Location { Name, File, { range = Range }, nothing }; { enumerator = Enumerator } = Entity; ) # For a given declaration, match to proper code.cxx.Entity. It will be # a definition entity if the given declaration points to a definition. predicate CxxResolveDeclarationToEntity: { decl: cxx1.Declaration, entity: code.cxx.Entity, } { Decl, Entity } where if ( { function_ = FunctionDecl } = Decl; FunctionDefn = cxx1.FunctionDefinition { declaration = FunctionDecl } ) then ( { defn = { function_ = FunctionDefn } } = Entity ) else if ( { record_ = RecordDecl } = Decl; RecordDefn = cxx1.RecordDefinition { declaration = RecordDecl } ) then ( { defn = { record_ = RecordDefn } } = Entity ) else if ( { enum_ = EnumDecl } = Decl; EnumDefn = cxx1.EnumDefinition { declaration = EnumDecl } ) then ( { defn = { enum_ = EnumDefn } } = Entity ) else if ( { namespace_ = NamespaceDecl } = Decl; NamespaceDefn = cxx1.NamespaceDefinition { declaration = NamespaceDecl } ) then ( { defn = { namespace_ = NamespaceDefn } } = Entity ) else if ( { objcContainer = ContDecl } = Decl; ContainerDefn = cxx1.ObjcContainerDefinition { declaration = ContDecl } ) then ( { defn = { objcContainer = ContainerDefn } } = Entity ) else if ( { objcMethod = MethDecl } = Decl; MethDefn = cxx1.ObjcMethodDefinition MethDecl ) then ( { defn = { objcMethod = MethDefn } } = Entity ) else ( { decl = Decl } = Entity ) # If an entity is a declaration, try to find its definition, which # might be in a different file. There might be multiple definitions # (but presumably not linked in the same binary, because that would # violate the One Definition Rule). predicate CxxFindDefinitionOfEntity: { entity: code.cxx.Entity, definition: code.cxx.Entity, } ( { { defn = A }, { defn = B } } where A = B ) | ( { { decl = D }, DefEnt } where if ( code.cxx.DeclToDef { D, Defn }; ) then ( { defn = Defn } = DefEnt; ) else ( { decl = D } = DefEnt; ) ) # Finding entities' locations predicate CxxEntityLocation: { entity: code.cxx.Entity, location: codemarkup.types.Location, } { Entity , { Name, File, { range = Range }, Destination } } where ( { decl = Decl } = Entity; cxx1.DeclarationLocationNameSpan { Decl, Range, Name, NameFile, NameSpan }; { file = File } = Range; { just = { NameFile, NameSpan } } = Destination; ) | ( { defn = Defn } = Entity; cxx1.DefToBaseDecl { Defn, Decl }; cxx1.DeclarationLocationNameSpan { Decl, Range, Name, NameFile, NameSpan }; { file = File } = Range; { just = { NameFile, NameSpan } } = Destination; ) | ( { enumerator = { name = cxx1.Name Name, source = Range } } = Entity; { file = File } = Range; nothing = Destination; # we only have the range for enumerators ); # Finding references in a file # n.b. limited support for finding C++ xrefs by file, as the types are # generally too complex to flatten in Angle. We only provide local-to-file # xrefs via this path. To do the full set see glass Query/Cxx.hs # predicate CxxFileEntityXRefLocations: { file: src.File, xref: codemarkup.types.XRefLocation, entity: code.cxx.Entity, } { File, XRef, Entity } where ( Trace = cxx1.FileXRefs { xmap = { file = File } }; CxxFileEntityXMapFixedXRefLocations { Trace, XRef, Entity } ) | ( CxxFileEntitySpellingXRefLocations { File, XRef, Entity } ) # Fixed C++ xrefs, keyed by a specific cxx1.FileXRefs fact # We will expand any targets as best we can predicate CxxFileEntityXMapFixedXRefLocations: { trace: cxx1.FileXRefs, xref: codemarkup.types.XRefLocation, entity: code.cxx.Entity, } { Trace, XRef, Entity } where cxx1.FileXRefs { xmap = { fixed = Fixeds } } = Trace; cxx1.FixedXRef { XRefTarget, From } = Fixeds[..]; CxxXRefTargetLocation { XRefTarget, Entity, Location }; { spans = PackedSpans, spellings = PackedSpellings } = From; Spans = prim.unpackByteSpans PackedSpans; Spellings = prim.unpackByteSpans PackedSpellings; Span = (Spans | Spellings)[..]; { Location, { span = Span } } = XRef; predicate CxxFileEntitySpellingXRefLocations: { file: src.File, xref: codemarkup.types.XRefLocation, entity: code.cxx.Entity, } { File, XRef, Entity } where cxx1.SpellingXRef { { File, Span }, XRefTarget }; CxxXRefTargetLocation { XRefTarget, Entity, Location }; { Location, { span = Span } } = XRef; # Helper to (partially) process XRefTargets to entities and xrefs predicate CxxXRefTargetLocation: { target: cxx1.XRefTarget, entity: code.cxx.Entity, location: codemarkup.types.Location, } { XRefTarget, Entity, Location } where # fixed declaration entities ( { declaration = Decl } = XRefTarget; cxx1.DeclarationLocationNameSpan { Decl, Range, Name, NameFile, NameSpan }; { file = TargetFile } = Range; Destination = { just = { NameFile, NameSpan } }; { Name, TargetFile, { range = Range }, Destination } = Location; CxxResolveDeclarationToEntity { Decl, Entity }; ) | ( # or jump through the decl sometimes to a def { declaration = Decl } = XRefTarget; CxxDeclToDefXRefTargetLocation { Decl, Entity, Location }; ) | ( # fixed enumerator entities { enumerator = Enum } = XRefTarget; { cxx1.Name Name, _, Range } = Enum; { file = TargetFile } = Range; { Name, TargetFile, { range = Range }, nothing } = Location; { enumerator = Enum } = Entity; ) # objcSelector -- not an entity type # objcSelectorSlot -- can't implement due to array indexing # unknown -- just a file and a point in the file tbd # indirect -- can't implement due to recursion # # Find xrefs associated with decls in this file / trace # # For decls, compute unique xrefs to defns # For defns, compute unique xrefs to decls (decl families) # predicate CxxFileEntityTraceDeclToDefXRefLocations: { file: src.File, trace: cxx1.Trace, xref: codemarkup.types.XRefLocation, entity: code.cxx.Entity, } { File, Trace, XRef, Entity } where Trace = cxx1.Trace { File, cxx1.Declarations Decls, _ }; Decl = Decls[..]; cxx1.DeclarationNameSpan { Decl, _, Span }; # Get xrefs from decl to defn ,and defn back to decl family ({ Entity, Location } where CxxDeclToDefXRefTargetLocation { Decl, Entity, Location } | CxxDefToDeclFamilyXRefTargetLocation { Decl, Entity, Location } ); { Location, { span = Span }} = XRef; # For a given Decl, it might have a base Defn, build an entity for that # Iff the target is not the same as the source Decl predicate CxxDeclToDefXRefTargetLocation: { decl: cxx1.Declaration, entity: code.cxx.Entity, location: codemarkup.types.Location } { Decl1, Entity, Location } where CxxResolveDeclarationToEntity { Decl1, { decl = _ } }; code.cxx.DeclToDef { Decl1, Defn }; cxx1.DefToBaseDecl { Defn , Decl2 }; Decl1 != Decl2; # Filter out (many) self refs cxx1.DeclarationLocationNameSpan { Decl2, Range, Name, NameFile, NameSpan }; { file = TargetFile } = Range; Destination = { just = { NameFile, NameSpan } }; { Name, TargetFile, { range = Range }, Destination } = Location; { defn = Defn } = Entity; # For a given Decl, find any DeclFamily entries # We will turn these into xrefs predicate CxxDefToDeclFamilyXRefTargetLocation: { decl: cxx1.Declaration, entity: code.cxx.Entity, location: codemarkup.types.Location, } { Decl1, Entity, Location } where CxxResolveDeclarationToEntity { Decl1, { defn = _ } }; cxx1.DeclFamilyOf { decl = Decl1, family = Decl2 }; Decl1 != Decl2; # filter out many self-refs cxx1.DeclarationLocationNameSpan { Decl2, Range, Name, NameFile, NameSpan }; { file = TargetFile } = Range; Destination = { just = { NameFile, NameSpan } }; { Name, TargetFile, { range = Range }, Destination } = Location; { decl = Decl2 } = Entity; # Bulk fetch any declaration locations associated with the xref targets # Rather than O(n) calls to map over the external target xrefs, # we can bulk-fetch all locations in one go, saving a lot of calls predicate CxxFileEntityXMapVariableXRefDeclLocations: { trace: cxx1.FileXRefs, source: cxx1.Declaration, # used to identify the source location: codemarkup.types.Location, } { Trace, Decl, Location } where cxx1.FileXRefs { targets = Ts } = Trace; cxx1.XRefTargets Targets = Ts[..]; { declaration = Decl } = Targets[..]; cxx1.DeclarationLocationNameSpan { Decl, Range, Name, NameFile, NameSpan }; { file = TargetFile } = Range; Destination = { just = { NameFile, NameSpan } }; { Name, TargetFile, { range = Range }, Destination } = Location; predicate XRefTargetToEntity: { xrefTarget: cxx1.XRefTarget, ent: code.cxx.Entity } { X, E } where ({ declaration = D } = X; { decl = D } = E) | ({ enumerator = En } = X; { enumerator = En } = E) | ( { indirect = { target = X2 } } = X; ( ({ declaration = D2 } = X2; { decl = D2 } = E) | ({ enumerator = En2 } = X2; { enumerator = En2 } = E) ) ) predicate EntityToXRefTarget: { ent: code.cxx.Entity, xrefTarget: cxx1.XRefTarget } { E, X } where ({ decl = D } = E; { declaration = D } = X) | ({ enumerator = En } = E; { enumerator = En } = X) predicate CxxEntityIdl: { ent: code.cxx.Entity, idlEnt: code.IdlEntity, } { E, I } where EntityToXRefTarget { E, XRefTarget }; cxx1.CxxToThrift { from = XRefTarget, to = Thrift }; fbthrift.DeclarationFile { Thrift, fbthrift.File F }; { lang = Thrift, file = F, entity = { just = { fbthrift = { decl = Thrift } } }, range = nothing } = I # Bulk fetch any idl entities associated with the xref in the filexrefs predicate CxxFileEntityIdl: { trace: cxx1.FileXRefs, ent: code.Entity, idlEnt: code.IdlEntity, } { Trace, { cxx = Entity }, Idl } where cxx1.FileXRefs { xmap = { fixed = Fs }, targets = Ts } = Trace; ( cxx1.XRefTargets Targets = Ts[..]; XRefTarget = Targets[..]; XRefTargetToEntity { XRefTarget, Entity }; CxxEntityIdl { ent = Entity, idlEnt = Idl } ) | ( { target = XRefTarget } = Fs[..]; XRefTargetToEntity { XRefTarget, Entity }; CxxEntityIdl { ent = Entity, idlEnt = Idl }; ) # Bulk fetch any definitions associated with the external decls in the filexrefs predicate CxxFileEntityXMapVariableXRefDeclToDefs: { trace: cxx1.FileXRefs, source: cxx1.Declaration, # used to identify the source entity: code.cxx.Entity, # enough stuff to build a xreflocation location: codemarkup.types.Location, } { Trace, Decl, Entity, Location } where cxx1.FileXRefs { targets = Ts } = Trace; cxx1.XRefTargets Targets = Ts[..]; # decls # todo: more cases: recursion: indirect xrefs could be decls too { declaration = Decl } = Targets[..]; CxxDeclToDefXRefTargetLocation { Decl, Entity, Location }; # # Language entity uses # predicate CxxIdlEntityUses: { target: code.Entity, file: src.File, span: src.ByteSpan, } { Target, File, Span} where { fbthrift = { decl = Thrift } } = Target; cxx1.ThriftToCxx { Thrift, { declaration = CxxDecl } }; CxxEntityUses { { decl = CxxDecl }, File, Span } predicate CxxEntityUses: { target: code.cxx.Entity, file: src.File, span: src.ByteSpan, } ({ { decl = Decl }, File, Span } where cxx1.DeclFamilyOf { Decl, D }; cxx1.TargetUses { { declaration = D }, File, From }; { spans = PackedSpans, spellings = PackedSpellings } = From; Spans = prim.unpackByteSpans PackedSpans; Spellings = prim.unpackByteSpans PackedSpellings; Span = (Spans | Spellings)[..]) | ({ { defn = Defn }, File, Span } where CxxEntityDefinitionBase { Defn, DeclBase }; cxx1.DeclFamilyOf { DeclBase, D }; cxx1.TargetUses { { declaration = D }, File, From }; { spans = PackedSpans, spellings = PackedSpellings } = From; Spans = prim.unpackByteSpans PackedSpans; Spellings = prim.unpackByteSpans PackedSpellings; Span = (Spans | Spellings)[..]) | ({ { enumerator = E }, File, Span } where cxx1.TargetUses { { enumerator = E }, File, From }; { spans = PackedSpans, spellings = PackedSpellings } = From; Spans = prim.unpackByteSpans PackedSpans; Spellings = prim.unpackByteSpans PackedSpellings; Span = (Spans | Spellings)[..]) # For definitions, we find uses of the underlying declaration # For classes and anything else with ctors and dtors we also include uses # of the ctor and dtors predicate CxxEntityDefinitionBase: { target : code.cxx.Definition, base: cxx1.Declaration } { Defn, Decl } where # case 1: the base decl cxx1.DefToBaseDecl { Defn, Decl } | # case 2: for records, their ctors and dtors, a subset of functions ( cxx1.DefinitionEntity Defn; { record_ = RecordDefn } = Defn; cxx1.RecordDefinition { members = cxx1.Declarations Decls } = RecordDefn; Decl = Decls[..]; { function_ = { name = FQName } } = Decl; { name = { constructor = _ } | { destructor = _ } } = FQName; ) # # Language-specific symbol info # predicate CxxEntityKind: { entity: code.cxx.Entity, kind: codemarkup.types.SymbolKind, } { CxxD, Kind } where ({ decl = Decl } = CxxD; CxxDeclKind { Decl, Kind }) | ({ enumerator = _ } = CxxD; Enumerator = Kind) | ({ defn = Defn } = CxxD; cxx1.DefToBaseDecl { Defn, Decl }; CxxDeclKind { Decl, Kind } ) predicate CxxDeclKind: { decl: cxx1.Declaration, kind: codemarkup.types.SymbolKind, } { Decl, Kind } where ({ function_ = { name = FQN, method = MM } } = Decl; { name = FN } = FQN; ( { constructor = _ } = FN; Constructor = Kind ) | ( { destructor = _ } = FN; Constructor = Kind ) | ( { operator_ = _ } = FN; Operator = Kind ) | ( { literalOperator = _ } = FN; Operator = Kind ) | ( { conversionOperator = _ } = FN; Operator = Kind ) | ( { name = _ } = FN; ( { just = _ } = MM; Method = Kind ) | ( nothing = MM; Function = Kind ) ) ) | ( ({ enum_ = _ } = Decl; Enum_ = Kind ) | ({ namespace_ = _ } = Decl; Namespace = Kind ) | ({ objcMethod = _ } = Decl; Method = Kind ) | ({ objcProperty = _ } = Decl; Property = Kind ) | ({ typeAlias = _ } = Decl; Type = Kind ) | # typedef or using ({ usingDeclaration = _ } = Decl; Namespace = Kind ) | ({ variable = _ } = Decl; Variable = Kind ) | # TODO: more objc containers, using directives ({ objcContainer = { id = ObjcId } } = Decl; ({ interface_ = _ } | { categoryInterface = _ } | { extensionInterface = _ }) = ObjcId; Interface = Kind; ) | ( { record_ = R } = Decl; ({ kind = { struct_ = _ } } = R; Struct = Kind ) | ({ kind = { class_ = _ } } = R; Class_ = Kind ) | ({ kind = { union_ = _ } } = R; Union = Kind ) ) ) predicate CxxEntityInfo: { entity: code.cxx.Entity, info: codemarkup.types.SymbolInfo, } { CxxD, Info } where ({ decl = Decl } = CxxD; CxxDeclInfo { Decl, Info }) | ({ enumerator = _ } = CxxD; { kind = Enumerator, isAbstract = false } = Info) | ({ defn = Defn } = CxxD; cxx1.DefToBaseDecl { Defn, Decl }; CxxDeclInfo { Decl, Info }; ) predicate CxxDeclInfo: { decl: cxx1.Declaration, info: codemarkup.types.SymbolInfo, } { Decl, { kind = Kind, isAbstract = Abs } } where CxxDeclKind { decl = Decl, kind = Kind }; if (Method = Kind) then ( ({ function_ = { method = { just = M }}} = Decl; { isVirtual = Abs } = M ) | ( { objcMethod = _ } = Decl; false = Abs; ) ) else ( false = Abs ) # # Annotations # predicate CxxAnnotation: { entity: code.cxx.Entity, anns: code.cxx.Annotations, } {{ decl = Decl }, { attributes = As }} where { function_ = F } = Decl; if (cxx1.FunctionDeclAttribute { F, A }) then (As=[A]) else (As=[]:[cxx1.Attribute]); # # Visibility and modifiers # predicate CxxVisibility: { entity: code.cxx.Entity, visibility: codemarkup.types.Visibility, } { Entity, Visibility } where ( { decl = Decl } = Entity; CxxDeclVisibility { Decl, Visibility } ) | ( { defn = Defn } = Entity; CxxDefnVisibility { Defn, Visibility } ); predicate CxxDeclVisibility: { decl: cxx1.Declaration, visibility: codemarkup.types.Visibility } { Decl, Visibility } where Decl : cxx1.Declaration; if cxx1.DeclarationScope { Decl, Scope } then ( { recordWithAccess = { access = Access } } = Scope; FromCxxVisibility { Access, Visibility } ) else # Objc things don't have Scope ( { objcMethod = _ } | { objcProperty = _ } | { objcContainer = _ } = Decl; Public = Visibility ) predicate CxxDefnVisibility: { decl: code.cxx.Definition, visibility: codemarkup.types.Visibility } { Defn, Visibility } where cxx1.DefToBaseDecl { Defn, Decl }; CxxDeclVisibility { Decl, Visibility } # helper from C++ visibility to the codemarkup.types version predicate FromCxxVisibility: { cxx : cxx1.Access, out : codemarkup.types.Visibility } { In, Out } where ( Public = In; Public ) | ( Private = In; Private ) | ( Protected = In; Protected ) = Out; # Sets of modifier keywords on a symbol predicate CxxModifiers: { entity: code.cxx.Entity, keywords: codemarkup.types.Modifiers } { Entity, Modifiers } where ( { defn = Defn } = Entity; CxxDefinitionModifiers { Defn, Modifiers }) | ( { decl = Decl } = Entity; CxxDeclarationModifiers { Decl, Modifiers }); predicate CxxDefinitionModifiers: { entity: code.cxx.Definition, keywords: codemarkup.types.Modifiers } { Defn, Modifiers } where ( { function_ = FunDefn } = Defn; { declaration = FunDecl, isInline = Inline } = FunDefn; CxxDeclarationModifiers { { function_ = FunDecl } , ModifiersBase }; { _, _, _, _, _, Const, _, Volatile, Virtual, _ } = ModifiersBase; { false, false, false, false, false, Const, false, Volatile, Virtual, Inline } = Modifiers; ) | ( { objcMethod = M : cxx1.ObjcMethodDeclaration } = Defn; CxxDeclarationModifiers { { objcMethod = M }, Modifiers }; ) | ( { variable = VarDecl } = Defn; CxxDeclarationModifiers { { variable = VarDecl } , Modifiers }; ); predicate CxxDeclarationModifiers: { entity: cxx1.Declaration, keywords: codemarkup.types.Modifiers } { Decl, Modifiers } where ( { function_ = { method = MSig, name = { scope = Scope } } } = Decl; if ( { just = { isVirtual = V, isConst = C, isVolatile = Vol } } = MSig ) then ( Virtual = V; Const = C; Volatile = Vol ) else ( Virtual = false; Const = false; Volatile = false ); Static = if (nothing = MSig; { recordWithAccess = _ } = Scope) then true else false; Inline = false; Readonly = false; Static = Static; Mutable = false; ) | ( { objcProperty = { isReadOnly = Readonly, isInstance = Instance } } = Decl; Const = false; Volatile = false; Virtual = false; Inline = false; Static = (if (Instance = true) then false else true); Mutable = true; ) | ( { objcMethod = { isInstance = Instance } } = Decl; Readonly = false; Const = false; Volatile = false; Virtual = false; Inline = false; Static = (if (Instance = true) then false else true); Mutable = true; ) | ( { variable = { kind = Kind } } = Decl; ( { global_ = { VKind, Attr, _ } } = Kind; Static = if ( StaticVariable | StaticMember = VKind ) then ( true ) else ( false ); Inline = if ( Inline = Attr ) then ( true ) else ( false ); Const = if ( Constexpr = Attr ) then ( true ) else ( false ); Volatile = false; Virtual = false; Readonly = false; Mutable = false; ) | ( { local = { LKind, Attr } } = Kind; Static = if ( StaticVariable = LKind ) then ( true ) else ( false ); Const = if ( Constexpr = Attr ) then ( true ) else ( false ); Volatile = false; Virtual = false; Readonly = false; Inline = false; Mutable = false; ) | ( { field = { mutable_ = Mutable } } = Kind; Static = false; Readonly = false; Const = false; Volatile = false; Virtual = false; Readonly = false; Inline = false; ); ); { false, false, false, Static, Readonly, Const, Mutable, Volatile, Virtual, Inline } = Modifiers; # # Relations # # The child `extends` parent relationship predicate CxxExtendsParentEntity : { child : code.cxx.Entity, parent : code.cxx.Entity } { Child, Parent } where ( { decl = Decl } = Child; CxxDeclarationExtendsParent { Decl, Parent } ) | ( { defn = Defn } = Child; CxxDefinitionExtendsParent { Defn, Parent } ) # child extends parent for definitions # # - records (structs, classses) # - methods # - objC things # predicate CxxDefinitionExtendsParent: { child : code.cxx.Definition, parent : code.cxx.Entity } { Child, Parent } where ( { record_ = C } = Child; cxx1.RecordDefinition { bases = BS } = C; cxx1.RecordBase { base = P } = BS[..]; CxxResolveDeclarationToEntity { { record_ = P }, Parent } ) | ( { objcContainer = { declaration = C }} = Child; cxx1.ObjcImplements { C, P } | cxx1.ObjcContainerBase{ C, P }; CxxResolveDeclarationToEntity { { objcContainer = P }, Parent } ) predicate CxxDeclarationExtendsParent: { child : cxx1.Declaration, parent : code.cxx.Entity } { Child, Parent } where ( { record_ = _ } = Child; code.cxx.DeclToDef { Child, Defn }; CxxDefinitionExtendsParent { Defn, Parent } ) | ( { function_ = C } = Child; cxx1.MethodOverrides { C, P }; CxxResolveDeclarationToEntity { { function_ = P }, Parent } ) | ( { objcContainer = C } = Child; cxx1.ObjcImplements { C, P } | cxx1.ObjcContainerBase{ C, P }; CxxResolveDeclarationToEntity { { objcContainer = P }, Parent } ) # The parent `extended by` child relationship predicate CxxExtendsChildEntity : { parent: code.cxx.Entity, child: code.cxx.Entity } { Parent, Child } where ( { decl = Decl } = Parent; CxxDeclarationExtendsChild { Decl, Child } ) | ( { defn = Defn } = Parent; CxxDefinitionExtendsChild { Defn, Child } ) predicate CxxDefinitionExtendsChild: { parent: code.cxx.Definition, child: code.cxx.Entity } { Parent, Child } where cxx1.DefToBaseDecl { Parent, Decl }; CxxDeclarationExtendsChild { Decl, Child } predicate CxxDeclarationExtendsChild: { parent: cxx1.Declaration, child: code.cxx.Entity } { Parent, Child } where ( { record_ = P } = Parent; cxx1.RecordDerived { P, C }; CxxResolveDeclarationToEntity { { record_ = C }, Child } ) | ( { function_ = P } = Parent; cxx1.MethodOverridden { P, C }; CxxResolveDeclarationToEntity { { function_ = C }, Child } ) | ( { objcContainer = P } = Parent; cxx1.ObjcContainerInheritance { P, C }; CxxResolveDeclarationToEntity { { objcContainer = C }, Child } ) # The child of parent relationship # # works for only some things # # - enumerators -> enum # - nested records/unions/structs # - methods -> container classes # predicate CxxContainsParentEntity : { child: code.cxx.Entity, parent: code.cxx.Entity } { Child, Parent } where ( { decl = Decl } = Child; CxxDeclarationContainsParent { Decl, Parent }; ) | ( { defn = Defn } = Child; CxxDefinitionContainsParent { Defn, Parent } ) | ( { enumerator = E } = Child; cxx1.EnumeratorInEnum { E, Enum }; { defn = { enum_ = Enum } } = Parent ) # Definition to parent container, efficiently predicate CxxDefinitionContainsParent: { child : code.cxx.Definition, parent : code.cxx.Entity } { Child, Parent } where # most C++ things: functions, records, variables: { record_ = _ } | { function_ = _ } | { enum_ = _ } | { variable = _ } = Child; cxx1.DefnInRecord { Child, P }; # find the precise parent set { defn = { record_ = P } } = Parent # # we can find parents via the cxx1.Scope of the child # this works ok for definition types, where we restrict by membership filters # we can't do this for namespaces yet, without enumerating traces or all decls # predicate CxxDeclarationContainsParent: { child: cxx1.Declaration, parent: code.cxx.Entity } { Child, Parent } where # most C++ things: functions, records, variables: { usingDeclaration = _ } | { usingDirective = _ } | { record_ = _ } | { enum_ = _ } | { function_ = _ } | { variable = _ } | { typeAlias = _ } = Child; cxx1.DeclInRecord { Child, P }; # find the precise parent set { defn = { record_ = P } } = Parent # | ( # { objcMethod = _ } | { objcProperty = _ } = Child; # cxx1.DeclInObjcContainer { Child, P }; # { defn = { objcContainer = P } } = Parent #) # # The parent `contains` child relationship # predicate CxxContainsChildEntity : { parent: code.cxx.Entity, child: code.cxx.Entity } { Parent, Child } where ( { decl = Decl} = Parent; CxxDeclarationContainsChild { Decl, Child } ) | ( { defn = Defn } = Parent; CxxDefinitionContainsChild { Defn, Child } ) # Lookup container child for definition occurences # # - records # - objc containers # - namespaces # - enums # predicate CxxDefinitionContainsChild: { parent: code.cxx.Definition, child: code.cxx.Entity } { Parent, Child } where ( { record_ = Defn } = Parent; cxx1.RecordDefinition { members = cxx1.Declarations Decls } = Defn; Decl = Decls[..]; CxxResolveDeclarationToEntity { Decl, Child } ) | ( { objcContainer = Defn } = Parent; cxx1.ObjcContainerDefinition { members = cxx1.Declarations Decls } = Defn; Decl = Decls[..]; CxxResolveDeclarationToEntity { Decl, Child } ) | ( # namespace member facts are all empty, so instead lookup by scope { namespace_ = Defn } = Parent; cxx1.NamespaceDefinition { declaration = Decl } = Defn; CxxNamespaceDeclarationContainsChild { Decl, Child } ) | ( { enum_ = Defn } = Parent; cxx1.EnumDefinition { enumerators = Es } = Defn; E = Es[..]; { enumerator = E } = Child ) # we could add params of methods and functions # { function_ = Defn } = Container; # ( { objcMethod = Defn } = Container ) | # these do not have children # ( { variable = Defn } = Container ) | # Lookup container children via decl goes via its definition predicate CxxDeclarationContainsChild: { parent: cxx1.Declaration, child: code.cxx.Entity } { Parent, Child } where ( { namespace_ = Decl } = Parent; CxxNamespaceDeclarationContainsChild { Decl, Child } ) | ( ({ record_ = _ } | { objcContainer = _ } | { enum_ = _ } ) = Parent; code.cxx.DeclToDef { Parent, Defn }; CxxDefinitionContainsChild { Defn, Child } ) # Namespaces contain children with the namespace as its scope # these can be quite large for common namespaces shared widely predicate CxxNamespaceDeclarationContainsChild: { parent: cxx1.NamespaceDeclaration, child: code.cxx.Entity } { Decl, Child } where { name = NSQName } = Decl; Scope = cxx1.Scope { namespace_ = NSQName }; ( Q = cxx1.QName { name = _, scope = Scope }; # n.b. not left prefixed! ( code.cxx.Entity { decl = { record_ = { name = Q }}} | code.cxx.Entity { decl = { variable = { name = Q }}} | code.cxx.Entity { decl = { typeAlias = { name = Q }}} | code.cxx.Entity { decl = { enum_ = { name = Q }}} ) ) | ( D = cxx1.FunctionDeclaration { name = { scope = Scope } }; code.cxx.Entity { decl = { function_ = D } } ) = Child; # comment blocks across declaration families predicate CxxEntityDocumentation : { entity : code.cxx.Entity, file : src.File, span : src.ByteSpan, } { E, F, S } where ( { decl = Decl } = E; cxx1.DeclarationComment{ declaration = Decl, file = F, span = S } ) | ( { defn = Defn } = E; cxx1.DefToBaseDecl { Defn, DeclBase }; cxx1.DeclarationComment{ declaration = DeclBase, file = F, span = S } ) predicate CxxDataAvailable : src.File F where src.File _ = F; # double negation is used to check for existence # (even if the Angle compiler could notice and optimize) !(!(cxx1.Trace {file = F})) predicate CxxEntityUSR : { entity : code.cxx.Entity, usr : cxx1.USR, } { E, U } where ( { defn = Defn } = E; cxx1.DefToBaseDecl { Defn, DeclBase }; cxx1.DeclFamilyOf { DeclBase, Decl }; cxx1.DeclarationToUSR { Decl, U }; ) | ( { decl = Decl } = E; cxx1.DeclFamilyOf { Decl, DeclFam }; cxx1.DeclarationToUSR { DeclFam, U }; ) # TODO: do we have to care about decl families? (see CxxEntityUSR above) predicate SymbolToEntity: { usr: code.cxx.SymbolId, entity: code.cxx.Entity, } { Symbol, Entity } where cxx1.USRToDeclaration { hash = Symbol, declaration = Decl }; Decl = cxx1.Declaration D; ( (D = { objcContainer = { id = { protocol = _ } | { interface_ = _ } | { categoryInterface = _ } | { extensionInterface = _ } } }) | (D = { objcMethod = { container = { protocol = _ } | { implementation = _ } | { categoryImplementation = _ } | { extensionInterface = _ } } }) | !(D = { objcContainer = _ } | { objcMethod = _ }) ); Entity = { decl = Decl }; predicate CxxEntityMangledNameHash : { entity : code.cxx.Entity, hash : cxx1.MangledNameHash, } { E, H } where ( { defn = Defn } = E; cxx1.DefToBaseDecl { Defn, DeclBase }; cxx1.DeclFamilyOf { DeclBase, Decl }; cxx1.MangledNameHashToDeclaration { H, Decl }; ) | ( { decl = Decl } = E; cxx1.DeclFamilyOf { Decl, DeclFam }; cxx1.MangledNameHashToDeclaration { H, DeclFam }; ) predicate CxxDeclarationSource: { target: cxx1.Declaration, referrer: code.cxx.Entity, } { Target, Referrer} where cxx1.DeclarationSources { target = Target, sources = Sources }; Source = Sources[..]; { decl = Source } = Referrer; predicate CxxEntitySource: { target: code.cxx.Entity, source: code.cxx.Entity, } { Target, Referrer} where ( {decl = Decl} = Target ; CxxDeclarationSource { Decl, Referrer} ) | ( {defn = Def } = Target; cxx1.DefToBaseDecl { Def, Decl }; CxxDeclarationSource{ Decl, Referrer} ) }