{- 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. -} module Glean.Clang.Test ( driver, driverWith, Options, Cpp.clangIncremental ) where import qualified Data.Aeson as Aeson import Data.List import System.Directory import System.FilePath import Text.JSON import Glean.Indexer import Glean.Indexer.Cpp import qualified Glean.Indexer.Cpp as Cpp ( clangIncremental ) import Glean.Regression.Snapshot.Driver import Glean.Regression.Snapshot.Transform import Glean.Util.CxxXRef import Debug.Trace (trace) import qualified Data.HashMap.Strict as HM type Options = Clang driverWith :: Bool -> Driver Clang driverWith deriveToo = driver' { driverTransforms = HM.insert "xrefs" (Transform xrefTransform) (driverTransforms driver') } where driver' = driverFromIndexer indexer' baseIndexer = indexerWith deriveToo isSrcFile file = takeExtension file `elem` [".c", ".cpp", ".m", ".mm"] withCompileCommandsFor _opts params f = do srcFiles <- map (indexerRoot params ) . filter isSrcFile <$> listDirectory (indexerRoot params) writeFile (indexerOutput params "compile_commands.json") $ commandsJsonFor (indexerOutput params) srcFiles f (indexerOutput params) indexer' = baseIndexer { indexerRun = \clang backend repo params -> withCompileCommandsFor clang params $ \cdbDir -> indexerRun baseIndexer (clang { clangCompileDBDir = Just cdbDir }) backend repo params } driver :: Driver Clang driver = driverWith False commandsJsonFor :: FilePath -> [FilePath] -> String commandsJsonFor tmpDir srcFiles = ("[" ++) $ (++ "]") ( unlines $ intersperse "," [ unlines [ "{" , " \"directory\": \"" ++ tmpDir ++ "\"," , " \"command\": \"/usr/bin/clang-11 " ++ argsFor srcFile ++ " -o " ++ objFileFor srcFile ++ " -c " ++ srcFile ++ "\"," , " \"file\": \"" ++ srcFile ++ "\"" , "}" ] | srcFile <- srcFiles ] ) where objFileFor srcFile = tmpDir (takeFileName srcFile <.> "o") argsFor srcFile | takeExtension srcFile == ".cpp" = "-std=c++14 -fcoroutines-ts -xc++" | takeExtension srcFile == ".c" = "-std=c99 -xc" | takeExtension srcFile == ".mm" = "-xobjective-c++" | otherwise = "-xobjective-c" xrefTransform :: Unit -> [JSValue] -> [JSValue] xrefTransform _ = map go where go jsval = case transformXRefs jsval of Ok x -> x Error msg -> trace ("xrefTransform error: " ++ show msg) jsval -- with aeson <2, () isn't a valid decoding of -- [] and {}, which xrefTransform apparently runs into, -- so we embed our ()-like little helper that can -- always be decoded. -- (problem is fixed with aeson >= 2) data Unit = Unit instance Aeson.FromJSON Unit where parseJSON _ = pure Unit