{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} {-# LANGUAGE TypeApplications, ApplicativeDo, PartialTypeSignatures #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# OPTIONS_GHC -Wno-orphans #-} module Glean.Glass.Search.Cxx ( {- instances -} ) where import Data.Text ( Text ) import qualified Data.Text as Text import Data.Set ( Set ) import qualified Data.Set as Set import Glean.Angle as Angle import Glean.Haxl.Repos (ReposHaxl) import Glean.Glass.Search.Class ( ResultLocation, SearchResult(None), Search(..), searchSymbolId ) import Glean.Glass.Query ( entityLocation ) import qualified Glean.Glass.SymbolId.Cxx.Parse as P import qualified Glean.Schema.CodeCxx.Types as Cxx import qualified Glean.Schema.Code.Types as Code import qualified Glean.Schema.CodemarkupTypes.Types as Code import qualified Glean.Schema.Cxx1.Types as Cxx import qualified Glean.Schema.Src.Types as Src import qualified Glean.Schema.SymbolidCxx.Types as SymbolId instance Search (ResultLocation Cxx.Entity) where symbolSearch = cxxSymbolSearch cxxSymbolSearch :: [Text] -> ReposHaxl u w (SearchResult (ResultLocation Cxx.Entity)) cxxSymbolSearch t = case P.validateSymbolId t of Left errs -> return $ None (Text.unlines errs) Right env -> case P.compileSymbolEnv env of Left err -> return $ None err Right exp -> case exp of P.CxxDecl e -> cxxSymbolExprEvalDecl t e P.CxxDefn e -> cxxSymbolExprEvalDefn t e cxxSymbolExprEvalDecl :: [Text] -> P.CxxSymbolExpr -> ReposHaxl u w (SearchResult (ResultLocation Cxx.Entity)) cxxSymbolExprEvalDecl t exp = case exp of P.CxxConstructor{..} -> searchSymbolId t $ lookupCTorSignatureDeclaration cPath cScope cParams P.CxxDestructor{..} -> searchSymbolId t $ lookupDTorDeclaration cPath cScope P.CxxFunction{..} -> searchSymbolId t $ lookupFunctionSignatureDeclaration cPath cScope cName cParams cQuals P.CxxOperator{..} -> searchSymbolId t $ lookupOperatorSignatureDeclaration cPath cScope cName cParams cQuals P.CxxTypeConversionOperator{..} -> searchSymbolId t $ lookupTypeOperatorSignatureDeclaration cPath cScope cReturns cQuals P.CxxLegacyCTorParams{..} -> let scope' = cScope <> [P.Name ".ctor"] -- hack into scope query builder in searchSymbolId t $ lookupDeclaration cPath scope' cName P.CxxAny{..} -> searchDeclarations t cPath cScope cName cxxSymbolExprEvalDefn :: [Text] -> P.CxxSymbolExpr -> ReposHaxl u w (SearchResult (ResultLocation Cxx.Entity)) cxxSymbolExprEvalDefn t exp = case exp of P.CxxConstructor{..} -> searchSymbolId t $ lookupCTorSignatureDefinition cPath cScope cParams P.CxxDestructor{..} -> searchSymbolId t $ lookupDTorDefinition cPath cScope P.CxxFunction{..} -> searchSymbolId t $ lookupFunctionSignatureDefinition cPath cScope cName cParams cQuals P.CxxOperator{..} -> searchSymbolId t $ lookupOperatorSignatureDefinition cPath cScope cName cParams cQuals P.CxxTypeConversionOperator{..} -> searchSymbolId t $ lookupTypeOperatorSignatureDefinition cPath cScope cReturns cQuals P.CxxLegacyCTorParams{..} -> let scope' = cScope <> [P.Name ".ctor"] -- hack into scope query builder in searchSymbolId t $ lookupDefinition cPath scope' cName P.CxxAny{..} -> searchDefinitions t cPath cScope cName -- this is the most common path, for e.g. classes and functions -- -- > fbsource/cpp @ fbcode/folly/Optional/assign -- > fbsource/cpp @ fbcode/folly/Optional -- -- would resolve to their definition occurences. -- -- enumerators (fields of enums) are also in this path -- searchDefinitions :: [Text] -> Text -> [P.Name] -> P.Name -> ReposHaxl u w (SearchResult (ResultLocation Cxx.Entity)) searchDefinitions t path ns name = searchSymbolId t (lookupDefinition path ns name) .|? searchSymbolId t (lookupFunctionDefinition path ns name) .|? searchSymbolId t (lookupNamespaceDefinition path ns name) .|? (if not (null ns) then searchSymbolId t (lookupEnumerator path (init ns) (last ns) name) else pure $ None "Cxx.searchDefinitions: no results found") -- -- declaration entities only -- searchDeclarations :: [Text] -> Text -> [P.Name] -> P.Name -> ReposHaxl u w (SearchResult (ResultLocation Cxx.Entity)) searchDeclarations t path ns name = -- `ns` might be [] for global scope searchSymbolId t (lookupDeclaration path ns name) .|? searchSymbolId t (lookupFunctionDeclaration path ns name) .|? searchSymbolId t (lookupNamespaceDeclaration path ns name) -- -- A little `then` or .|. thing for searching until first match -- (.|?) :: ReposHaxl u w (SearchResult t) -> ReposHaxl u w (SearchResult t) -> ReposHaxl u w (SearchResult t) a .|? b = do v <- a case v of None{} -> b _ -> pure v ------------------------------------------------------------------------ -- -- Records, Variables, Enum, TypeAlias, Using Directives. -- lookupDefinition :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupDefinition = lookupEntityFn $ \(P.Name name) ns entity -> predicate @SymbolId.LookupDefinition ( rec $ field @"name" (string name) $ field @"scope" (scopeQ (reverse (P.unNames ns))) $ field @"entity" entity end) lookupFunctionDefinition :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupFunctionDefinition = lookupEntityFn $ \(P.Name name) ns entity -> predicate @SymbolId.LookupFunctionDefinition ( rec $ field @"name" (functionName name) $ field @"scope" (scopeQ (reverse (P.unNames ns))) $ field @"entity" entity end) lookupNamespaceDefinition :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupNamespaceDefinition = lookupEntityFn $ \(P.Name name) ns entity -> predicate @SymbolId.LookupNamespaceDefinition ( rec $ field @"name" (maybeName name) $ field @"parent" (namespaceParentQName (reverse (P.unNames ns))) $ field @"entity" entity end) -- -- enum values (fields of an enumerator) are a bit different again. -- they are a field in an enum declaration, so to query you need to -- know the field, and also the parent enum name and scope. -- lookupEnumerator :: Text -> [P.Name] -> P.Name -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupEnumerator anchor ns (P.Name parent) (P.Name name) = vars $ \ (decl :: Angle Cxx.Enumerator) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ( (scope .= sig (scopeQ (reverse scopes))):( wild .= predicate @SymbolId.LookupEnumerator ( rec $ field @"name" (string name) $ field @"parent" (string parent) $ field @"scope" scope $ field @"decl" (asPredicate decl) end)) : (alt @"enumerator" (asPredicate decl) .= sig entity) : entityFooter anchor entity codeEntity file rangespan lname ) where scopes = P.unNames ns lookupDTorDeclaration :: Text -> [P.Name] -> Angle (ResultLocation Cxx.Entity) lookupDTorDeclaration anchor ns = vars $ \(decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ( (scope .= sig (scopeQ (reverse scopes))):( wild .= predicate @SymbolId.LookupFunctionDeclaration ( rec $ field @"name" (alt @"destructor" wild) $ field @"scope" scope $ field @"decl" decl end)) : entityDeclFooter anchor decl entity codeEntity file rangespan lname ) where scopes = P.unNames ns lookupDTorDefinition :: Text -> [P.Name] -> Angle (ResultLocation Cxx.Entity) lookupDTorDefinition anchor ns = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ( (scope .= sig (scopeQ (reverse scopes))):( wild .= predicate @SymbolId.LookupFunctionDefinition ( rec $ field @"name" (alt @"destructor" wild) $ field @"scope" scope $ field @"entity" entity end)) : entityFooter anchor entity codeEntity file rangespan lname ) where scopes = P.unNames ns lookupCTorSignatureDefinition :: Text -> [P.Name] -> [P.Name] -> Angle (ResultLocation Cxx.Entity) lookupCTorSignatureDefinition anchor ns ps = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureDefinition ( rec $ field @"name" (alt @"constructor" wild) $ -- either @alt ctor or dtor field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"entity" entity end) ] <> entityFooter anchor entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps lookupCTorSignatureDeclaration :: Text -> [P.Name] -> [P.Name] -> Angle (ResultLocation Cxx.Entity) lookupCTorSignatureDeclaration anchor ns ps = vars $ \(decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureDeclaration ( rec $ field @"name" (alt @"constructor" wild) $ -- either @alt ctor or dtor field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"decl" decl end) ] <> entityDeclFooter anchor decl entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps lookupFunctionSignatureDeclaration :: Text -> [P.Name] -> P.Name -> [P.Name] -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupFunctionSignatureDeclaration anchor ns (P.Name name) ps quals = vars $ \(decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (fname :: Angle Cxx.FunctionName) (n :: Angle Cxx.Name) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ n .= predicate @Cxx.Name (string name), fname .= predicate @Cxx.FunctionName (alt @"name" (asPredicate n)), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDeclaration ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"qualifiers" (qualifiersQ quals) $ field @"decl" decl end) ] <> entityDeclFooter anchor decl entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps lookupFunctionSignatureDefinition :: Text -> [P.Name] -> P.Name -> [P.Name] -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupFunctionSignatureDefinition anchor ns (P.Name name) ps quals = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (fname :: Angle Cxx.FunctionName) (n :: Angle Cxx.Name) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ n .= predicate @Cxx.Name (string name), fname .= predicate @Cxx.FunctionName (alt @"name" (asPredicate n)), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDefinition ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"qualifiers" (qualifiersQ quals) $ field @"entity" entity end) ] <> entityFooter anchor entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps -- -- Like functions, but there's no Name fact to bind -- lookupOperatorSignatureDeclaration :: Text -> [P.Name] -> P.Name -> [P.Name] -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupOperatorSignatureDeclaration anchor ns (P.Name o) ps quals = vars $ \(decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (fname :: Angle Cxx.FunctionName) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ fname .= predicate @Cxx.FunctionName (operatorQ o), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDeclaration ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"qualifiers" (qualifiersQ quals) $ field @"decl" decl end) ] <> entityDeclFooter anchor decl entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps lookupOperatorSignatureDefinition :: Text -> [P.Name] -> P.Name -> [P.Name] -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupOperatorSignatureDefinition anchor ns (P.Name o) ps quals = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (fname :: Angle Cxx.FunctionName) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ fname .= predicate @Cxx.FunctionName (operatorQ o), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDefinition ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (paramTypesQ params)) $ field @"qualifiers" (qualifiersQ quals) $ field @"entity" entity end) ] <> entityFooter anchor entity codeEntity file rangespan lname) where scopes = P.unNames ns params = P.unNames ps -- -- Like functions, but there's no Name fact to bind -- lookupTypeOperatorSignatureDeclaration :: Text -> [P.Name] -> P.Name -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupTypeOperatorSignatureDeclaration anchor ns (P.Name retTy) quals = vars $ \(decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (tyFact :: Angle Cxx.Type) (fname :: Angle Cxx.FunctionName) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ tyFact .= predicate @Cxx.Type (string retTy), fname .= predicate @Cxx.FunctionName (alt @"conversionOperator" (asPredicate tyFact)), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDeclaration ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (returnTypeQ tyFact)) $ field @"qualifiers" (qualifiersQ quals) $ field @"decl" decl end) ] <> entityDeclFooter anchor decl entity codeEntity file rangespan lname) where scopes = P.unNames ns lookupTypeOperatorSignatureDefinition :: Text -> [P.Name] -> P.Name -> Set P.Qualifier -> Angle (ResultLocation Cxx.Entity) lookupTypeOperatorSignatureDefinition anchor ns (P.Name retTy) quals = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (tyFact :: Angle Cxx.Type) (fname :: Angle Cxx.FunctionName) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ([ tyFact .= predicate @Cxx.Type (string retTy), fname .= predicate @Cxx.FunctionName (alt @"conversionOperator" (asPredicate tyFact)), scope .= sig (scopeQ (reverse scopes)), wild .= predicate @SymbolId.LookupFunctionSignatureQualifierDefinition ( rec $ field @"name" (asPredicate fname) $ field @"scope" scope $ field @"signature" (asPredicate (returnTypeQ tyFact)) $ field @"qualifiers" (qualifiersQ quals) $ field @"entity" entity end) ] <> entityFooter anchor entity codeEntity file rangespan lname) where scopes = P.unNames ns -- -- We have four variants, and two ways to resolve each -- -- - record, variable, enum, type , using -- - functions (and function-like things) -- - namespaces -- - enumerators -- -- And for the first 3, a defn version as well. -- -- -- Declarations of records, variables, enums, type , using directives -- n.b. a lot of variables are not considered "Definitions" (e.g. local/auto) -- so they are only discoverable through decl search -- lookupDeclaration :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupDeclaration anchor ns (P.Name name) = vars $ \ (decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ( (scope .= sig (scopeQ (reverse scopes))):( wild .= predicate @SymbolId.LookupDeclaration ( rec $ field @"name" (string name) $ field @"scope" scope $ field @"decl" decl end)) : entityDeclFooter anchor decl entity codeEntity file rangespan lname ) where scopes = P.unNames ns -- -- Declarations of functions, including regular named functions, operators, -- literl operators, constructors (anonymous), destructors (anonymous), and -- type conversion operators. -- -- Note things like variables, within a function, have a FunctionQName scope -- but are not FunctionName-indexed -- lookupFunctionDeclaration :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupFunctionDeclaration anchor ns (P.Name name) = vars $ \ (decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) (scope :: Angle Cxx.Scope) -> tuple (entity, file, rangespan, lname) `where_` ( (scope .= sig (scopeQ (reverse scopes))):( wild .= predicate @SymbolId.LookupFunctionDeclaration ( rec $ field @"name" (functionName name) $ -- scopeQuery: too generic? can this ever be local or a function? field @"scope" scope $ field @"decl" decl end)) : entityDeclFooter anchor decl entity codeEntity file rangespan lname ) where scopes = P.unNames ns -- -- Namespaces are a bit like regular scopes but they can be anonymous. -- This is a "" in the symbol id, corresponding to a nothing in the query -- lookupNamespaceDeclaration :: Text -> [P.Name] -> P.Name -> Angle (ResultLocation Cxx.Entity) lookupNamespaceDeclaration anchor ns (P.Name name) = vars $ \ (decl :: Angle Cxx.Declaration) (entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) -> tuple (entity, file, rangespan, lname) `where_` (( wild .= predicate @SymbolId.LookupNamespaceDeclaration ( rec $ field @"name" (maybeName name) $ field @"parent" (namespaceParentQName (reverse scopes)) $ field @"decl" decl end)) : entityDeclFooter anchor decl entity codeEntity file rangespan lname ) where scopes = P.unNames ns -- -- AngleStatement helpers, to generate query fragments -- lookupEntityFn :: Angle.AngleVars (Angle Cxx.Entity -> Angle Code.Entity -> Angle Src.File -> Angle Code.RangeSpan -> Angle Text -> Angle (Cxx.Entity, Src.File, Code.RangeSpan, Text)) r => (P.Name -> [P.Name] -> Angle Cxx.Entity -> Angle t) -> Text -> [P.Name] -> P.Name -> Angle r lookupEntityFn pred anchor ns name = vars $ \(entity :: Angle Cxx.Entity) (codeEntity :: Angle Code.Entity) (file :: Angle Src.File) (rangespan :: Angle Code.RangeSpan) (lname :: Angle Text) -> tuple (entity, file, rangespan, lname) `where_` (( wild .= pred name ns entity) : entityFooter anchor entity codeEntity file rangespan lname ) entityDeclFooter :: Text -> Angle Cxx.Declaration -> Angle Cxx.Entity -> Angle Code.Entity -> Angle Src.File -> Angle Code.RangeSpan -> Angle Text -> [AngleStatement] entityDeclFooter anchor decl entity codeEntity file rangespan lname = (alt @"decl" decl .= sig entity) : entityFooter anchor entity codeEntity file rangespan lname entityFooter :: Text -> Angle Cxx.Entity -> Angle Code.Entity -> Angle Src.File -> Angle Code.RangeSpan -> Angle Text -> [AngleStatement] entityFooter anchor entity codeEntity file rangespan lname = [ alt @"cxx" entity .= sig codeEntity , entityLocation codeEntity file rangespan lname ] ++ -- refine to specific sub-repo if we have a prefix [file .= predicate @Src.File (stringPrefix anchor) | not (Text.null anchor)] -- -- Scope queries -- -- These will never be empty strings functionName :: Text -> Angle Cxx.FunctionName_key functionName name = alt @"name" (string name) .| alt @"operator_" (string name) .| alt @"literalOperator" (string name) .| alt @"conversionOperator" (string name) operatorQ :: Text -> Angle Cxx.FunctionName_key operatorQ name = alt @"operator_" (string name) .| alt @"literalOperator" (string name) -- -- For namespaces, which may have anonymous components -- maybeName :: Text -> Angle (Maybe Cxx.Name) maybeName "" = nothing maybeName n = just (predicate (string n)) namespaceParentQName :: [Text] -> Angle (Maybe Cxx.NamespaceQName) namespaceParentQName [] = nothing namespaceParentQName (n:ns) = just $ predicate $ rec $ field @"name" (maybeName n) $ field @"parent" (namespaceParentQName ns) end namespaceQName :: [Text] -> Text -> Angle Cxx.NamespaceQName_key namespaceQName ns n = rec $ field @"name" (maybeName n) $ field @"parent" (namespaceParentQName ns) end functionQName :: Angle Cxx.Scope -> Text -> Angle Cxx.FunctionQName_key functionQName scope_ns ".ctor" = -- hard coded tokens. fix. rec $ field @"name" (alt @"constructor" wild) $ field @"scope" scope_ns end functionQName scope_ns ".dtor" = -- hard coded tokens rec $ field @"name" (alt @"destructor" wild) $ field @"scope" scope_ns end functionQName scope_ns n = rec $ field @"name" (functionName n) $ -- i suspect we have params to constrs here field @"scope" scope_ns end -- -- Scope queries. There are lots of alternatives, recursively, unfortunately -- scopeQ :: [Text] -> Angle Cxx.Scope scopeQ [] = alt @"global_" wild scopeQ (n:ns) = alt @"namespace_" (namespaceQName ns n) .| ( var $ \scope_ns -> let result = alt @"recordWithAccess" (rec $ field @"record" (rec $ -- anonymous QName field @"name" (string n) $ field @"scope" scope_ns -- I suspect this is too generic end) $ field @"access" ( enum Cxx.Access_Public .| enum Cxx.Access_Protected .| enum Cxx.Access_Private ) end) .| alt @"local" (functionQName scope_ns n) -- too broad, will yield local (global ..) in result `where_` [scopeQ ns .= scope_ns] ) -- -- cxx1.Signature type only of param queries -- Fn where S = cxx1.Scope { -- recordWithAccess = { record = { name = "dynamic", -- scope = { namespace_ = { name = { just = "folly" } }}}}}; -- Fn = symbolid.cxx.LookupFunctionDeclaration { name = { constructor = {} }, -- scope = S, decl = { function_ = -- { signature = { parameters = [{"r","folly::dynamic::Array &&"}] } -- , source = {file = F } } }}; F = src.File "fbcode/".. -- -- Note: params are in the non-left position, so this should always be used -- _after_ matching the FunctionDeclaration -- paramTypesQ :: [Text] -> Angle Cxx.Signature paramTypesQ ps = predicate @Cxx.Signature $ rec $ field @"parameters" (array (map paramQ ps)) end where paramQ :: Text -> Angle Cxx.Parameter paramQ tyStr = rec $ field @"type" (string tyStr) end -- -- return type matching -- returnTypeQ :: Angle Cxx.Type -> Angle Cxx.Signature returnTypeQ retTyQ = predicate @Cxx.Signature $ rec $ field @"returns" (asPredicate retTyQ) end -- -- function signature qualifiers (const &&, volatile etc) -- qualifiersQ :: Set P.Qualifier -> Angle (Maybe Cxx.MethodSignature) qualifiersQ qs | Set.null qs -- if there's no qualifiers its either nothing or all false = sig nothing .| just ( rec $ field @"isVirtual" false $ field @"isConst" false $ field @"isVolatile" false $ field @"refQualifier" (enum Cxx.RefQualifier_None_) end) | otherwise -- its definitely set = just $ sig $ rec $ field @"isVirtual" (bool $ P.Virtual `Set.member` qs) $ field @"isConst" (bool $ P.Const `Set.member` qs) $ field @"isVolatile" (bool $ P.Volatile `Set.member` qs) $ field @"refQualifier" (enum (if P.RefQual P.LValue `Set.member` qs then Cxx.RefQualifier_LValue else if P.RefQual P.RValue `Set.member` qs then Cxx.RefQualifier_RValue else Cxx.RefQualifier_None_ )) end