Implementing pragmas
This commit is contained in:
@@ -13,6 +13,7 @@ type ProjectTree struct {
|
||||
Root *ProjectNode
|
||||
References []Reference
|
||||
IsolatedFiles map[string]*ProjectNode
|
||||
GlobalPragmas map[string][]string
|
||||
}
|
||||
|
||||
func (pt *ProjectTree) ScanDirectory(rootPath string) error {
|
||||
@@ -59,6 +60,7 @@ type Fragment struct {
|
||||
Definitions []parser.Definition
|
||||
IsObject bool
|
||||
ObjectPos parser.Position
|
||||
EndPos parser.Position
|
||||
Doc string // Documentation for this fragment (if object)
|
||||
}
|
||||
|
||||
@@ -69,6 +71,7 @@ func NewProjectTree() *ProjectTree {
|
||||
Metadata: make(map[string]string),
|
||||
},
|
||||
IsolatedFiles: make(map[string]*ProjectNode),
|
||||
GlobalPragmas: make(map[string][]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +92,7 @@ func (pt *ProjectTree) RemoveFile(file string) {
|
||||
pt.References = newRefs
|
||||
|
||||
delete(pt.IsolatedFiles, file)
|
||||
delete(pt.GlobalPragmas, file)
|
||||
pt.removeFileFromNode(pt.Root, file)
|
||||
}
|
||||
|
||||
@@ -156,6 +160,14 @@ func (pt *ProjectTree) extractFieldMetadata(node *ProjectNode, f *parser.Field)
|
||||
func (pt *ProjectTree) AddFile(file string, config *parser.Configuration) {
|
||||
pt.RemoveFile(file)
|
||||
|
||||
// Collect global pragmas
|
||||
for _, p := range config.Pragmas {
|
||||
txt := strings.TrimSpace(p.Text)
|
||||
if strings.HasPrefix(txt, "//!allow(") {
|
||||
pt.GlobalPragmas[file] = append(pt.GlobalPragmas[file], txt)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Package == nil {
|
||||
node := &ProjectNode{
|
||||
Children: make(map[string]*ProjectNode),
|
||||
@@ -249,6 +261,7 @@ func (pt *ProjectTree) addObjectFragment(node *ProjectNode, file string, obj *pa
|
||||
File: file,
|
||||
IsObject: true,
|
||||
ObjectPos: obj.Position,
|
||||
EndPos: obj.Subnode.EndPosition,
|
||||
Doc: doc,
|
||||
}
|
||||
|
||||
@@ -462,3 +475,44 @@ func (pt *ProjectTree) queryNode(node *ProjectNode, file string, line, col int)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pt *ProjectTree) GetNodeContaining(file string, pos parser.Position) *ProjectNode {
|
||||
if isoNode, ok := pt.IsolatedFiles[file]; ok {
|
||||
if found := pt.findNodeContaining(isoNode, file, pos); found != nil {
|
||||
return found
|
||||
}
|
||||
return isoNode
|
||||
}
|
||||
if pt.Root != nil {
|
||||
if found := pt.findNodeContaining(pt.Root, file, pos); found != nil {
|
||||
return found
|
||||
}
|
||||
for _, frag := range pt.Root.Fragments {
|
||||
if frag.File == file && !frag.IsObject {
|
||||
return pt.Root
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pt *ProjectTree) findNodeContaining(node *ProjectNode, file string, pos parser.Position) *ProjectNode {
|
||||
for _, child := range node.Children {
|
||||
if res := pt.findNodeContaining(child, file, pos); res != nil {
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
for _, frag := range node.Fragments {
|
||||
if frag.File == file && frag.IsObject {
|
||||
start := frag.ObjectPos
|
||||
end := frag.EndPos
|
||||
|
||||
if (pos.Line > start.Line || (pos.Line == start.Line && pos.Column >= start.Column)) &&
|
||||
(pos.Line < end.Line || (pos.Line == end.Line && pos.Column <= end.Column)) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -581,8 +581,8 @@ func formatNodeInfo(node *index.ProjectNode) string {
|
||||
}
|
||||
|
||||
// Size
|
||||
dims := node.Metadata["NumberOfDimensions"]
|
||||
elems := node.Metadata["NumberOfElements"]
|
||||
dims := node.Metadata["NumberOfDimensions"]
|
||||
elems := node.Metadata["NumberOfElements"]
|
||||
if dims != "" || elems != "" {
|
||||
sigInfo += fmt.Sprintf("**Size**: `[%s]`, `%s` dims ", elems, dims)
|
||||
}
|
||||
@@ -592,6 +592,57 @@ elems := node.Metadata["NumberOfElements"]
|
||||
if node.Doc != "" {
|
||||
info += fmt.Sprintf("\n\n%s", node.Doc)
|
||||
}
|
||||
|
||||
// Find references
|
||||
var refs []string
|
||||
for _, ref := range tree.References {
|
||||
if ref.Target == node {
|
||||
container := tree.GetNodeContaining(ref.File, ref.Position)
|
||||
if container != nil {
|
||||
threadName := ""
|
||||
stateName := ""
|
||||
|
||||
curr := container
|
||||
for curr != nil {
|
||||
if cls, ok := curr.Metadata["Class"]; ok {
|
||||
if cls == "RealTimeThread" {
|
||||
threadName = curr.RealName
|
||||
}
|
||||
if cls == "RealTimeState" {
|
||||
stateName = curr.RealName
|
||||
}
|
||||
}
|
||||
curr = curr.Parent
|
||||
}
|
||||
|
||||
if threadName != "" || stateName != "" {
|
||||
refStr := ""
|
||||
if stateName != "" {
|
||||
refStr += fmt.Sprintf("State: `%s`", stateName)
|
||||
}
|
||||
if threadName != "" {
|
||||
if refStr != "" {
|
||||
refStr += ", "
|
||||
}
|
||||
refStr += fmt.Sprintf("Thread: `%s`", threadName)
|
||||
}
|
||||
refs = append(refs, refStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(refs) > 0 {
|
||||
uniqueRefs := make(map[string]bool)
|
||||
info += "\n\n**Referenced in**:\n"
|
||||
for _, r := range refs {
|
||||
if !uniqueRefs[r] {
|
||||
uniqueRefs[r] = true
|
||||
info += fmt.Sprintf("- %s\n", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
|
||||
@@ -354,15 +354,17 @@ func (v *Validator) validateGAMSignal(gamNode, signalNode *index.ProjectNode, di
|
||||
}
|
||||
|
||||
if targetNode == nil {
|
||||
suppress := false
|
||||
for _, p := range signalNode.Pragmas {
|
||||
if strings.HasPrefix(p, "implicit:") {
|
||||
suppress = true
|
||||
break
|
||||
suppressed := v.isGloballyAllowed("implicit")
|
||||
if !suppressed {
|
||||
for _, p := range signalNode.Pragmas {
|
||||
if strings.HasPrefix(p, "implicit:") {
|
||||
suppressed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !suppress {
|
||||
if !suppressed {
|
||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||
Level: LevelWarning,
|
||||
Message: fmt.Sprintf("Implicitly Defined Signal: '%s' is defined in GAM '%s' but not in DataSource '%s'", targetSignalName, gamNode.RealName, dsName),
|
||||
@@ -624,6 +626,9 @@ func (v *Validator) checkUnusedRecursive(node *index.ProjectNode, referenced map
|
||||
// Heuristic for GAM
|
||||
if isGAM(node) {
|
||||
if !referenced[node] {
|
||||
if v.isGloballyAllowed("unused") {
|
||||
return
|
||||
}
|
||||
suppress := false
|
||||
for _, p := range node.Pragmas {
|
||||
if strings.HasPrefix(p, "unused:") {
|
||||
@@ -647,6 +652,9 @@ func (v *Validator) checkUnusedRecursive(node *index.ProjectNode, referenced map
|
||||
if signalsNode, ok := node.Children["Signals"]; ok {
|
||||
for _, signal := range signalsNode.Children {
|
||||
if !referenced[signal] {
|
||||
if v.isGloballyAllowed("unused") {
|
||||
continue
|
||||
}
|
||||
suppress := false
|
||||
for _, p := range signal.Pragmas {
|
||||
if strings.HasPrefix(p, "unused:") {
|
||||
@@ -709,4 +717,16 @@ func (v *Validator) getNodeFile(node *index.ProjectNode) string {
|
||||
return node.Fragments[0].File
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (v *Validator) isGloballyAllowed(warningType string) bool {
|
||||
prefix := fmt.Sprintf("//!allow(%s)", warningType)
|
||||
for _, pragmas := range v.Tree.GlobalPragmas {
|
||||
for _, p := range pragmas {
|
||||
if strings.HasPrefix(p, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user