1
1
mirror of https://github.com/github/semantic.git synced 2024-11-22 23:29:37 +03:00

Rework tagging to compute LSP offsets

Also updates how we generate the line of source code for display
This commit is contained in:
Timothy Clem 2020-06-25 14:38:33 -07:00
parent 255d78cd8f
commit e591457a4c
13 changed files with 164 additions and 210 deletions

View File

@ -17,12 +17,10 @@ import AST.Traversable1
import Control.Effect.Reader import Control.Effect.Reader
import Control.Effect.Writer import Control.Effect.Writer
import Data.Foldable (for_) import Data.Foldable (for_)
import Data.Text (Text)
import qualified Language.CodeQL.AST as CodeQL import qualified Language.CodeQL.AST as CodeQL
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -56,17 +54,12 @@ gtags ::
m () m ()
gtags = traverse1_ @ToTags (const (pure ())) tags gtags = traverse1_ @ToTags (const (pure ())) tags
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name kind ty loc srcLineRange = do
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
instance ToTags CodeQL.Module where instance ToTags CodeQL.Module where
tags tags
t@CodeQL.Module t@CodeQL.Module
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.ModuleName {extraChildren = Parse.Success (CodeQL.SimpleId {text, ann})}) name = Parse.Success (CodeQL.ModuleName {extraChildren = Parse.Success (CodeQL.SimpleId {text, ann})})
} = yieldTag text P.MODULE P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.MODULE P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.ClasslessPredicate where instance ToTags CodeQL.ClasslessPredicate where
@ -74,7 +67,7 @@ instance ToTags CodeQL.ClasslessPredicate where
t@CodeQL.ClasslessPredicate t@CodeQL.ClasslessPredicate
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.PredicateName {text, ann}) name = Parse.Success (CodeQL.PredicateName {text, ann})
} = yieldTag text P.FUNCTION P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.FUNCTION P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.AritylessPredicateExpr where instance ToTags CodeQL.AritylessPredicateExpr where
@ -82,7 +75,7 @@ instance ToTags CodeQL.AritylessPredicateExpr where
t@CodeQL.AritylessPredicateExpr t@CodeQL.AritylessPredicateExpr
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.LiteralId {text, ann}) name = Parse.Success (CodeQL.LiteralId {text, ann})
} = yieldTag text P.CALL P.REFERENCE ann byteRange >> gtags t } = Tags.yield text P.CALL P.REFERENCE ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.Dataclass where instance ToTags CodeQL.Dataclass where
@ -90,7 +83,7 @@ instance ToTags CodeQL.Dataclass where
t@CodeQL.Dataclass t@CodeQL.Dataclass
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.ClassName {text, ann}) name = Parse.Success (CodeQL.ClassName {text, ann})
} = yieldTag text P.CLASS P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.CLASS P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.MemberPredicate where instance ToTags CodeQL.MemberPredicate where
@ -98,7 +91,7 @@ instance ToTags CodeQL.MemberPredicate where
t@CodeQL.MemberPredicate t@CodeQL.MemberPredicate
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.PredicateName {text, ann}) name = Parse.Success (CodeQL.PredicateName {text, ann})
} = yieldTag text P.METHOD P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.METHOD P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.Datatype where instance ToTags CodeQL.Datatype where
@ -106,7 +99,7 @@ instance ToTags CodeQL.Datatype where
t@CodeQL.Datatype t@CodeQL.Datatype
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.ClassName {text, ann}) name = Parse.Success (CodeQL.ClassName {text, ann})
} = yieldTag text P.CLASS P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.CLASS P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.DatatypeBranch where instance ToTags CodeQL.DatatypeBranch where
@ -114,7 +107,7 @@ instance ToTags CodeQL.DatatypeBranch where
t@CodeQL.DatatypeBranch t@CodeQL.DatatypeBranch
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (CodeQL.ClassName {text, ann}) name = Parse.Success (CodeQL.ClassName {text, ann})
} = yieldTag text P.CLASS P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.CLASS P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags CodeQL.ClasslessPredicateCall where instance ToTags CodeQL.ClasslessPredicateCall where
@ -131,7 +124,7 @@ instance ToTags CodeQL.QualifiedRhs where
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = expr name = expr
} = case expr of } = case expr of
Just (EPrj CodeQL.PredicateName {text, ann}) -> yieldTag text P.CALL P.REFERENCE ann byteRange >> gtags t Just (EPrj CodeQL.PredicateName {text, ann}) -> Tags.yield text P.CALL P.REFERENCE ann byteRange >> gtags t
_ -> gtags t _ -> gtags t
instance ToTags CodeQL.TypeExpr where instance ToTags CodeQL.TypeExpr where
@ -140,7 +133,7 @@ instance ToTags CodeQL.TypeExpr where
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = expr name = expr
} = case expr of } = case expr of
Just (EPrj CodeQL.ClassName {text, ann}) -> yieldTag text P.TYPE P.REFERENCE ann byteRange >> gtags t Just (EPrj CodeQL.ClassName {text, ann}) -> Tags.yield text P.TYPE P.REFERENCE ann byteRange >> gtags t
_ -> gtags t _ -> gtags t
instance ToTags CodeQL.AddExpr instance ToTags CodeQL.AddExpr

View File

@ -1,4 +1,5 @@
{-# LANGUAGE DefaultSignatures #-}{-# LANGUAGE DisambiguateRecordFields #-} {-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
@ -15,12 +16,10 @@ import AST.Token
import AST.Traversable1 import AST.Traversable1
import Control.Effect.Reader import Control.Effect.Reader
import Control.Effect.Writer import Control.Effect.Writer
import Data.Text as Text
import qualified Language.Go.AST as Go import qualified Language.Go.AST as Go
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -44,7 +43,7 @@ instance ToTags Go.FunctionDeclaration where
t@Go.FunctionDeclaration t@Go.FunctionDeclaration
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (Go.Identifier {text, ann}) name = Parse.Success (Go.Identifier {text, ann})
} = yieldTag text P.FUNCTION P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.FUNCTION P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags Go.MethodDeclaration where instance ToTags Go.MethodDeclaration where
@ -52,7 +51,7 @@ instance ToTags Go.MethodDeclaration where
t@Go.MethodDeclaration t@Go.MethodDeclaration
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (Go.FieldIdentifier {text, ann}) name = Parse.Success (Go.FieldIdentifier {text, ann})
} = yieldTag text P.METHOD P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.METHOD P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags Go.CallExpression where instance ToTags Go.CallExpression where
@ -68,7 +67,7 @@ instance ToTags Go.CallExpression where
Prj Go.CallExpression {function = Parse.Success (Go.Expression e)} -> match e Prj Go.CallExpression {function = Parse.Success (Go.Expression e)} -> match e
Prj Go.ParenthesizedExpression {extraChildren = Parse.Success (Go.Expression e)} -> match e Prj Go.ParenthesizedExpression {extraChildren = Parse.Success (Go.Expression e)} -> match e
_ -> gtags t _ -> gtags t
yield name loc = yieldTag name P.CALL P.REFERENCE loc byteRange >> gtags t yield name loc = Tags.yield name P.CALL P.REFERENCE loc byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance (ToTags l, ToTags r) => ToTags (l :+: r) where instance (ToTags l, ToTags r) => ToTags (l :+: r) where
@ -86,11 +85,6 @@ gtags ::
m () m ()
gtags = traverse1_ @ToTags (const (pure ())) tags gtags = traverse1_ @ToTags (const (pure ())) tags
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name kind ty loc srcLineRange = do
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
instance ToTags Go.ArgumentList instance ToTags Go.ArgumentList
instance ToTags Go.ArrayType instance ToTags Go.ArrayType

View File

@ -22,7 +22,6 @@ import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Range import Source.Range
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -54,17 +53,14 @@ instance ToTags Java.MethodDeclaration where
name = Parse.Success (Java.Identifier {text, ann}), name = Parse.Success (Java.Identifier {text, ann}),
body body
} = do } = do
src <- ask @Source let srcRange =
let line =
Tags.firstLine
src
range range
{ end = case body of { end = case body of
Just (Parse.Success (Java.Block {ann = Loc Range {end} _})) -> end Just (Parse.Success (Java.Block {ann = Loc Range {end} _})) -> end
Nothing -> end range Nothing -> end range
Just (Parse.Fail _) -> end range Just (Parse.Fail _) -> end range
} }
Tags.yield (Tag text P.METHOD P.DEFINITION ann line Nothing) Tags.yield text P.METHOD P.DEFINITION ann srcRange
gtags t gtags t
tags _ = pure () tags _ = pure ()
@ -78,8 +74,7 @@ instance ToTags Java.ClassDeclaration where
name = Parse.Success (Java.Identifier {text, ann}), name = Parse.Success (Java.Identifier {text, ann}),
body = Parse.Success (Java.ClassBody {ann = Loc Range {start = end} _}) body = Parse.Success (Java.ClassBody {ann = Loc Range {start = end} _})
} = do } = do
src <- ask @Source Tags.yield text P.CLASS P.DEFINITION ann (Range start end)
Tags.yield (Tag text P.CLASS P.DEFINITION ann (Tags.firstLine src (Range start end)) Nothing)
gtags t gtags t
tags _ = pure () tags _ = pure ()
@ -89,8 +84,7 @@ instance ToTags Java.MethodInvocation where
{ ann = Loc {byteRange = range}, { ann = Loc {byteRange = range},
name = Parse.Success (Java.Identifier {text, ann}) name = Parse.Success (Java.Identifier {text, ann})
} = do } = do
src <- ask @Source Tags.yield text P.CALL P.REFERENCE ann range
Tags.yield (Tag text P.CALL P.REFERENCE ann (Tags.firstLine src range) Nothing)
gtags t gtags t
tags _ = pure () tags _ = pure ()
@ -100,17 +94,15 @@ instance ToTags Java.InterfaceDeclaration where
{ ann = Loc {byteRange}, { ann = Loc {byteRange},
name = Parse.Success (Java.Identifier {text, ann}) name = Parse.Success (Java.Identifier {text, ann})
} = do } = do
src <- ask @Source Tags.yield text P.INTERFACE P.DEFINITION ann byteRange
Tags.yield (Tag text P.INTERFACE P.DEFINITION ann (Tags.firstLine src byteRange) Nothing)
gtags t gtags t
tags _ = pure () tags _ = pure ()
instance ToTags Java.InterfaceTypeList where instance ToTags Java.InterfaceTypeList where
tags t@Java.InterfaceTypeList {extraChildren = interfaces} = do tags t@Java.InterfaceTypeList {extraChildren = interfaces} = do
src <- ask @Source
for_ interfaces $ \x -> case x of for_ interfaces $ \x -> case x of
Parse.Success (Java.Type (Prj (Java.UnannotatedType (Prj (Java.SimpleType (Prj Java.TypeIdentifier {ann = loc@Loc {byteRange = range}, text = name})))))) -> Parse.Success (Java.Type (Prj (Java.UnannotatedType (Prj (Java.SimpleType (Prj Java.TypeIdentifier {ann = loc@Loc {byteRange = range}, text = name})))))) ->
Tags.yield (Tag name P.IMPLEMENTATION P.REFERENCE loc (Tags.firstLine src range) Nothing) Tags.yield name P.IMPLEMENTATION P.REFERENCE loc range
_ -> pure () _ -> pure ()
gtags t gtags t

View File

@ -17,12 +17,10 @@ import AST.Token
import AST.Traversable1 import AST.Traversable1
import Control.Effect.Reader import Control.Effect.Reader
import Control.Effect.Writer import Control.Effect.Writer
import Data.Text (Text)
import qualified Language.PHP.AST as PHP import qualified Language.PHP.AST as PHP
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -56,17 +54,12 @@ gtags ::
m () m ()
gtags = traverse1_ @ToTags (const (pure ())) tags gtags = traverse1_ @ToTags (const (pure ())) tags
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name kind ty loc srcLineRange = do
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
instance ToTags PHP.FunctionDefinition where instance ToTags PHP.FunctionDefinition where
tags tags
t@PHP.FunctionDefinition t@PHP.FunctionDefinition
{ PHP.ann = Loc {byteRange}, { PHP.ann = Loc {byteRange},
PHP.name = Parse.Success (PHP.Name {text, ann}) PHP.name = Parse.Success (PHP.Name {text, ann})
} = yieldTag text P.METHOD P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.METHOD P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags PHP.MethodDeclaration where instance ToTags PHP.MethodDeclaration where
@ -74,7 +67,7 @@ instance ToTags PHP.MethodDeclaration where
t@PHP.MethodDeclaration t@PHP.MethodDeclaration
{ PHP.ann = Loc {byteRange}, { PHP.ann = Loc {byteRange},
PHP.name = Parse.Success (PHP.Name {text, ann}) PHP.name = Parse.Success (PHP.Name {text, ann})
} = yieldTag text P.FUNCTION P.DEFINITION ann byteRange >> gtags t } = Tags.yield text P.FUNCTION P.DEFINITION ann byteRange >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags PHP.FunctionCallExpression where instance ToTags PHP.FunctionCallExpression where
@ -84,7 +77,7 @@ instance ToTags PHP.FunctionCallExpression where
PHP.function = func PHP.function = func
} = match func } = match func
where where
yield name loc = yieldTag name P.CALL P.REFERENCE loc byteRange >> gtags t yield name loc = Tags.yield name P.CALL P.REFERENCE loc byteRange >> gtags t
match expr = case expr of match expr = case expr of
EPrj PHP.VariableName {extraChildren = Parse.Success (PHP.Name {text, ann})} -> yield text ann *> gtags t EPrj PHP.VariableName {extraChildren = Parse.Success (PHP.Name {text, ann})} -> yield text ann *> gtags t
EPrj PHP.QualifiedName {extraChildren = [EPrj PHP.Name {text, ann}]} -> yield text ann *> gtags t EPrj PHP.QualifiedName {extraChildren = [EPrj PHP.Name {text, ann}]} -> yield text ann *> gtags t
@ -96,7 +89,7 @@ instance ToTags PHP.MemberCallExpression where
t@PHP.MemberCallExpression t@PHP.MemberCallExpression
{ PHP.ann = Loc {byteRange}, { PHP.ann = Loc {byteRange},
PHP.name = Parse.Success (Prj PHP.Name {text, ann}) PHP.name = Parse.Success (Prj PHP.Name {text, ann})
} = yieldTag text P.CALL P.REFERENCE ann byteRange >> gtags t } = Tags.yield text P.CALL P.REFERENCE ann byteRange >> gtags t
tags t = gtags t tags t = gtags t

View File

@ -18,15 +18,12 @@ import AST.Traversable1
import Control.Effect.Reader import Control.Effect.Reader
import Control.Effect.Writer import Control.Effect.Writer
import Data.Foldable import Data.Foldable
import Data.List.NonEmpty (NonEmpty (..))
import Data.Maybe (listToMaybe)
import Data.Text as Text import Data.Text as Text
import qualified Language.Python.AST as Py import qualified Language.Python.AST as Py
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Range import Source.Range
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -61,7 +58,7 @@ keywordFunctionCall ::
Range -> Range ->
Text -> Text ->
m () m ()
keywordFunctionCall t loc range name = yieldTag name P.FUNCTION P.DEFINITION loc range Nothing >> gtags t keywordFunctionCall t loc range name = Tags.yield name P.FUNCTION P.DEFINITION loc range >> gtags t
instance ToTags Py.String where instance ToTags Py.String where
tags Py.String {extraChildren} = for_ extraChildren $ \x -> case x of tags Py.String {extraChildren} = for_ extraChildren $ \x -> case x of
@ -99,11 +96,9 @@ instance ToTags Py.FunctionDefinition where
t@Py.FunctionDefinition t@Py.FunctionDefinition
{ ann = Loc {byteRange = Range {start}}, { ann = Loc {byteRange = Range {start}},
name = Parse.Success (Py.Identifier {text, ann}), name = Parse.Success (Py.Identifier {text, ann}),
body = Parse.Success (Py.Block {ann = Loc Range {start = end} _, extraChildren}) body = Parse.Success (Py.Block {ann = Loc Range {start = end} _})
} = do } = do
src <- ask @Source Tags.yield text P.FUNCTION P.DEFINITION ann (Range start end) >> gtags t
let docs = listToMaybe extraChildren >>= docComment src
yieldTag text P.FUNCTION P.DEFINITION ann (Range start end) docs >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags Py.ClassDefinition where instance ToTags Py.ClassDefinition where
@ -111,11 +106,9 @@ instance ToTags Py.ClassDefinition where
t@Py.ClassDefinition t@Py.ClassDefinition
{ ann = Loc {byteRange = Range {start}}, { ann = Loc {byteRange = Range {start}},
name = Parse.Success (Py.Identifier {text, ann}), name = Parse.Success (Py.Identifier {text, ann}),
body = Parse.Success (Py.Block {ann = Loc Range {start = end} _, extraChildren}) body = Parse.Success (Py.Block {ann = Loc Range {start = end} _})
} = do } = do
src <- ask @Source Tags.yield text P.CLASS P.DEFINITION ann (Range start end) >> gtags t
let docs = listToMaybe extraChildren >>= docComment src
yieldTag text P.CLASS P.DEFINITION ann (Range start end) docs >> gtags t
tags _ = pure () tags _ = pure ()
instance ToTags Py.Call where instance ToTags Py.Call where
@ -131,35 +124,9 @@ instance ToTags Py.Call where
Prj Py.Call {function = Parse.Success (Py.PrimaryExpression expr')} -> match expr' -- Nested call expression like this in Python represent creating an instance of a class and calling it: e.g. AClass()() Prj Py.Call {function = Parse.Success (Py.PrimaryExpression expr')} -> match expr' -- Nested call expression like this in Python represent creating an instance of a class and calling it: e.g. AClass()()
Prj (Py.ParenthesizedExpression _ (Parse.Success (Prj (Py.Expression (Prj (Py.PrimaryExpression expr')))))) -> match expr' -- Parenthesized expressions Prj (Py.ParenthesizedExpression _ (Parse.Success (Prj (Py.Expression (Prj (Py.PrimaryExpression expr')))))) -> match expr' -- Parenthesized expressions
_ -> gtags t _ -> gtags t
yield name loc = yieldTag name P.CALL P.REFERENCE loc byteRange Nothing >> gtags t yield name loc = Tags.yield name P.CALL P.REFERENCE loc byteRange >> gtags t
tags _ = pure () tags _ = pure ()
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> Maybe Text -> m ()
yieldTag name kind ty loc srcLineRange docs = do
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) docs)
docComment :: Source -> Parse.Err ((Py.CompoundStatement :+: Py.SimpleStatement) Loc) -> Maybe Text
docComment
src
( Parse.Success
( R1
( Py.SimpleStatement
( Prj
Py.ExpressionStatement
{ extraChildren =
Parse.Success
( L1
(Prj (Py.Expression (Prj (Py.PrimaryExpression (Prj Py.String {ann})))))
)
:| _
}
)
)
)
) = Just (toText (slice src (byteRange ann)))
docComment _ _ = Nothing
gtags :: gtags ::
( Has (Reader Source) sig m, ( Has (Reader Source) sig m,
Has (Writer Tags.Tags) sig m, Has (Writer Tags.Tags) sig m,

View File

@ -29,7 +29,6 @@ import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Range as Range import Source.Range as Range
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -75,9 +74,7 @@ nameBlacklist =
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m () yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure () yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure ()
yieldTag name kind ty loc srcLineRange = do yieldTag name kind ty loc srcLineRange = Tags.yield name kind ty loc srcLineRange
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
instance ToTags Rb.Class where instance ToTags Rb.Class where
tags tags
@ -213,7 +210,7 @@ instance ToTags Rb.Lambda where
instance ToTags Rb.If where instance ToTags Rb.If where
tags Rb.If {condition = Parse.Success cond, consequence, alternative} = do tags Rb.If {condition = Parse.Success cond, consequence, alternative} = do
tags cond tags cond
case consequence of case consequence of
Just (Parse.Success cons) -> tags cons Just (Parse.Success cons) -> tags cons
_ -> pure () _ -> pure ()
case alternative of case alternative of
@ -224,7 +221,7 @@ instance ToTags Rb.If where
instance ToTags Rb.Elsif where instance ToTags Rb.Elsif where
tags Rb.Elsif {condition = Parse.Success cond, consequence, alternative} = do tags Rb.Elsif {condition = Parse.Success cond, consequence, alternative} = do
tags cond tags cond
case consequence of case consequence of
Just (Parse.Success cons) -> tags cons Just (Parse.Success cons) -> tags cons
_ -> pure () _ -> pure ()
case alternative of case alternative of
@ -235,7 +232,7 @@ instance ToTags Rb.Elsif where
instance ToTags Rb.Unless where instance ToTags Rb.Unless where
tags Rb.Unless {condition = Parse.Success cond, consequence, alternative} = do tags Rb.Unless {condition = Parse.Success cond, consequence, alternative} = do
tags cond tags cond
case consequence of case consequence of
Just (Parse.Success cons) -> tags cons Just (Parse.Success cons) -> tags cons
_ -> pure () _ -> pure ()
case alternative of case alternative of

View File

@ -1,17 +1,23 @@
module Tags.Tag (Tag (..)) where module Tags.Tag (Tag (..), UTF16CodeUnitSpan, OneIndexedSpan) where
import Data.Text (Text) import Data.Text (Text)
import qualified Proto.Semantic as P import qualified Proto.Semantic as P
import Source.Loc import Source.Loc
-- | A 0-indxed Span where the column offset units are utf-16 code units (2
-- bytes), suitable for the LSP (Language Server Protocol) specification.
type UTF16CodeUnitSpan = Span
-- A 1-indexed Span where the units are bytes.
type OneIndexedSpan = Span
data Tag data Tag
= Tag = Tag
{ tagName :: Text, { tagName :: Text,
tagSyntaxType :: P.SyntaxType, tagSyntaxType :: P.SyntaxType,
tagNodeType :: P.NodeType, tagNodeType :: P.NodeType,
tagLoc :: Loc, tagSpan :: OneIndexedSpan,
tagLine :: Text, tagLine :: Text,
tagDocs :: Maybe Text, tagLspSpan :: UTF16CodeUnitSpan
tagLspSpan :: Span
} }
deriving (Eq, Show) deriving (Eq, Show)

View File

@ -1,12 +1,12 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeApplications #-}
module Tags.Tagging.Precise module Tags.Tagging.Precise
( Tags ( Tags
, Tag(..) , Tag(..)
, ToTags(..) , ToTags(..)
, yield , yield
, runTagging , runTagging
, firstLine , calculateLineAndSpans
, firstLineAndSpans
, surroundingLine , surroundingLine
, surroundingLineRange , surroundingLineRange
) where ) where
@ -16,12 +16,14 @@ import Control.Carrier.Reader
import Control.Carrier.Writer.Strict import Control.Carrier.Writer.Strict
import Data.Functor.Identity import Data.Functor.Identity
import Data.Monoid (Endo (..)) import Data.Monoid (Endo (..))
import Data.Text as Text (Text, take, takeWhile, stripEnd, foldr, take) import Data.Text as Text (Text, take, strip, foldr, take)
import Prelude hiding (span) import Prelude hiding (span)
import Source.Loc import Source.Loc
import Source.Span (Pos(..), start, end) import Source.Span (Pos(..), start, end)
import Source.Source as Source import Source.Source as Source
import qualified Source.Range as Range (start)
import Tags.Tag import Tags.Tag
import qualified Proto.Semantic as P
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Data.Bits ((.&.)) import Data.Bits ((.&.))
@ -33,10 +35,24 @@ class ToTags t where
tags :: Source -> t Loc -> [Tag] tags :: Source -> t Loc -> [Tag]
yield :: Has (Writer Tags) sig m => Tag -> m () -- yield :: Has (Writer Tags) sig m => Tag -> m ()
yield = tell . Endo . (:) . modSpan toOneIndexed where -- yield = tell . Endo . (:) . modSpan toOneIndexed where
modSpan f t@Tag{ tagLoc = l } = t { tagLoc = l { span = f (span l) } } -- modSpan f t@Tag{ tagLoc = l } = t { tagLoc = l { span = f (span l) } }
toOneIndexed (Span (Pos l1 c1) (Pos l2 c2)) = Span (Pos (l1 + 1) (c1 + 1)) (Pos (l2 + 1) (c2 + 1)) -- toOneIndexed (Span (Pos l1 c1) (Pos l2 c2)) = Span (Pos (l1 + 1) (c1 + 1)) (Pos (l2 + 1) (c2 + 1))
yield ::
(Has (Reader Source) sig m, Has (Writer Tags) sig m) =>
Text -> -- |^ Text of the identifier
P.SyntaxType -> -- |^ Type of syntax
P.NodeType -> -- |^ Node type: definition or reference
Loc -> -- |^ Location of the identifier
Range -> -- |^ Range of the entire expression (not used, but reserved for future used)
m ()
yield name syntaxType nodeType loc _ = do
src <- ask @Source
let (line, span, lspSpan) = calculateLineAndSpans src loc
tell . Endo . (:) $
Tag name syntaxType nodeType span line lspSpan
runTagging :: Source -> ReaderC Source (WriterC Tags Identity) () -> [Tag] runTagging :: Source -> ReaderC Source (WriterC Tags Identity) () -> [Tag]
runTagging source runTagging source
@ -46,27 +62,19 @@ runTagging source
. execWriter . execWriter
. runReader source . runReader source
-- | Slices a range out of 'Source' and gives back the first line of source up to 180 characters.
firstLine :: Source -> Range -> Text
firstLine src = Text.stripEnd . Text.take 180 . Text.takeWhile (/= '\n') . Source.toText . slice src
-- A 1-indexed Span where the units are bytes.
type OneIndexedSpan = Span
-- | A 0-indxed Span where the units are utf-16 code units (2 bytes), suitable for the LSP (Language Server Protocol) specification
type UTF16CodeUnitSpan = Span
-- | Takes a Loc (where the span's column offset is measured in bytes) and -- | Takes a Loc (where the span's column offset is measured in bytes) and
-- returns two Spans: A 1-indexed span LSP friendly span (where column offset is measure in utf16 code -- returns two Spans: A 1-indexed span LSP friendly span (where column offset is
-- units). -- measure in utf16 code units).
firstLineAndSpans :: Source -> Loc -> (Text, OneIndexedSpan, UTF16CodeUnitSpan) calculateLineAndSpans ::
firstLineAndSpans src Loc {byteRange, span = span@Span {start = start@Pos {column = startCol}, end = end@Pos {column = endCol}}} = Source -> -- |^ Source
Loc -> -- |^ Location of identifier
(Text, OneIndexedSpan, UTF16CodeUnitSpan)
calculateLineAndSpans src Loc {byteRange = srcRange, span = span@Span {start = start@Pos {column = startCol}, end = end@Pos {column = endCol}}} =
(line, toOneIndexed span, Span start {column = utf16cpStartOffset} end {column = utf16cpEndOffset}) (line, toOneIndexed span, Span start {column = utf16cpStartOffset} end {column = utf16cpEndOffset})
where where
-- NB: Important to limit to 180 characters after converting to text so as -- NB: Important to limit to 180 characters after converting to text so as not to take in the middle of a multi-byte character.
-- not to take in the middle of a multi-byte character. line = Text.strip . Text.take 180 . Source.toText $ srcLine
line = Text.stripEnd . Text.take 180 . Source.toText $ srcLine srcLine = surroundingLine src srcRange
srcLine = surroundingLine src byteRange
toOneIndexed (Span (Pos l1 c1) (Pos l2 c2)) = Span (Pos (l1 + 1) (c1 + 1)) (Pos (l2 + 1) (c2 + 1)) toOneIndexed (Span (Pos l1 c1) (Pos l2 c2)) = Span (Pos (l1 + 1) (c1 + 1)) (Pos (l2 + 1) (c2 + 1))
utf16cpStartOffset = countUtf16CodeUnits startSlice utf16cpStartOffset = countUtf16CodeUnits startSlice
@ -87,16 +95,16 @@ countUtf16CodeUnits = Text.foldr len 0 . Source.toText
-- | The Source of the entire surrounding line. -- | The Source of the entire surrounding line.
surroundingLine :: Source -> Range -> Source surroundingLine :: Source -> Range -> Source
surroundingLine src = Source.slice src . surroundingLineRange src surroundingLine src = Source.slice src . surroundingLineRange src . Range.start
-- | Find the Range of the line surrounding the given Range where a line is defined by `\n`, `\r\n`, or `\r`. -- | Find the Range of the line surrounding the given Position where a line is defined by `\n`, `\r\n`, or `\r`.
surroundingLineRange :: Source -> Range -> Range surroundingLineRange :: Source -> Int -> Range
surroundingLineRange src (Range start end) = Range lineStart lineEnd surroundingLineRange src start = Range lineStart lineEnd
where where
lineStart = maybe start (start -) $ B.elemIndex lfChar precedingSource <|> B.elemIndex crChar precedingSource lineStart = maybe 0 (start -) $ B.elemIndex lfChar precedingSource <|> B.elemIndex crChar precedingSource
precedingSource = B.reverse $ bytes (Source.slice src (Range 0 start)) precedingSource = B.reverse $ bytes (Source.slice src (Range 0 start))
lineEnd = maybe end (start +) $ B.elemIndex crChar remainingSource <|> B.elemIndex lfChar remainingSource lineEnd = maybe eof (start +) $ B.elemIndex crChar remainingSource <|> B.elemIndex lfChar remainingSource
remainingSource = bytes $ Source.slice src (Range start eof) remainingSource = bytes $ Source.slice src (Range start eof)
lfChar = toEnum (ord '\n') lfChar = toEnum (ord '\n')

View File

@ -19,50 +19,49 @@ main = defaultMain $ testGroup "semantic-tags" [ testTree ]
testTree :: Tasty.TestTree testTree :: Tasty.TestTree
testTree = Tasty.testGroup "Tags.Tagging.Precise" testTree = Tasty.testGroup "Tags.Tagging.Precise"
[ Tasty.testGroup "firstLineAndSpans" [ Tasty.testGroup "firstLineAndSpans"
[ testCase "ascii" $ [ testCase "one line" $
( " 'a'.hi" let src = Source.fromText "def foo;end"
, Span (Pos 2 7) (Pos 2 9) -- one indexed, counting bytes loc = Loc (Range 4 7) (Span (Pos 0 4) (Pos 0 7))
, Span (Pos 1 6) (Pos 1 8)) -- zero-indexed, counting utf16 code units (lsp-style column offset) in ( "def foo;end"
@=? , Span (Pos 1 5) (Pos 1 8) -- one indexed, counting bytes
firstLineAndSpans (Source.fromText "def foo\n 'a'.hi\nend\n") (Loc (Range 14 16) (Span (Pos 1 6) (Pos 1 8))) , Span (Pos 0 4) (Pos 0 7) -- zero-indexed, counting utf16 code units (lsp-style column offset)
-- 0123456 789 ) @=? calculateLineAndSpans src loc
-- 10 ~~~^
-- 11 ~~~~^
-- 12 ~~~~~^
, testCase "unicode" $
( " 'à'.hi"
, Span (Pos 2 8) (Pos 2 10) -- one indexed, counting bytes
, Span (Pos 1 6) (Pos 1 8)) -- zero-indexed, counting utf16 code units (lsp-style column offset)
@=?
firstLineAndSpans (Source.fromText "def foo\n 'à'.hi\nend\n") (Loc (Range 15 17) (Span (Pos 1 7) (Pos 1 9)))
-- 0123456 789
-- 10 ~~~^
-- 11, 12 ~~~~^
-- 13 ~~~~~^
, testCase "multi code point unicode" $
( " '💀'.hi"
, Span (Pos 2 10) (Pos 2 12) -- one indexed, counting bytes
, Span (Pos 1 7) (Pos 1 9)) -- zero-indexed, counting utf16 code units (lsp-style column offset)
@=?
firstLineAndSpans (Source.fromText "def foo\n '💀'.hi\nend\n") (Loc (Range 17 19) (Span (Pos 1 9) (Pos 1 11)))
-- 0123456 789
-- 10 ~~~^
-- 11, 12, 13, 14 ~~~~^
-- 15 ~~~~~^
-- NB: This emoji cannot be entered into a string literal in haskell for some reason, you'll get: , testCase "ascii" $
let src = Source.fromText "def foo\n 'a'.hi\nend\n"
loc = Loc (Range 14 16) (Span (Pos 1 6) (Pos 1 8))
in ( "'a'.hi"
, Span (Pos 2 7) (Pos 2 9) -- one indexed, counting bytes
, Span (Pos 1 6) (Pos 1 8) -- zero-indexed, counting utf16 code units (lsp-style column offset)
) @=? calculateLineAndSpans src loc
, testCase "unicode" $
let src = Source.fromText "def foo\n 'à'.hi\nend\n"
loc = Loc (Range 15 17) (Span (Pos 1 7) (Pos 1 9))
in ( "'à'.hi"
, Span (Pos 2 8) (Pos 2 10) -- one indexed, counting bytes
, Span (Pos 1 6) (Pos 1 8) -- zero-indexed, counting utf16 code units (lsp-style column offset)
) @=? calculateLineAndSpans src loc
, testCase "multi code point unicode" $
let src = Source.fromText "def foo\n '💀'.hi\nend\n"
loc = Loc (Range 17 19) (Span (Pos 1 9) (Pos 1 11))
in ( "'💀'.hi"
, Span (Pos 2 10) (Pos 2 12) -- one indexed, counting bytes
, Span (Pos 1 7) (Pos 1 9) -- zero-indexed, counting utf16 code units (lsp-style column offset)
) @=? calculateLineAndSpans src loc
-- NB: This emoji (:man-woman-girl-girl:) cannot be entered into a string literal in haskell for some reason, you'll get:
-- > lexical error in string/character literal at character '\8205' -- > lexical error in string/character literal at character '\8205'
-- The work around is to enter the unicode directly. -- The work around is to enter the unicode directly (7 code points).
-- utf-8: 25 bytes to represent -- utf-8: 25 bytes to represent
-- utf-16: 24 bytes to represent -- utf-16: 23 bytes to represent
, testCase "multi code point unicode :man-woman-girl-girl:" $ , testCase "multi code point unicode :man-woman-girl-girl:" $
( " '\128104\8205\128105\8205\128103\8205\128103'.hi" let src = Source.fromText "def foo\n '\128104\8205\128105\8205\128103\8205\128103'.hi\nend\n"
, Span (Pos 2 31) (Pos 2 33) -- one indexed, counting bytes loc = Loc (Range 38 40) (Span (Pos 1 30) (Pos 1 32))
, Span (Pos 1 16) (Pos 1 18)) -- zero-indexed, counting utf16 code units (lsp-style column offset) in ( "'\128104\8205\128105\8205\128103\8205\128103'.hi"
@=? , Span (Pos 2 31) (Pos 2 33) -- one indexed, counting bytes
firstLineAndSpans (Source.fromText "def foo\n '\128104\8205\128105\8205\128103\8205\128103'.hi\nend\n") (Loc (Range 38 40) (Span (Pos 1 30) (Pos 1 32))) , Span (Pos 1 16) (Pos 1 18) -- zero-indexed, counting utf16 code units (lsp-style column offset)
-- 0123456 789 ) @=? calculateLineAndSpans src loc
-- 10 ~~~^
-- 11-35 ~~~~^
] ]
] ]

View File

@ -23,7 +23,6 @@ import qualified Language.TSX.AST as Tsx
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags t where class ToTags t where
@ -148,9 +147,7 @@ nameBlacklist = ["require"]
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m () yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure () yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure ()
yieldTag name kind ty loc srcLineRange = do yieldTag name kind ty loc srcLineRange = Tags.yield name kind ty loc srcLineRange
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
{- ORMOLU_DISABLE -} {- ORMOLU_DISABLE -}
instance ToTags Tsx.AbstractClassDeclaration instance ToTags Tsx.AbstractClassDeclaration

View File

@ -26,7 +26,6 @@ import qualified Language.TypeScript.AST as Ts
import Proto.Semantic as P import Proto.Semantic as P
import Source.Loc import Source.Loc
import Source.Source as Source import Source.Source as Source
import Tags.Tag
import qualified Tags.Tagging.Precise as Tags import qualified Tags.Tagging.Precise as Tags
class ToTags (t :: * -> *) where class ToTags (t :: * -> *) where
@ -152,9 +151,7 @@ nameBlacklist = ["require"]
yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m () yieldTag :: (Has (Reader Source) sig m, Has (Writer Tags.Tags) sig m) => Text -> P.SyntaxType -> P.NodeType -> Loc -> Range -> m ()
yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure () yieldTag name P.CALL _ _ _ | name `elem` nameBlacklist = pure ()
yieldTag name kind ty loc srcLineRange = do yieldTag name kind ty loc srcLineRange = Tags.yield name kind ty loc srcLineRange
src <- ask @Source
Tags.yield (Tag name kind ty loc (Tags.firstLine src srcLineRange) Nothing)
{- ORMOLU_DISABLE -} {- ORMOLU_DISABLE -}
instance ToTags Ts.AbstractClassDeclaration instance ToTags Ts.AbstractClassDeclaration

View File

@ -76,8 +76,8 @@ parseSymbols blobs = do
& P.nodeType .~ tagNodeType tag & P.nodeType .~ tagNodeType tag
& P.syntaxType .~ tagSyntaxType tag & P.syntaxType .~ tagSyntaxType tag
& P.line .~ tagLine tag & P.line .~ tagLine tag
& P.maybe'span ?~ converting # Loc.span (tagLoc tag) & P.maybe'span ?~ converting # tagSpan tag
& P.maybe'docs .~ fmap (flip (set P.docstring) defMessage) (tagDocs tag) & P.maybe'lspSpan ?~ converting # tagLspSpan tag
where where
toKind = toTitle . pack . show . tagSyntaxType toKind = toTitle . pack . show . tagSyntaxType

View File

@ -14,80 +14,91 @@ spec = do
describe "go" $ do describe "go" $ do
it "produces tags for functions with docs (TODO)" $ it "produces tags for functions with docs (TODO)" $
parseTestFile [P.FUNCTION] (Path.relFile "test/fixtures/go/tags/simple_functions.go") `shouldReturn` parseTestFile [P.FUNCTION] (Path.relFile "test/fixtures/go/tags/simple_functions.go") `shouldReturn`
[ Tag "TestFromBits" P.FUNCTION P.DEFINITION (Loc (Range 56 68) (Span (Pos 6 6) (Pos 6 18))) "func TestFromBits(t *testing.T) {" Nothing [ Tag "TestFromBits" P.FUNCTION P.DEFINITION (Span (Pos 6 6) (Pos 6 18)) "func TestFromBits(t *testing.T) {" (Span (Pos 5 5) (Pos 5 17))
, Tag "Hi" P.FUNCTION P.DEFINITION (Loc (Range 99 101) (Span (Pos 10 6) (Pos 10 8))) "func Hi() {" Nothing ] , Tag "Hi" P.FUNCTION P.DEFINITION (Span (Pos 10 6) (Pos 10 8)) "func Hi() {" (Span (Pos 9 5) (Pos 9 7))
]
it "produces tags for methods" $ it "produces tags for methods" $
parseTestFile [] (Path.relFile "test/fixtures/go/tags/method.go") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/go/tags/method.go") `shouldReturn`
[ Tag "CheckAuth" P.METHOD P.DEFINITION (Loc (Range 39 48) (Span (Pos 3 21) (Pos 3 30))) "func (c *apiClient) CheckAuth(req *http.Request, user, repo string) (*authenticatedActor, error) {}" Nothing] [ Tag "CheckAuth" P.METHOD P.DEFINITION (Span (Pos 3 21) (Pos 3 30)) "func (c *apiClient) CheckAuth(req *http.Request, user, repo string) (*authenticatedActor, error) {}" (Span (Pos 2 20) (Pos 2 29))
]
it "produces tags for calls" $ it "produces tags for calls" $
parseTestFile [P.CALL] (Path.relFile "test/fixtures/go/tags/simple_functions.go") `shouldReturn` parseTestFile [P.CALL] (Path.relFile "test/fixtures/go/tags/simple_functions.go") `shouldReturn`
[ Tag "Hi" P.CALL P.REFERENCE (Loc (Range 86 88) (Span (Pos 7 2) (Pos 7 4))) "Hi()" Nothing] [ Tag "Hi" P.CALL P.REFERENCE (Span (Pos 7 2) (Pos 7 4)) "Hi()" (Span (Pos 6 1) (Pos 6 3))
]
describe "javascript and typescript" $ do describe "javascript and typescript" $ do
it "produces tags for functions with docs (TODO)" $ it "produces tags for functions with docs (TODO)" $
parseTestFile [] (Path.relFile "test/fixtures/javascript/tags/simple_function_with_docs.js") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/javascript/tags/simple_function_with_docs.js") `shouldReturn`
[ Tag "myFunction" P.FUNCTION P.DEFINITION (Loc (Range 31 41) (Span (Pos 2 10) (Pos 2 20))) "function myFunction() {" Nothing ] [ Tag "myFunction" P.FUNCTION P.DEFINITION (Span (Pos 2 10) (Pos 2 20)) "function myFunction() {" (Span (Pos 1 9) (Pos 1 19))
]
it "produces tags for classes" $ it "produces tags for classes" $
parseTestFile [] (Path.relFile "test/fixtures/typescript/tags/class.ts") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/typescript/tags/class.ts") `shouldReturn`
[ Tag "FooBar" P.CLASS P.DEFINITION (Loc (Range 6 12) (Span (Pos 1 7) (Pos 1 13))) "class FooBar {}" Nothing ] [ Tag "FooBar" P.CLASS P.DEFINITION (Span (Pos 1 7) (Pos 1 13)) "class FooBar {}" (Span (Pos 0 6) (Pos 0 12))
]
it "produces tags for modules" $ it "produces tags for modules" $
parseTestFile [] (Path.relFile "test/fixtures/typescript/tags/module.ts") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/typescript/tags/module.ts") `shouldReturn`
[ Tag "APromise" P.MODULE P.DEFINITION (Loc (Range 7 15) (Span (Pos 1 8) (Pos 1 16))) "module APromise { }" Nothing ] [ Tag "APromise" P.MODULE P.DEFINITION (Span (Pos 1 8) (Pos 1 16)) "module APromise { }" (Span (Pos 0 7) (Pos 0 15))
]
describe "python" $ do describe "python" $ do
it "produces tags for functions" $ it "produces tags for functions" $
parseTestFile [] (Path.relFile "test/fixtures/python/tags/simple_functions.py") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/python/tags/simple_functions.py") `shouldReturn`
[ Tag "Foo" P.FUNCTION P.DEFINITION (Loc (Range 4 7) (Span (Pos 1 5) (Pos 1 8))) "def Foo(x):" Nothing [ Tag "Foo" P.FUNCTION P.DEFINITION (Span (Pos 1 5) (Pos 1 8)) "def Foo(x):" (Span (Pos 0 4) (Pos 0 7))
, Tag "Bar" P.FUNCTION P.DEFINITION (Loc (Range 74 77) (Span (Pos 7 5) (Pos 7 8))) "def Bar():" Nothing , Tag "Bar" P.FUNCTION P.DEFINITION (Span (Pos 7 5) (Pos 7 8)) "def Bar():" (Span (Pos 6 4) (Pos 6 7))
, Tag "local" P.FUNCTION P.DEFINITION (Loc (Range 89 94) (Span (Pos 8 9) (Pos 8 14))) "def local():" Nothing , Tag "local" P.FUNCTION P.DEFINITION (Span (Pos 8 9) (Pos 8 14)) "def local():" (Span (Pos 7 8) (Pos 7 13))
] ]
it "produces tags for functions with docs" $ it "produces tags for functions with docs" $
parseTestFile [] (Path.relFile "test/fixtures/python/tags/simple_function_with_docs.py") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/python/tags/simple_function_with_docs.py") `shouldReturn`
[ Tag "Foo" P.FUNCTION P.DEFINITION (Loc (Range 4 7) (Span (Pos 1 5) (Pos 1 8))) "def Foo(x):" (Just "\"\"\"This is the foo function\"\"\"") ] [ Tag "Foo" P.FUNCTION P.DEFINITION (Span (Pos 1 5) (Pos 1 8)) "def Foo(x):" (Span (Pos 0 4) (Pos 0 7))
]
it "produces tags for classes" $ it "produces tags for classes" $
parseTestFile [] (Path.relFile "test/fixtures/python/tags/class.py") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/python/tags/class.py") `shouldReturn`
[ Tag "Foo" P.CLASS P.DEFINITION (Loc (Range 6 9) (Span (Pos 1 7) (Pos 1 10))) "class Foo:" (Just "\"\"\"The Foo class\"\"\"") [ Tag "Foo" P.CLASS P.DEFINITION (Span (Pos 1 7) (Pos 1 10)) "class Foo:" (Span (Pos 0 6) (Pos 0 9))
, Tag "f" P.FUNCTION P.DEFINITION (Loc (Range 43 44) (Span (Pos 3 9) (Pos 3 10))) "def f(self):" (Just "\"\"\"The f method\"\"\"") , Tag "f" P.FUNCTION P.DEFINITION (Span (Pos 3 9) (Pos 3 10)) "def f(self):" (Span (Pos 2 8) (Pos 2 9))
] ]
it "produces tags for multi-line functions" $ it "produces tags for multi-line functions" $
parseTestFile [P.FUNCTION] (Path.relFile "test/fixtures/python/tags/multiline.py") `shouldReturn` parseTestFile [P.FUNCTION] (Path.relFile "test/fixtures/python/tags/multiline.py") `shouldReturn`
[ Tag "Foo" P.FUNCTION P.DEFINITION (Loc (Range 4 7) (Span (Pos 1 5) (Pos 1 8))) "def Foo(x," Nothing ] [ Tag "Foo" P.FUNCTION P.DEFINITION (Span (Pos 1 5) (Pos 1 8)) "def Foo(x," (Span (Pos 0 4) (Pos 0 7))
]
describe "ruby" $ do describe "ruby" $ do
it "produces tags for methods" $ it "produces tags for methods" $
parseTestFile [P.METHOD] (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") `shouldReturn` parseTestFile [P.METHOD] (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") `shouldReturn`
[ Tag "foo" P.METHOD P.DEFINITION (Loc (Range 4 7) (Span (Pos 1 5) (Pos 1 8))) "def foo" Nothing ] [ Tag "foo" P.METHOD P.DEFINITION (Span (Pos 1 5) (Pos 1 8)) "def foo" (Span (Pos 0 4) (Pos 0 7))
]
it "produces tags for sends" $ it "produces tags for sends" $
parseTestFile [P.CALL] (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") `shouldReturn` parseTestFile [P.CALL] (Path.relFile "test/fixtures/ruby/tags/simple_method.rb") `shouldReturn`
[ Tag "puts" P.CALL P.REFERENCE (Loc (Range 10 14) (Span (Pos 2 3) (Pos 2 7))) "puts \"hi\"" Nothing [ Tag "puts" P.CALL P.REFERENCE (Span (Pos 2 3) (Pos 2 7)) "puts \"hi\"" (Span (Pos 1 2) (Pos 1 6))
, Tag "bar" P.CALL P.REFERENCE (Loc (Range 24 27) (Span (Pos 3 5) (Pos 3 8))) "a.bar" Nothing , Tag "bar" P.CALL P.REFERENCE (Span (Pos 3 5) (Pos 3 8)) "a.bar" (Span (Pos 2 4) (Pos 2 7))
, Tag "a" P.CALL P.REFERENCE (Loc (Range 22 23) (Span (Pos 3 3) (Pos 3 4))) "a" Nothing , Tag "a" P.CALL P.REFERENCE (Span (Pos 3 3) (Pos 3 4)) "a.bar" (Span (Pos 2 2) (Pos 2 3))
] ]
it "produces tags for methods with docs (TODO)" $ it "produces tags for methods with docs (TODO)" $
parseTestFile [] (Path.relFile "test/fixtures/ruby/tags/simple_method_with_docs.rb") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/ruby/tags/simple_method_with_docs.rb") `shouldReturn`
[ Tag "foo" P.METHOD P.DEFINITION (Loc (Range 18 21) (Span (Pos 2 5) (Pos 2 8))) "def foo" Nothing ] [ Tag "foo" P.METHOD P.DEFINITION (Span (Pos 2 5) (Pos 2 8)) "def foo" (Span (Pos 1 4) (Pos 1 7))
]
it "correctly tags files containing multibyte UTF-8 characters (TODO)" $ it "correctly tags files containing multibyte UTF-8 characters (TODO)" $
parseTestFile [] (Path.relFile "test/fixtures/ruby/tags/unicode_identifiers.rb") `shouldReturn` parseTestFile [] (Path.relFile "test/fixtures/ruby/tags/unicode_identifiers.rb") `shouldReturn`
[ Tag "日本語" P.METHOD P.DEFINITION (Loc (Range 20 29) (Span (Pos 2 5) (Pos 2 14))) "def 日本語" Nothing] [ Tag "日本語" P.METHOD P.DEFINITION (Span (Pos 2 5) (Pos 2 14)) "def 日本語" (Span (Pos 1 4) (Pos 1 7))
]
it "produces tags for methods and classes with docs (TODO)" $ it "produces tags for methods and classes with docs (TODO)" $
parseTestFile [P.MODULE, P.CLASS, P.METHOD] (Path.relFile "test/fixtures/ruby/tags/class_module.rb") `shouldReturn` parseTestFile [P.MODULE, P.CLASS, P.METHOD] (Path.relFile "test/fixtures/ruby/tags/class_module.rb") `shouldReturn`
[ Tag "Foo" P.MODULE P.DEFINITION (Loc (Range 21 24) (Span (Pos 2 8) (Pos 2 11))) "module Foo" Nothing [ Tag "Foo" P.MODULE P.DEFINITION (Span (Pos 2 8) (Pos 2 11)) "module Foo" (Span (Pos 1 7) (Pos 1 10))
, Tag "Bar" P.CLASS P.DEFINITION (Loc (Range 50 53) (Span (Pos 5 9) (Pos 5 12))) "class Bar" Nothing , Tag "Bar" P.CLASS P.DEFINITION (Span (Pos 5 9) (Pos 5 12)) "class Bar" (Span (Pos 4 8) (Pos 4 11))
, Tag "baz" P.METHOD P.DEFINITION (Loc (Range 81 84) (Span (Pos 8 9) (Pos 8 12))) "def baz(a)" Nothing , Tag "baz" P.METHOD P.DEFINITION (Span (Pos 8 9) (Pos 8 12)) "def baz(a)" (Span (Pos 7 8) (Pos 7 11))
, Tag "C" P.CLASS P.DEFINITION (Loc (Range 132 133) (Span (Pos 14 13) (Pos 14 14))) "class A::B::C" Nothing , Tag "C" P.CLASS P.DEFINITION (Span (Pos 14 13) (Pos 14 14)) "class A::B::C" (Span (Pos 13 12) (Pos 13 13))
, Tag "foo" P.METHOD P.DEFINITION (Loc (Range 140 143) (Span (Pos 15 7) (Pos 15 10))) "def foo" Nothing , Tag "foo" P.METHOD P.DEFINITION (Span (Pos 15 7) (Pos 15 10)) "def foo" (Span (Pos 14 6) (Pos 14 9))
, Tag "foo" P.METHOD P.DEFINITION (Loc (Range 175 178) (Span (Pos 18 12) (Pos 18 15))) "def self.foo" Nothing , Tag "foo" P.METHOD P.DEFINITION (Span (Pos 18 12) (Pos 18 15)) "def self.foo" (Span (Pos 17 11) (Pos 17 14))
] ]
parseTestFile :: Foldable t => t P.SyntaxType -> Path.RelFile -> IO [Tag] parseTestFile :: Foldable t => t P.SyntaxType -> Path.RelFile -> IO [Tag]