Commit cd596c91 authored by Tristan Gingold's avatar Tristan Gingold

First packaging of the vhdllint tool.

parent b4dc77d0
*~
*.pyc
__pycache__
*.egg-info
doc/vhdl-coding-style.html
doc/vhdl-coding-style.pdf
doc/vhdl-coding-style.xml
"""A setuptools setup module for vhdllint."""
from setuptools import setup
setup(
name='vhdllint',
version='0.1.0',
description='Linter and style checker for VHDL',
url='https://www.ohwr.org/projects/vhdl-style',
author='Tristan Gingold - CERN BE-CO-HT',
author_email='vhdl-style@ohwr.org',
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 4 - Beta',
# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
# Pick your license as you wish
'License :: OSI Approved :: '
'GNU General Public License v3 or later (GPLv3+)'
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
keywords='checker linter lint vhdl',
packages=["vhdllint"],
install_requires=['libghdl'],
entry_points={
'console_scripts': [
'vhdllint-ohwr = vhdllint.ohwr.main'
]
}
)
"""File wide rules.
The input of these rule checkers is the filename and the files (as a list
of line). The rules must have a file scope, like presence of an header,
no trailing spaces, max line length...
Do not check about comments, the place for that in lexrules."""
from vhdllint.rule import Rule
class FileRule(Rule):
def __init__(self, rulename):
super(FileRule, self).__init__(rulename)
def check(self, loc, lines):
"""The check to be performed on the whole file.
lines is the list of lines, with the line terminator"""
assert False # Must be redefined
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckCharSet(FileRule):
"""Check only 7-bit ASCII characters are used."""
rulename = 'CharSet'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, loc, lines):
for lineno, line in enumerate(lines):
for col, c in enumerate(line):
if ord(c) > 127:
self.error(loc.new(lineno + 1, col + 1),
"Non 7-bit ASCII character")
# At most one error per line
break
@staticmethod
def test(runner):
rule = CheckCharSet()
TestRunOK(runner, "File with no tab",
rule, "hello.vhdl")
TestRunFail(runner, "File with an invalid character",
rule, "charset1.vhdl")
import os.path
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckFilenameExtension(FileRule):
"""Check the extension of the filename"""
rulename = 'FileExt'
def __init__(self, extensions=['.vhd', '.vhdl'], name=None):
super(CheckFilenameExtension, self).__init__(name)
self.extensions = extensions
def check(self, loc, lines):
filename = loc.filename
(root, ext) = os.path.splitext(filename)
if ext not in self.extensions:
self.error(loc, 'bad filename extension')
@staticmethod
def test(runner):
rule = CheckFilenameExtension()
TestRunOK(runner, "Filename with correct extension",
rule, "hello.vhdl")
TestRunFail(runner, "Filename with incorrect extension",
rule, "badext.txt")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckHeader(FileRule):
"""Check the file starts with an header."""
rulename = 'Header'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def extract_header(self, lines):
header = b""
for l in lines:
if not l.startswith(b'--'):
break
header += l
return header
def check(self, loc, lines):
header = self.extract_header(lines)
if header == b'':
self.error(loc.new(1, 1), "file should have an header")
@staticmethod
def test(runner):
rule = CheckHeader()
TestRunOK(runner, "File with an header",
rule, "hello.vhdl")
TestRunFail(runner, "File without an header",
rule, "noheader.vhdl")
TestRunFail(runner, "File without an header at line 1",
rule, "noheader2.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckLineLength(FileRule):
"""Check maximum length of lines"""
rulename = 'LineLen'
def __init__(self, maxlen=80, name=None):
super(self.__class__, self).__init__(name)
self._maxlen = maxlen
def check(self, loc, lines):
lineno = 1
for line in lines:
linelen = len(line)
# Strip CR/LF
while linelen > 1 and line[linelen - 1] in b"\r\n":
linelen -= 1
if linelen > self._maxlen:
self.error(loc.new(lineno, linelen), 'line is too long')
lineno += 1
@staticmethod
def test(runner):
rule = CheckLineLength()
TestRunOK(runner, "File with normal lines",
rule, "hello.vhdl")
TestRunOK(runner, "File with 2 lines of exactely 80 characters",
rule, "line80.vhdl")
TestRunFail(runner, "File with a long line",
rule, "longline.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckMissingNewline(FileRule):
"""Check the file finishes with a newline."""
rulename = 'NewlineEOF'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, loc, lines):
nbr_lines = len(lines)
if nbr_lines == 0:
return
lastline = lines[nbr_lines - 1]
linelen = len(lastline)
if linelen == 0 or lastline[linelen - 1] not in b"\r\n":
self.error(loc.new(nbr_lines, linelen),
'missing newline at end of file')
@staticmethod
def test(runner):
rule = CheckMissingNewline()
TestRunOK(runner, "File with a newline at the end",
rule, "hello.vhdl")
TestRunFail(runner, "File without a newline at EOF",
rule, "nonewlineateof.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckNewline(FileRule):
"""Check the newline is LF (unix convention)."""
rulename = 'Newline'
def __init__(self, newline=b'\n', name=None):
super(self.__class__, self).__init__(name)
self._newline = newline
def check(self, loc, lines):
nllen = len(self._newline)
for lineno, line in enumerate(lines):
l = len(line)
if l < nllen \
or line[-nllen:] != self._newline \
or (l > nllen and line[-nllen - 1] in b"\r\n"):
self.error(loc.new(lineno + 1, l), "incorrect newline")
elif l > nllen > l and line[0] in b"\r\n":
self.error(loc.new(lineno + 1, 1), "incorrect newline")
@staticmethod
def test(runner):
rule = CheckNewline()
TestRunOK(runner, "File with unix newline",
rule, "hello.vhdl")
TestRunFail(runner, "File with dos newline",
rule, "dosfile.vhdl")
TestRunFail(runner, "File with macos newline",
rule, "macfile.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckNoBlankLineAtEOF(FileRule):
"""Check there is not blank line at end of file."""
rulename = 'BlankLine'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, loc, lines):
nbr_lines = len(lines)
if nbr_lines == 0:
return
lastline = lines[nbr_lines - 1]
if lastline.rstrip(b"\r\n\t ") == b'':
self.error(loc.new(nbr_lines, 1),
'blank line at end of file')
@staticmethod
def test(runner):
rule = CheckNoBlankLineAtEOF()
TestRunOK(runner, "File with a newline at the end",
rule, "hello.vhdl")
TestRunFail(runner, "File with a blank line at EOF",
rule, "blanklineateof.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckNoTAB(FileRule):
"""Check there is no TAB (HT, VT and FF)."""
rulename = 'NoTAB'
def __init__(self, tabs=b"\t\v\f", name=None):
super(self.__class__, self).__init__(name)
self._tabs = tabs
def check(self, loc, lines):
for lineno, line in enumerate(lines):
for col, c in enumerate(line):
if c in self._tabs:
self.error(loc.new(lineno + 1, col + 1),
"HT not allowed" if c == '\t'
else "character not allowed")
# At most one error per line
break
@staticmethod
def test(runner):
rule = CheckNoTAB()
TestRunOK(runner, "File with no tab",
rule, "hello.vhdl")
TestRunFail(runner, "File with an horizontal tab (HT)",
rule, "ht.vhdl")
TestRunFail(runner, "File with an vertical tab (VT)",
rule, "vt.vhdl")
TestRunFail(runner, "File with a form-feed (FF)",
rule, "ff.vhdl")
from vhdllint.filerules import FileRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
class CheckNoTrailingSpaces(FileRule):
"""Check there is no trailing spaces."""
rulename = 'NoSpaceEOL'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, loc, lines):
for lineno, line in enumerate(lines):
line = line.rstrip(b"\r\n")
ln = len(line)
if ln > 0 and line[ln - 1] in b' \t':
self.error(loc.new(lineno + 1, ln), "trailing space")
@staticmethod
def test(runner):
rule = CheckNoTrailingSpaces()
TestRunOK(runner, "File with no trailing spaces",
rule, "hello.vhdl")
TestRunFail(runner, "File with a trailing space",
rule, "trailingspace.vhdl")
"""Lexical rules.
The checkers are called for each token in the files. The tokens include
comments (there is a special token to represent a comment).
Lexical rules include case of keywords, specific rules about comments,
spaces around operators...
"""
from vhdllint.rule import Rule
class LexRule(Rule):
def __init__(self, rulename):
super(LexRule, self).__init__(rulename)
def check(self, loc, filebuf, tok):
"""The check to be performed on a token."""
assert False # Must be redefined
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckComments(LexRule):
"""Check comments are followed by a space or are line comment."""
rulename = 'Comments'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, loc, filebuf, tok):
if tok == tokens.Tok.Comment:
p = loc.start
assert filebuf[p:p + 2] == b'--'
if p != 0 and filebuf[p - 1] not in b" \t\r\n":
self.error(loc, "missing space before comment")
if filebuf[p + 2] in b" -=\r\n":
return
self.error(loc, "space required after comment")
@staticmethod
def test(runner):
rule = CheckComments()
TestRunOK(runner, "File with correct comments",
rule, "hello.vhdl")
TestRunFail(runner, "Comment not followed by a space",
rule, "comment1.vhdl")
TestRunOK(runner, "File with a line comment",
rule, "comment2.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
import libghdl.thin as thin
class CheckForbiddenId(LexRule):
"""Check for fobidden identifiers."""
rulename = 'ForbiddenId'
def __init__(self, ids=[b'l', b'o'], name=None):
super(self.__class__, self).__init__(name)
self._ids = ids
def check(self, loc, filebuf, tok):
if tok == tokens.Tok.Identifier:
s = thin.Get_Name_Ptr(thin.Scanner.Current_Identifier())
if s in self._ids:
self.error(
loc, "use of forbidden identifier '{0}'".format(
s.decode('latin-1')))
@staticmethod
def test(runner):
rule = CheckForbiddenId()
TestRunOK(runner, "File with no forbidden id",
rule, "hello.vhdl")
TestRunFail(runner, "File with identifier 'l'",
rule, "forbiddenid.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckKeywordCase(LexRule):
"""Check keywords are in lower-case."""
# OK, in VHDL there are no keywords but reserved words.
rulename = 'KeywordCase'
def __init__(self, filter=lambda x: x.islower(), name=None):
super(self.__class__, self).__init__(name)
self._filter = filter
def check(self, loc, filebuf, tok):
if tok >= tokens.Tok.And and tok <= tokens.Tok.Tolerance:
s = filebuf[loc.start:loc.end]
if not self._filter(s):
self.error(loc, "incorrect keyword case for {0}".format(s))
@staticmethod
def test(runner):
rule = CheckKeywordCase()
TestRunOK(runner, "File with no tab",
rule, "hello.vhdl")
TestRunFail(runner, "File a keyword in upper case",
rule, "keyword.vhdl")
TestRunFail(runner, "File a capitalized keyword",
rule, "keyword2.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckNoSpaceAfter(LexRule):
"""Check some delimiters are not followed by a space."""
rulename = 'NoSpaceAfter'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._toks = [tokens.Tok.Tick, tokens.Tok.Dot]
self._spaces = b" \t"
def check(self, loc, filebuf, tok):
if tok in self._toks:
e = loc.end
if e < len(filebuf) and filebuf[e] in self._spaces:
self.error(
loc, "space not allowed space after '{0}'".format(
filebuf[loc.start:loc.end]))
@staticmethod
def test(runner):
rule = CheckNoSpaceAfter()
TestRunOK(runner, "File without space after '.'",
rule, "nospace5.vhdl")
TestRunFail(runner, "Space after '",
rule, "nospace6.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckSpaceAfter(LexRule):
"""Check some delimiters are followed by one space."""
rulename = 'SpaceAfter'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._toks = [tokens.Tok.Comma, tokens.Tok.Colon]
self._spaces = b" \t\r\n"
def check(self, loc, filebuf, tok):
if tok in self._toks:
e = loc.end
if e < len(filebuf) and filebuf[e] not in self._spaces:
self.error(
loc, "missing space after '{0}'".format(
filebuf[loc.start:loc.end]))
@staticmethod
def test(runner):
rule = CheckSpaceAfter()
TestRunOK(runner, "File with spaces around operator",
rule, "hello.vhdl")
TestRunFail(runner, "No space after ':'",
rule, "nospace1.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckSpaces(LexRule):
"""Check operators have a space before and after."""
# ... for some extended definition of operators.
rulename = 'Spaces'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
# What a space is
self._spaces = b" \t\r\n"
self._before_after = [tokens.Tok.Assign, tokens.Tok.Colon,
tokens.Tok.Equal, tokens.Tok.Not_Equal,
tokens.Tok.Less, tokens.Tok.Less_Equal,
tokens.Tok.Greater, tokens.Tok.Greater_Equal,
tokens.Tok.Double_Arrow]
self._not_before = [tokens.Tok.Comma, tokens.Tok.Semi_Colon]
self._prev_tok = tokens.Tok.Invalid
def has_before(self, loc, filebuf):
return loc.start > 0 and filebuf[loc.start - 1] in self._spaces
def has_after(self, loc, filebuf):
return loc.end < len(filebuf) and filebuf[loc.end] in self._spaces
def check_before(self, loc, filebuf, s):
if not self.has_before(loc, filebuf):
self.error(loc, "missing space before '{0}'".format(s))
def check_not_before(self, loc, filebuf, s):
if self.has_before(loc, filebuf):
self.error(loc, "extra space before '{0}'".format(s))
def check_after(self, loc, filebuf, s):
if not self.has_after(loc, filebuf):
self.error(loc, "missing space after '{0}'".format(s))
def check(self, loc, filebuf, tok):
if tok in self._before_after:
s = filebuf[loc.start:loc.end]
self.check_before(loc, filebuf, s)
self.check_after(loc, filebuf, s)
elif tok in self._not_before:
s = filebuf[loc.start:loc.end]
self.check_not_before(loc, filebuf, s)
self._prev_tok = tok
@staticmethod
def test(runner):
rule = CheckSpaces()
TestRunOK(runner, "File with no issues",
rule, "hello.vhdl")
TestRunFail(runner, "No space after ':'",
rule, "nospace1.vhdl")
from vhdllint.lexrules import LexRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.tokens as tokens
class CheckSpacesAroundOperator(LexRule):
"""Check operators have a space before and after."""
# ... for some extended definition of operators.
rulename = 'OperatorSpace'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._operators = [tokens.Tok.Assign,
tokens.Tok.Equal, tokens.Tok.Not_Equal,
tokens.Tok.Less, tokens.Tok.Less_Equal,
tokens.Tok.Greater, tokens.Tok.Greater_Equal,
tokens.Tok.Plus,
tokens.Tok.Ampersand, # tokens.Tok.Star,
tokens.Tok.Slash]
self._spaces = b" \t\r\n"
def check(self, loc, filebuf, tok):
if tok in self._operators:
s = filebuf[loc.start:loc.end]
if loc.start > 0 and filebuf[loc.start - 1] not in self._spaces:
self.error(
loc, "missing space before operator '{0}'".format(s))
if loc.end < len(filebuf) and filebuf[loc.end] not in self._spaces:
self.error(
loc, "missing space after operator '{0}'".format(s))
elif (loc.end < len(filebuf) + 1
and filebuf[loc.end] in b" \t"
and filebuf[loc.end + 1] in b" \t"):
self.error(
loc, "multiple spaces after operator '{0}'".format(s))
@staticmethod
def test(runner):
rule = CheckSpacesAroundOperator()
TestRunOK(runner, "File with spaces around operator",
rule, "hello.vhdl")
TestRunFail(runner, "No space after '+'",
rule, "operatorspace1.vhdl")
TestRunFail(runner, "No space before '/'",
rule, "operatorspace2.vhdl")
TestRunFail(runner, "Multiple spaces after '>'",
rule, "operatorspace3.vhdl")
import ctypes
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
def _is_interface_port_generic(node):
parent_kind = iirs.Get_Kind(iirs.Get_Parent(node))
return (parent_kind in [iirs.Iir_Kind.Entity_Declaration,
iirs.Iir_Kind.Component_Declaration,
iirs.Iir_Kind.Block_Header])
def is_generic(node):
"""Return True iff argument node is a generic."""
if iirs.Get_Kind(node) != iirs.Iir_Kind.Interface_Constant_Declaration:
return False
return _is_interface_port_generic(node)
def is_port(node):
"""Return True iff argument node is a port."""
if iirs.Get_Kind(node) != iirs.Iir_Kind.Interface_Signal_Declaration:
return False
return _is_interface_port_generic(node)
def is_std_logic(typ):
return typ == thin.Ieee.Std_Logic_Type.value
def is_std_logic_vector(typ):
return iirs.Get_Base_Type(typ) == thin.Ieee.Std_Logic_Vector_Type.value
def is_std_logic_or_std_logic_vector(typ):
return is_std_logic(typ) or is_std_logic_vector(typ)
def get_identifier_str(n):
"""Return the identifier (as it appears in the sources) for node n.
The node n must have an identifier field. There is no case conversion."""
ident = iirs.Get_Identifier(n)
id_len = thin.Get_Name_Length(ident)
loc = iirs.Get_Location(n)
fe = thin.Location_To_File(loc)
pos = thin.Location_File_To_Pos(loc, fe)
fptr = thin.Get_File_Buffer(fe)
return ctypes.string_at(fptr + pos, id_len).decode('latin-1')
def is_predefined_node(n):
k = iirs.Get_Kind(n)
if k == iirs.Iir_Kind.Interface_Constant_Declaration \
and iirs.Get_Identifier(n) == 0:
return True
if k == iirs.Iir_Kind.Function_Declaration \
and iirs.Get_Implicit_Definition(n) < iirs.Iir_Predefined.PNone:
return True
return False
def is_one_stmt(chain):
return chain != thin.Null_Iir \
and iirs.Get_Chain(chain) == thin.Null_Iir
def is_one_alt(alts):
assert not iirs.Get_Same_Alternative_Flag(alts)
next_alt = iirs.Get_Chain(alts)
return next_alt == thin.Null_Iir \
or not iirs.Get_Same_Alternative_Flag(next_alt)
def is_same_line(loc1, loc2):
"""Return True iff loc1 and loc2 point to the same line in the
same file."""
fe = thin.Location_To_File(loc1)
if fe != thin.Location_To_File(loc2):
return False
line = thin.Location_File_To_Line(loc1, fe)
return line == thin.Location_File_To_Line(loc2, fe)
def extract_packages_from_context_clause(dsgn):
"""Return a list of package declarations from design unit dsgn (which must
have been analyzed)."""
res = []
for n in thinutils.chain_iter(iirs.Get_Context_Items(dsgn)):
if iirs.Get_Kind(n) != iirs.Iir_Kind.Use_Clause:
continue
cl = n
while cl != thin.Null_Iir:
name = iirs.Get_Selected_Name(cl)
if iirs.Get_Kind(name) == iirs.Iir_Kind.Selected_By_All_Name:
name = iirs.Get_Prefix(name)
name = iirs.Get_Named_Entity(name)
assert name != thin.Null_Iir, "unit not analyzed"
if iirs.Get_Kind(name) == iirs.Iir_Kind.Package_Declaration:
res.append(name)
cl = iirs.Get_Use_Clause_Chain(cl)
return res
#!/usr/bin/env python
# VHDL linter for OHWR coding style
import sys
import rulesexec
import libghdl.thin
import libghdl.iirs as iirs
# Import all rules
from filerules.check_line_length import CheckLineLength
from filerules.check_no_blank_line_at_eof import CheckNoBlankLineAtEOF
from filerules.check_missing_newline import CheckMissingNewline
from filerules.check_no_tab import CheckNoTAB
from filerules.check_no_trailing_spaces import CheckNoTrailingSpaces
from filerules.check_newline import CheckNewline
from filerules.check_header import CheckHeader
from filerules.check_charset import CheckCharSet
from lexrules.check_keyword_case import CheckKeywordCase
from lexrules.check_comments import CheckComments
from lexrules.check_spaces import CheckSpaces
from syntaxrules.check_attribute_decl import CheckAttributeDecl
from syntaxrules.check_attribute_name import CheckAttributeName
from syntaxrules.check_entity_simple import CheckEntitySimple
from syntaxrules.check_enum_char_lit import CheckEnumCharLit
from syntaxrules.check_guarded_signals import CheckGuardedSignals
from syntaxrules.check_disconnection import CheckDisconnection
from syntaxrules.check_simple_block import CheckSimpleBlock
from syntaxrules.check_group import CheckGroup
from syntaxrules.check_ports_mode import CheckPortsMode
from syntaxrules.check_config_spec import CheckConfigSpec
from syntaxrules.check_file_name import CheckFileName
from syntaxrules.check_one_unit import CheckOneUnit
from syntaxrules.check_generics import CheckGenerics
from syntaxrules.check_ports_name import CheckPortsName
from syntaxrules.check_basic_indent import CheckBasicIndent
from syntaxrules.check_name_decl import CheckNameDecl
from syntaxrules.check_ieee_packages import CheckIeeePackages
from syntaxrules.check_signals_name import CheckSignalsName
from syntaxrules.check_context_use import CheckContextUse
from syntaxrules.check_end_label import CheckEndLabel
from syntaxrules.check_parenthesis import CheckParenthesis
from syntaxrules.check_process_label import CheckProcessLabel
from syntaxrules.check_subprg_is_layout import CheckSubprgIsLayout
from syntaxrules.check_complex_stmt_layout import CheckComplexStmtLayout
from syntaxrules.check_instantiation import CheckInstantiation
from syntaxrules.check_entity_layout import CheckEntityLayout
from syntaxrules.check_context_clauses import CheckContextClauses
# [VHDLVersion] [M] VHDL standard version
# There is no specific rule, the analyzer will catch errors
libghdl.thin.set_option("--std=93c")
# Create rules
rules = rulesexec.RulesExec()
# List of rules (v1.0):
# File rules
# [FileName] [M] Name of VHDL file
rules.add(CheckFileName(extension='.vhd'))
# [FileContent] [R] Content of a VHDL file
rules.add(CheckOneUnit(name='FileContent', patterns=['EA', 'C', 'P', 'PB']))
# [FileHeader] [M] Header comment of a VHDL file
# TODO: template
rules.add(CheckHeader(name='FileHeader'))
# [LineLength] [M] Source line length
rules.add(CheckLineLength(132))
# [EndOfLine] [M] End of line
rules.add(CheckNewline(name='EndOfLine'))
# [Language] [M] Language for comments and identifiers (I)
# Inspection
# [CharSet] [M] Character set
rules.add(CheckCharSet())
# [NoTAB] [M] No tabulation
rules.add(CheckNoTAB(name='NoTAB'))
# [LastLine] [M] Last line in a file
rules.add(CheckNoBlankLineAtEOF(name='LastLine'))
rules.add(CheckMissingNewline(name='LastLine'))
# [TrailingSpaces] [M] Trailing spaces
rules.add(CheckNoTrailingSpaces(name='TrailingSpaces'))
# Format rules
# [Comments] [M] Comment style
rules.add(CheckComments())
# [Indentation] [M] Indentation
rules.add(CheckBasicIndent(name='Indentation'))
# [WhiteSpaces] [M] Spaces
rules.add(CheckSpaces(name='Spaces'))
# [Context] [M] Context clauses
rules.add(CheckContextClauses())
# [UseClause] [M] Place of use clause
rules.add(CheckContextUse())
# [EntityLayout] [M] Layout of entity declaration
rules.add(CheckEntityLayout())
# [ComplexStmtLayout] [M] Layout of complex statements
rules.add(CheckComplexStmtLayout())
# [SubprgIsLayout] [M] Layout of is keyword in subprogram
rules.add(CheckSubprgIsLayout())
# [EndLabel] [M] Presence of the label after end
rules.add(CheckEndLabel())
# [Instantiation] [M] Layout of instantiation
rules.add(CheckInstantiation())
# [ProcessLabel] [M] Label of processes
rules.add(CheckProcessLabel())
# [Parenthesis] [M] Use of parenthesis in expressions
rules.add(CheckParenthesis())
# Identifiers
# [Keywords] [M] Keywords case
rules.add(CheckKeywordCase())
# [Identifiers] [M] Identifiers case (I)
# Inspection
# [Underscores] [M] Use of underscore in identifiers (I)
# Inspection
# [ReferenceName] [M] Reference
# [ArchNames] [M] Architectures name
rules.add(CheckNameDecl(kind=iirs.Iir_Kind.Architecture_Body,
predicate=(lambda n: n == 'arch'),
name='ArchNames'))
# [Constants] [M] Constants name
rules.add(CheckNameDecl(kind=iirs.Iir_Kind.Constant_Declaration,
predicate=(lambda n: len(n) >= 3
and n[:2] == 'c_'
and n[2:].isupper()),
name='Constants'))
# [GenericsName] [M] Generics name
rules.add(CheckGenerics(name='GenericsName'))
# [PortsName] [M] Ports name
rules.add(CheckPortsName(name='PortsName'))
# [SignalsName] [M] Signals name
rules.add(CheckSignalsName(name='SignalsName'))
# [TypesName] [M] Types name
rules.add(CheckNameDecl(kind=iirs.Iir_Kind.Type_Declaration,
predicate=(lambda n: len(n) >= 3 and n[:2] == 't_'),
name='TypesName'))
rules.add(CheckNameDecl(kind=iirs.Iir_Kind.Subtype_Declaration,
predicate=(lambda n: len(n) >= 3 and n[:2] == 't_'),
name='TypesName'))
# [PackagesName] [M] Packages name
rules.add(CheckNameDecl(kind=iirs.Iir_Kind.Package_Declaration,
predicate=(lambda n: len(n) >= 4 and n[-4:] == '_pkg'),
name='PackagesName'))
# Language subset
# [VHDLVersion] [M] VHDL standard version
# Set by a switch
# [IEEEPkg] [M] Use of IEEE packages
rules.add(CheckIeeePackages(extra_pkg=['math_real',
'std_logic_misc',
'std_logic_textio'],
name='IEEEPkg'))
# [NoUserAttributes] [M] Attribute declarations not allowed
# Allow attributes for synthesis tools.
rules.add(CheckAttributeDecl
(name="NoUserAttributes",
allowed=['keep', 'shreg_extract', 'opt_mode', 'resource_sharing',
'altera_attribute']))
# [NoUserAttrName] [M] Attribute names
rules.add(CheckAttributeName())
# [EntityItems] [M] Entity declarative items
rules.add(CheckEntitySimple())
# [NoCharEnumLit] [M] Character as enumeration literal
rules.add(CheckEnumCharLit())
# [GuardedSignals] [M] Guarded signals
rules.add(CheckGuardedSignals())
# [Disconnection] [M] Disconnection Specification
rules.add(CheckDisconnection())
# [BlockStatement] [M] Block statements
rules.add(CheckSimpleBlock())
# [GroupDeclaration] [M] Group and group template
rules.add(CheckGroup())
# [PortMode] [M] Buffer and linkage mode
rules.add(CheckPortsMode())
# [ConfigSpec] [M] Configuration specification
rules.add(CheckConfigSpec())
# Synthesis rules
# [RemovedSynth] [M] Language features not allowed for synthesis
# [PortsType] [M] Type of top-level ports
# [GenericType] [M] Type of top-levels generics
# [WrapperUnit] [R] Wrapper of top-level units
# [RegisterTemplate] [R] Process for a register.
# [AsyncReset] [M] Asynchronous reset
# [RegisterReset] [M] Register reset
# [SignalAttribute] [M] Signal attributes
# [VectorDirection] [M] Direction of indexes
# [EmptyArray] [M] Minimal length of arrays
# [ClockResetPorts] [M] Clock and reset ports
# [ClocksUse] [M] Usage of clocks
# [FSMCoding] [R] FSM code style
rulesexec.execute_and_report(rules, sys.argv[1:])
class Rule(object):
def __init__(self, rulename):
if rulename:
self._rulename = rulename
else:
self._rulename = self.rulename
self._run = None
def set_runner(self, run):
self._run = run
def error(self, loc, msg):
self._run.error("{0}:{1}:{2}: [{3}] {4}\n".format(
loc.filename, loc.line, loc.col, self._rulename, msg))
This diff is collapsed.
"""Semantic rules.
The files are parsed and analyzed. Checkers are called for each file.
Semantic rules include checks on types, use of packages..."""
from vhdllint.rule import Rule
class SemRule(Rule):
def __init__(self, rulename):
super(SemRule, self).__init__(rulename)
def check(self, loc, dsgn):
"""The check to be performed on an AST (a design unit)."""
assert False # Must be redefined
class SemNodeRule(Rule):
def __init__(self, rulename):
super(SemNodeRule, self).__init__(rulename)
def check(self, loc, node):
"""The check to be performed on each node."""
assert False # Must be redefined
from vhdllint.semrules import SemRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thinutils as thinutils
import libghdl.thin as thin
import vhdllint.nodeutils as nodeutils
class CheckAssocs(SemRule):
"""Check associations order of instantiations.
In component instantiations generics and ports must be associated by
name in the same order as the interfaces."""
rulename = 'Assocs'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_assocs(self, n, inters, assocs):
if assocs == thin.Null_Iir:
# Also cover the case of no interfaces
return
inter = inters
for assoc in thinutils.chain_iter(assocs):
if iirs.Get_Kind(assoc) \
== iirs.Iir_Kind.Association_Element_By_Individual:
continue
formal = iirs.Get_Formal(assoc)
if formal == thin.Null_Iir:
self.error(
Location.from_node(assoc),
"association by position for {}".format(
nodeutils.get_identifier_str(inter)))
# Should the tool report all errors ?
return
assoc_inter = thin.Iirs_Utils.Get_Interface_Of_Formal(formal)
while assoc_inter != inter:
if inter == thin.Null_Iir:
self.error(
Location.from_node(assoc),
"incorrect association order for {}".format(
nodeutils.get_identifier_str(assoc_inter)))
return
inter = iirs.Get_Chain(inter)
if iirs.Get_Whole_Association_Flag(assoc):
inter = iirs.Get_Chain(inter)
def check(self, input, ast):
for n in thinutils.concurrent_stmts_iter(ast):
if iirs.Get_Kind(n) \
== iirs.Iir_Kind.Component_Instantiation_Statement:
comp = thin.Iirs_Utils.Get_Entity_From_Entity_Aspect(
iirs.Get_Instantiated_Unit(n))
self.check_assocs(
n, iirs.Get_Generic_Chain(comp),
iirs.Get_Generic_Map_Aspect_Chain(n))
self.check_assocs(
n, iirs.Get_Port_Chain(comp),
iirs.Get_Port_Map_Aspect_Chain(n))
@staticmethod
def test(runner):
rule = CheckAssocs()
TestRunOK(runner, "File without ports",
rule, "hello.vhdl")
TestRunOK(runner, "Simple component",
rule, "assocs1.vhdl")
TestRunFail(runner, "Simple component with incorrect order",
rule, "assocs2.vhdl")
TestRunOK(runner, "Simple component without generics",
rule, "assocs3.vhdl")
TestRunFail(runner, "Component with instantiation by position",
rule, "assocs4.vhdl")
from vhdllint.semrules import SemRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thinutils as thinutils
import libghdl.thin as thin
import vhdllint.nodeutils as nodeutils
class CheckDependences(SemRule):
"""Check all packages are 'imported' by a use clause.
Detect reference to packages that weren't referenced in a context
clause."""
# Check architecture
rulename = 'Dependences'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, ast):
# Build the list of use'd packages.
pkgs = []
for n in thinutils.chain_iter(iirs.Get_Context_Items(ast)):
if iirs.Get_Kind(n) != iirs.Iir_Kind.Use_Clause:
continue
cl = n
while cl != thin.Null_Iir:
name = iirs.Get_Selected_Name(cl)
if iirs.Get_Kind(name) == iirs.Iir_Kind.Selected_By_All_Name:
name = iirs.Get_Prefix(name)
p = iirs.Get_Named_Entity(name)
if iirs.Get_Kind(p) == iirs.Iir_Kind.Package_Declaration:
pkgs.append(p)
cl = iirs.Get_Use_Clause_Chain(cl)
# Check dependences
for du in thinutils.list_iter(iirs.Get_Dependence_List(ast)):
lu = iirs.Get_Library_Unit(du)
if iirs.Get_Kind(lu) == iirs.Iir_Kind.Package_Declaration:
if lu != thin.Standard_Package.value and lu not in pkgs:
self.error(
Location.from_node(ast),
"unit depends on '{}' but not by a use clause".format(
nodeutils.get_identifier_str(lu)))
@staticmethod
def test(runner):
rule = CheckDependences()
TestRunOK(runner, "Correct file",
rule, "hello.vhdl")
TestRunOK(runner, "Use through entity",
rule, "dependences1.vhdl")
TestRunOK(runner, "Normal use",
rule, "dependences2.vhdl")
TestRunFail(runner, "Incorrect use",
rule, "dependences3.vhdl")
TestRunFail(runner, "Incorrect use",
rule, "dependences4.vhdl")
from vhdllint.semrules import SemRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thinutils as thinutils
import vhdllint.nodeutils as nodeutils
class CheckPortsType(SemRule):
"""Check type of ports.
Port of top units must be of type std_logic or std_logic_vector, or
record of these types."""
rulename = 'PortsType'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_type(self, typ):
if nodeutils.is_std_logic_or_std_logic_vector(typ):
return True
basetype = iirs.Get_Base_Type(typ)
if iirs.Get_Kind(basetype) == iirs.Iir_Kind.Record_Type_Definition:
els = iirs.Get_Elements_Declaration_List(basetype)
for el in thinutils.flist_iter(els):
if not self.check_type(iirs.Get_Type(el)):
return False
return True
return False
def check(self, input, ast):
if 'top' not in input.props:
return
unit = iirs.Get_Library_Unit(ast)
if iirs.Get_Kind(unit) != iirs.Iir_Kind.Entity_Declaration:
return
for port in thinutils.chain_iter(iirs.Get_Port_Chain(unit)):
if not self.check_type(iirs.Get_Type(port)):
self.error(
Location.from_node(port),
"type of port '{0}' must be std_logic/_vector".format(
nodeutils.get_identifier_str(port)))
@staticmethod
def test(runner):
rule = CheckPortsType()
TestRunOK(runner, "File without ports",
rule, ['--top', "hello.vhdl"])
TestRunOK(runner, "correct ports",
rule, ['--top', "porttypes1.vhdl"])
TestRunFail(runner, "port std_ulogic",
rule, ['--top', "porttypes2.vhdl"])
TestRunFail(runner, "port std_ulogic_vector",
rule, ['--top', "porttypes3.vhdl"])
TestRunOK(runner, "port with record",
rule, ['--top', "porttypes4.vhdl"])
TestRunFail(runner, "port with bad record",
rule, ['--top', "porttypes5.vhdl"])
TestRunOK(runner, "port with nested record",
rule, ['--top', "porttypes6.vhdl"])
from vhdllint.semrules import SemNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import vhdllint.nodeutils as nodeutils
import libghdl.thin as thin
import libghdl.iirs as iirs
import libghdl.std_names as std_names
class CheckReferences(SemNodeRule):
"""Check case of names is the same as their definition.
References to libraries name must be in lower case.
References to names defined in the IEEE library must be in lower case.
References to names defined in the STD library must be in lower case,
except for control characters which must be in upper case.
TODO: end names, operators."""
rulename = 'References'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._handlers = {}
def get_lower(self, dfn, s):
"""Referenced identifier must be in lower case."""
return s.lower()
def get_standard(self, dfn, s):
"""Referenced indentifier must be in lower case, except for control
characters (which must be in upper case)."""
if iirs.Get_Kind(dfn) == iirs.Iir_Kind.Enumeration_Literal \
and iirs.Get_Type(dfn) == thin.Character_Type_Definition.value:
return s.upper()
else:
return s.lower()
def get_user(self, dfn, s):
"""Referenced identifier must match its definition."""
return nodeutils.get_identifier_str(dfn)
def find_handler(self, n):
"""Return the function to comparse the definition with the
reference."""
dfn_loc = iirs.Get_Location(n)
dfn_file = thin.Location_To_File(dfn_loc)
handler = self._handlers.get(dfn_file, None)
if handler:
return handler
if dfn_loc == thin.Library_Location.value:
handler = self.get_lower
else:
while iirs.Get_Kind(n) != iirs.Iir_Kind.Library_Declaration:
n = iirs.Get_Parent(n)
lib_id = iirs.Get_Identifier(n)
if lib_id == std_names.Name.Std:
handler = self.get_standard
elif lib_id == std_names.Name.Ieee:
handler = self.get_lower
else:
handler = self.get_user
self._handlers[dfn_file] = handler
return handler
def check_identifier(self, node, dfn):
if dfn == 0:
# Can happen for architecture in entity aspect
return
ref_str = nodeutils.get_identifier_str(node)
handler = self.find_handler(dfn)
def_str = handler(dfn, ref_str)
if ref_str == def_str:
# OK!
return
if iirs.Get_Kind(dfn) == iirs.Iir_Kind.Guard_Signal_Declaration:
# Guard signals are implicitely declared
def_str = "GUARD"
if ref_str == def_str:
return
self.error(
Location.from_node(node),
"{} is not the correct spelling for '{}'".format(
ref_str, def_str))
def check(self, input, node):
k = iirs.Get_Kind(node)
if k == iirs.Iir_Kind.Simple_Name \
or k == iirs.Iir_Kind.Selected_Name:
self.check_identifier(node, iirs.Get_Named_Entity(node))
elif k == iirs.Iir_Kind.Selected_Element:
self.check_identifier(node, iirs.Get_Selected_Element(node))
elif k == iirs.Iir_Kind.Library_Clause:
self.check_identifier(node, iirs.Get_Library_Declaration(node))
elif k == iirs.Iir_Kind.Attribute_Name:
attr_val = iirs.Get_Named_Entity(node)
attr_spec = iirs.Get_Attribute_Specification(attr_val)
attr_name = iirs.Get_Attribute_Designator(attr_spec)
self.check_identifier(node, iirs.Get_Named_Entity(attr_name))
@staticmethod
def test(runner):
rule = CheckReferences()
TestRunOK(runner, "File without references",
rule, "hello.vhdl")
TestRunOK(runner, "correct reference (simple name)",
rule, "reference1.vhdl")
TestRunFail(runner, "incorrect reference (simple name)",
rule, "reference2.vhdl")
TestRunOK(runner, "correct reference (library clause)",
rule, "reference3.vhdl")
TestRunFail(runner, "incorrect reference (library clause)",
rule, "reference4.vhdl")
TestRunOK(runner, "correct reference (library name, selected name)",
rule, "reference5.vhdl")
TestRunFail(runner, "incorrect reference (library name)",
rule, "reference6.vhdl")
TestRunFail(runner, "incorrect reference (selected name)",
rule, "reference7.vhdl")
TestRunOK(runner, "correct reference (name from ieee library)",
rule, "reference8.vhdl")
TestRunFail(runner, "incorrect reference (name from ieee library)",
rule, "reference9.vhdl")
TestRunOK(runner, "correct reference (name from standard package)",
rule, "reference10.vhdl")
TestRunFail(runner, "incorrect reference (name from standard package)",
rule, "reference11.vhdl")
TestRunOK(runner, "correct reference (control character name)",
rule, "reference12.vhdl")
TestRunOK(runner, "correct reference (attribute)",
rule, "reference13.vhdl")
TestRunFail(runner, "incorrect reference (attribute spec)",
rule, "reference14.vhdl")
TestRunOK(runner, "correct reference (attribute name)",
rule, "reference15.vhdl")
TestRunFail(runner, "incorrect reference (attribute name)",
rule, "reference16.vhdl")
TestRunOK(runner, "reference to an entity",
rule, "reference17.vhdl")
TestRunOK(runner, "architecture in an entity aspect",
rule, "reference18.vhdl")
TestRunOK(runner, "unknown architecture in an entity aspect",
rule, "reference19.vhdl")
TestRunFail(runner, "incorrect reference to an architecture",
rule, "reference20.vhdl")
from vhdllint.semrules import SemRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
import libghdl.std_names as std_names
import vhdllint.nodeutils as nodeutils
class CheckStdHidding(SemRule):
"""Check that standard names (from std.standard or any ieee package)
are never redeclared by user.
TODO: should have a list of ieee identifiers instead of using those
from use-d packages ?
"""
rulename = 'StdHidding'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._standard_ids = None
self._ieee_ids = set()
self._ieee_pkgs = []
def add_identifier(self, dct, decl):
id = iirs.Get_Identifier(decl)
if id >= std_names.Name.First_Keyword \
and id <= std_names.Name.Last_Vhdl93:
# An operator (like "and")
return
if id >= std_names.Name.First_Operator \
and id <= std_names.Name.Last_Operator:
# An operator (like "/=")
return
if id >= std_names.Name.First_Character \
and id <= std_names.Name.Last_Character:
# A character
return
dct.add(id)
def gather_identifiers(self, pkg):
res = set()
for d in thinutils.chain_iter(iirs.Get_Declaration_Chain(pkg)):
k = iirs.Get_Kind(d)
if d in iirs.Iir_Kinds.Specification:
continue
self.add_identifier(res, d)
if k in [iirs.Iir_Kind.Type_Declaration,
iirs.Iir_Kind.Anonymous_Type_Declaration]:
typ = iirs.Get_Type_Definition(d)
k = iirs.Get_Kind(typ)
if k == iirs.Iir_Kind.Enumeration_Type_Definition:
for lit in thinutils.list_iter(
iirs.Get_Enumeration_Literal_List(typ)):
self.add_identifier(res, lit)
elif k == iirs.Iir_Kind.Physical_Type_Definition:
for un in thinutils.chain_iter(iirs.Get_Unit_Chain(typ)):
self.add_identifier(res, un)
return res
def check(self, input, dsgn):
if self._standard_ids is None:
self._standard_ids = self.gather_identifiers(
thin.Standard_Package.value)
pkgs = nodeutils.extract_packages_from_context_clause(dsgn)
for pkg in pkgs:
lib = iirs.Get_Library(
iirs.Get_Design_File(iirs.Get_Design_Unit(pkg)))
if iirs.Get_Identifier(lib) == std_names.Name.Ieee \
and pkg not in self._ieee_pkgs:
self._ieee_pkgs.append(pkg)
self._ieee_ids = self._ieee_ids.union(
self.gather_identifiers(pkg))
lu = iirs.Get_Library_Unit(dsgn)
for d in thinutils.declarations_iter(lu):
id = iirs.Get_Identifier(d)
if id in self._standard_ids:
self.error(Location.from_node(d),
"declaration of {} uses a standard name".format(
nodeutils.get_identifier_str(d)))
if id in self._ieee_ids:
self.error(Location.from_node(d),
"declaration of {} uses an ieee name".format(
nodeutils.get_identifier_str(d)))
@staticmethod
def test(runner):
rule = CheckStdHidding()
TestRunOK(runner, "File without ieee",
rule, "hello.vhdl")
TestRunFail(runner, "Redefiniton of a standard identifier",
rule, "stdhide1.vhdl")
TestRunFail(runner, "Redefiniton of an ieee identifier",
rule, "stdhide2.vhdl")
from vhdllint.semrules import SemRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import vhdllint.nodeutils as nodeutils
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
class CheckUnused(SemRule):
"""Report unused declarations in architectures and package bodies.
One character loop iterators (like 'for i in ...') are not reported."""
rulename = 'Unused'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
self._handlers = {}
def mark_used(self, n):
self._used.add(n)
def mark(self, unit):
for n in thinutils.nodes_iter(unit):
k = iirs.Get_Kind(n)
if k == iirs.Iir_Kind.Simple_Name \
or k == iirs.Iir_Kind.Selected_Name:
self.mark_used(iirs.Get_Named_Entity(n))
elif k == iirs.Iir_Kind.Selected_Element:
self.mark_used(iirs.Get_Selected_Element(n))
def is_second_subprogram(self, decl):
return iirs.Get_Kind(decl) in iirs.Iir_Kinds.Subprogram_Declaration \
and thin.Iirs_Utils.Is_Second_Subprogram_Specification(decl)
def report_unused(self, unit):
for n in thinutils.declarations_iter(unit):
if n in self._used \
or nodeutils.is_predefined_node(n):
# Node is used (or not user defined)
continue
k = iirs.Get_Kind(n)
if k in [iirs.Iir_Kind.Function_Body,
iirs.Iir_Kind.Procedure_Body]:
# Bodies are never referenced.
continue
if self.is_second_subprogram(n):
# Subprogram specification of a body is never referenced.
continue
if k in iirs.Iir_Kinds.Interface_Object_Declaration:
p = iirs.Get_Parent(n)
if p != thin.Null_Iir \
and self.is_second_subprogram(p):
# Interfaces without parent are from implicit subprograms.
# Interfaces of the subprg spec of the body aren't
# referenced.
continue
if k in [iirs.Iir_Kind.Anonymous_Type_Declaration]:
# Anonymous types are never referenced.
continue
if k == iirs.Iir_Kind.Iterator_Declaration \
and thin.Get_Name_Length(iirs.Get_Identifier(n)) == 1:
# Loop iterator with a very short name (for i in ...)
# Allow it to be unused.
continue
self.error(
Location.from_node(n),
"{} is not used".format(
nodeutils.get_identifier_str(n)))
def check(self, input, unit):
libunit = iirs.Get_Library_Unit(unit)
k = iirs.Get_Kind(libunit)
if k == iirs.Iir_Kind.Architecture_Body:
self._used = set()
ent = thin.Iirs_Utils.Get_Entity(libunit)
self.mark(ent)
self.mark(libunit)
self.report_unused(ent)
self.report_unused(libunit)
elif k == iirs.Iir_Kind.Package_Body:
self._used = set()
self.mark(libunit)
self.report_unused(libunit)
@staticmethod
def test(runner):
rule = CheckUnused()
TestRunOK(runner, "File without references",
rule, "hello.vhdl")
TestRunFail(runner, "Unused port",
rule, "unused1.vhdl")
TestRunOK(runner, "Used generic",
rule, "unused2.vhdl")
TestRunFail(runner, "Unused constant declaration in package body",
rule, "unused3.vhdl")
TestRunOK(runner, "Used function with a specification",
rule, "unused4.vhdl")
"""Syntactic rules.
The files are first parsed (but semantic analysis is not done). checkers
are called for each file, with the unanalyzed AST.
Syntactic rules include indentations, naming conventions for some
identifiers..."""
from vhdllint.rule import Rule
class SyntaxRule(Rule):
def __init__(self, rulename):
super(SyntaxRule, self).__init__(rulename)
def check(self, input, ast):
"""The check to be performed on an AST (a design file)."""
assert False # Must be redefined
class SyntaxNodeRule(Rule):
def __init__(self, rulename):
super(SyntaxNodeRule, self).__init__(rulename)
def check(self, input, node):
"""The check to be performed on each node."""
assert False # Must be redefined
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
import string
class CheckAttributeDecl(SyntaxNodeRule):
"""Check no user attribute declarations."""
rulename = 'NoUserAttributes'
def __init__(self, name=None, allowed=[]):
"""Create the rule
:param execpt: is the list of allowed attribute.
"""
super(self.__class__, self).__init__(name)
self.allowed = [string.lower(attr) for attr in allowed]
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Attribute_Declaration:
s = nodeutils.get_identifier_str(node)
if string.lower(s) not in self.allowed:
self.error(
Location.from_node(node),
"user attribute declaration for '{0}' not allowed".format(
s))
@staticmethod
def test(runner):
rule = CheckAttributeDecl(allowed=['Reserved'])
TestRunOK(runner, "File without attributes",
rule, "hello.vhdl")
TestRunFail(runner, "Simple attribute declaration",
rule, "attrdecl1.vhdl")
TestRunOK(runner, "Allowed attribute declaration",
rule, "attrdecl2.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
import string
class CheckAttributeName(SyntaxNodeRule):
"""Check no user attribute name.
This is a syntax rule, so predefined attribute names are not separated
from user ones, but this check can be applied on a single file.
"""
rulename = 'NoUserAttrName'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
# Some reserved attributes, to be completed ?
self.predefined = ['length', 'left', 'right', 'low', 'high', 'range',
'reverse_range', 'ascending', 'pos', 'val',
'image', 'value',
'event', 'delayed', 'stable', 'quiet']
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Attribute_Name:
s = nodeutils.get_identifier_str(node)
if string.lower(s) not in self.predefined:
self.error(
Location.from_node(node),
"attribute name '{0}' not allowed".format(
s))
@staticmethod
def test(runner):
rule = CheckAttributeName()
TestRunOK(runner, "File without attributes",
rule, "hello.vhdl")
TestRunFail(runner, "Simple attribute name",
rule, "attrname1.vhdl")
TestRunOK(runner, "Predefined attribute name",
rule, "attrname2.vhdl")
This diff is collapsed.
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location, Location_To_File_Line_Col
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.elocations as elocations
class CheckBeginEndLayout(SyntaxRule):
"""Check each process has either a label or a preceeding comment."""
rulename = 'BeginEndLayout'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, ast):
for node in thinutils.constructs_iter(ast):
k = iirs.Get_Kind(node)
if k not in [iirs.Iir_Kind.Architecture_Body,
iirs.Iir_Kind.Block_Statement,
iirs.Iir_Kind.Entity_Declaration,
iirs.Iir_Kind.Generate_Statement_Body,
iirs.Iir_Kind.Process_Statement,
iirs.Iir_Kind.Sensitized_Process_Statement,
iirs.Iir_Kind.Procedure_Body,
iirs.Iir_Kind.Function_Body]:
continue
beg_loc = elocations.Get_Begin_Location(node)
end_loc = elocations.Get_End_Location(node)
if beg_loc == thin.No_Location or end_loc == thin.No_Location:
continue
beg_file, beg_line, beg_col = Location_To_File_Line_Col(beg_loc)
end_file, end_line, end_col = Location_To_File_Line_Col(end_loc)
if end_col != beg_col:
self.error(
Location.from_location(end_loc),
"'begin' and 'end' must be aligned on the same column")
if k in iirs.Iir_Kinds.Subprogram_Body:
if iirs.Get_Declaration_Chain(node) != thin.Null_Iir:
is_loc = elocations.Get_Is_Location(node)
is_file, is_ln, is_col = Location_To_File_Line_Col(is_loc)
if is_col != beg_col:
self.error(
Location.from_location(is_loc),
"'is' and 'begin' must be on the same column")
@staticmethod
def test(runner):
rule = CheckBeginEndLayout()
TestRunOK(runner, "Process without label",
rule, "hello.vhdl")
TestRunOK(runner, "'begin' in entity",
rule, "beginendlayout1.vhdl")
TestRunFail(runner, "unaligned 'begin' in entity",
rule, "beginendlayout2.vhdl")
TestRunFail(runner, "unaligned 'begin' in architecture",
rule, "beginendlayout3.vhdl")
TestRunFail(runner, "unaligned 'begin' in block",
rule, "beginendlayout4.vhdl")
TestRunFail(runner, "unaligned 'begin' in process",
rule, "beginendlayout6.vhdl")
TestRunFail(runner, "unaligned 'begin' in function body",
rule, "beginendlayout7.vhdl")
TestRunFail(runner, "unaligned 'begin' in procedure body",
rule, "beginendlayout8.vhdl")
TestRunFail(runner, "bad column for 'is' in procedure body",
rule, "beginendlayout9.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.elocations as elocs
import vhdllint.utils as utils
class CheckComplexStmtLayout(SyntaxRule):
"""Check complex statement layout:
'then' must be either on the same line or same column as 'if'/'elsif',
'loop' must be on the same line or same column as 'for'/'while',
'is' must be on the same line as 'case',
'generate' must be on the same line or column as 'if'/'for'."""
rulename = 'ComplexStmtLayout'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def chk_line_or_col(self, n, def_loc, loc):
fe = thin.Location_To_File(def_loc)
l_fe = thin.Location_To_File(loc)
assert fe == l_fe, "non-matching file location {} vs {}".format(
def_loc, loc)
def_line = thin.Location_File_To_Line(def_loc, fe)
line = thin.Location_File_To_Line(loc, fe)
if line == def_line:
return
def_col = thin.Location_File_Line_To_Col(def_loc, fe, def_line)
col = thin.Location_File_Line_To_Col(loc, fe, line)
if def_col != col:
self.error(
utils.Location.from_location(loc),
"indentation: must be at col {} instead of {}".format(
def_col, col))
def chk_if_stmt(self, n):
while n != thin.Null_Iir:
loc = iirs.Get_Location(n)
then_loc = elocs.Get_Then_Location(n)
if then_loc != 0:
self.chk_line_or_col(n, loc, then_loc)
n = iirs.Get_Else_Clause(n)
def check(self, input, ast):
for n in thinutils.constructs_iter(ast):
k = iirs.Get_Kind(n)
if k in iirs.Iir_Kinds.Subprogram_Body \
or k in iirs.Iir_Kinds.Process_Statement:
for n1 in thinutils.sequential_iter(n):
k = iirs.Get_Kind(n1)
if k == iirs.Iir_Kind.If_Statement:
self.chk_if_stmt(n1)
elif (k == iirs.Iir_Kind.For_Loop_Statement
or k == iirs.Iir_Kind.While_Loop_Statement):
self.chk_line_or_col(
n1, iirs.Get_Location(n1),
elocs.Get_Loop_Location(n1))
elif k == iirs.Iir_Kind.Case_Statement:
pass
elif k == iirs.Iir_Kind.For_Generate_Statement:
self.chk_line_or_col(
n, iirs.Get_Location(n), elocs.Get_Generate_Location(n))
elif k == iirs.Iir_Kind.If_Generate_Statement:
self.chk_line_or_col(
n, iirs.Get_Location(n), elocs.Get_Generate_Location(n))
@staticmethod
def test(runner):
rule = CheckComplexStmtLayout()
TestRunOK(runner, "Simple file",
rule, "hello.vhdl")
TestRunOK(runner, "Simple if statement",
rule, "complexstmtlayout1.vhdl")
TestRunFail(runner, "Incorrect if statement",
rule, "complexstmtlayout2.vhdl")
TestRunFail(runner, "Incorrect if statement (elsif)",
rule, "complexstmtlayout3.vhdl")
TestRunOK(runner, "Simple for statement",
rule, "complexstmtlayout4.vhdl")
TestRunOK(runner, "Simple for statement (different line)",
rule, "complexstmtlayout5.vhdl")
TestRunFail(runner, "Incorrect for statement",
rule, "complexstmtlayout6.vhdl")
TestRunOK(runner, "Simple while statement",
rule, "complexstmtlayout7.vhdl")
TestRunFail(runner, "Incorrect while statement",
rule, "complexstmtlayout8.vhdl")
TestRunFail(runner, "Incorrect for-generate statement",
rule, "complexstmtlayout9.vhdl")
TestRunFail(runner, "Incorrect if-generate statement",
rule, "complexstmtlayout10.vhdl")
TestRunOK(runner, "Correct case statement",
rule, "complexstmtlayout11.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
class CheckConfigSpec(SyntaxNodeRule):
"""Check no configuration specification."""
rulename = 'ConfigSpec'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
k = iirs.Get_Kind(node)
if k == iirs.Iir_Kind.Configuration_Specification:
self.error(
Location.from_node(node),
"configuration specification not allowed")
@staticmethod
def test(runner):
rule = CheckConfigSpec()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Simple configuration specification",
rule, "configspec1.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
import libghdl.std_names as std_names
import vhdllint.utils as utils
class CheckContextClauses(SyntaxRule):
"""Check that context clauses are organized by groups.
No library clause for 'std' or 'work'."""
rulename = 'Context'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_group(self, clauses):
lib = None
pos = -1
for cl in clauses:
pos += 1
n = cl['node']
if cl['kind'] == 'library':
# Check there is an empty line before.
if pos != 0:
prev_line = clauses[pos - 1]['line']
cur_line = cl['line']
if prev_line >= cur_line - 1:
self.error(Location.from_node(n),
"empty line required before library clause")
if pos == len(clauses) - 1 \
or clauses[pos + 1]['kind'] == 'library':
self.error(Location.from_node(n),
"library clause not followed by use")
if cl['name'] == std_names.Name.Ieee and lib is not None:
self.error(Location.from_node(n),
"library for 'ieee' must be the first")
lib = cl['name']
elif cl['kind'] == 'use':
if cl['library'] == std_names.Name.Std:
# Special case
if lib is not None and lib != std_names.Name.Ieee:
self.error(Location.from_node(n),
"use for std package must be in the "
"ieee group")
if pos < len(clauses) - 1 \
and clauses[pos + 1]['line'] < cl['line'] + 2:
self.error(Location.from_node(n),
"use for std package must be followed "
"by a blank line")
# TODO: check it doesn't appear before library ieee.
else:
if lib is None:
self.error(Location.from_node(n),
"missing library clause for use clause")
elif cl['library'] == std_names.Name.Work:
# More checks needed: should be a separate group.
pass
elif cl['library'] != lib:
self.error(Location.from_node(n),
"use clause not below the corresponding "
"library clause")
def extract_library(self, n):
name = iirs.Get_Identifier(n)
if iirs.Get_Has_Identifier_List(n):
self.error(Location.from_node(n),
"library must be alone")
if name == std_names.Name.Std:
self.error(Location.from_node(n),
"do not use library clause for 'std'")
elif name == std_names.Name.Work:
self.error(Location.from_node(n),
"do not use library clause for 'work'")
loc = iirs.Get_Location(n)
_, ln, _ = utils.Location_To_File_Line_Col(loc)
return [{'kind': 'library',
'node': n,
'name': name,
'line': ln}]
def extract_use(self, n):
if iirs.Get_Use_Clause_Chain(n):
self.error(Location.from_node(n),
"there must be an one package per use")
name = iirs.Get_Selected_Name(n)
if iirs.Get_Kind(name) != iirs.Iir_Kind.Selected_By_All_Name:
self.error(Location.from_node(n),
"missing .all after package name")
return []
prefix = iirs.Get_Prefix(name)
if iirs.Get_Kind(prefix) != iirs.Iir_Kind.Selected_Name:
self.error(Location.from_node(n),
"use-d name must be a selected name")
return []
lib_prefix = iirs.Get_Prefix(prefix)
if iirs.Get_Kind(lib_prefix) != iirs.Iir_Kind.Simple_Name:
self.error(Location.from_node(n),
"use-d prefix name must be a simple name")
return []
loc = iirs.Get_Location(n)
_, ln, _ = utils.Location_To_File_Line_Col(loc)
return [{'kind': 'use',
'node': n,
'name': iirs.Get_Identifier(prefix),
'library': iirs.Get_Identifier(lib_prefix),
'line': ln}]
def check(self, input, file):
for unit in thinutils.chain_iter(iirs.Get_First_Design_Unit(file)):
# Extract the list of clauses
clauses = []
for cl in thinutils.chain_iter(iirs.Get_Context_Items(unit)):
k = iirs.Get_Kind(cl)
if k == iirs.Iir_Kind.Library_Clause:
clauses.extend(self.extract_library(cl))
elif k == iirs.Iir_Kind.Use_Clause:
clauses.extend(self.extract_use(cl))
else:
assert False, "unknown context clause"
if clauses:
self.check_group(clauses)
@staticmethod
def test(runner):
rule = CheckContextClauses()
TestRunOK(runner, "File without ieee",
rule, "hello.vhdl")
TestRunOK(runner, "simple use of textio",
rule, "contextclauses1.vhdl")
TestRunFail(runner, "incorrect library clause for work",
rule, "contextclauses2.vhdl")
TestRunFail(runner, "incorrect library clause for std",
rule, "contextclauses3.vhdl")
TestRunOK(runner, "more complex example",
rule, "contextclauses4.vhdl")
TestRunFail(runner, "missing empty line before library clause",
rule, "contextclauses5.vhdl")
TestRunFail(runner, "multiple libraries for the same clause",
rule, "contextclauses6.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
class CheckContextUse(SyntaxNodeRule):
"""Check use clauses are placed in context clauses."""
rulename = 'ContextUse'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Use_Clause:
parent = iirs.Get_Parent(node)
if iirs.Get_Kind(parent) != iirs.Iir_Kind.Design_Unit:
self.error(
Location.from_node(node),
"use clause must be global (placed before the unit)")
@staticmethod
def test(runner):
rule = CheckContextUse()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunOK(runner, "Global use clause",
rule, "contextuse1.vhdl")
TestRunFail(runner, "Local use clause",
rule, "contextuse2.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
class CheckDisconnection(SyntaxNodeRule):
"""Check no disconnection specification."""
rulename = 'Disconnection'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
k = iirs.Get_Kind(node)
if k == iirs.Iir_Kind.Disconnection_Specification:
self.error(
Location.from_node(node),
"disconnection specification not allowed")
@staticmethod
def test(runner):
rule = CheckDisconnection()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Simple disconnection specification",
rule, "disconnect1.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import vhdllint.nodeutils as nodeutils
import libghdl.elocations as elocations
import libghdl.iirs as iirs
class CheckEndLabel(SyntaxNodeRule):
"""Check no group nor group template declaration."""
rulename = 'EndLabel'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_end(self, node, idnode):
idn = iirs.Get_Identifier(idnode)
if idn != 0 and not iirs.Get_End_Has_Identifier(node):
self.error(
Location.from_location(elocations.Get_End_Location(node)),
"missing '{}' after 'end'".format(
nodeutils.get_identifier_str(idnode)))
def check(self, input, node):
k = iirs.Get_Kind(node)
if k in [iirs.Iir_Kind.Entity_Declaration,
iirs.Iir_Kind.Package_Declaration,
iirs.Iir_Kind.Package_Body,
iirs.Iir_Kind.Architecture_Body,
iirs.Iir_Kind.Configuration_Declaration,
iirs.Iir_Kind.Protected_Type_Declaration,
iirs.Iir_Kind.For_Loop_Statement,
iirs.Iir_Kind.While_Loop_Statement,
iirs.Iir_Kind.Case_Statement,
iirs.Iir_Kind.If_Statement,
iirs.Iir_Kind.Block_Statement,
iirs.Iir_Kind.Sensitized_Process_Statement,
iirs.Iir_Kind.Process_Statement,
iirs.Iir_Kind.If_Generate_Statement,
iirs.Iir_Kind.For_Generate_Statement]:
self.check_end(node, node)
elif k in [iirs.Iir_Kind.Procedure_Body,
iirs.Iir_Kind.Function_Body]:
idnode = iirs.Get_Subprogram_Specification(node)
self.check_end(node, idnode)
elif k == iirs.Iir_Kind.Type_Declaration:
df = iirs.Get_Type_Definition(node)
if iirs.Get_Kind(df) in [iirs.Iir_Kind.Physical_Type_Definition,
iirs.Iir_Kind.Record_Type_Definition]:
self.check_end(df, node)
@staticmethod
def test(runner):
rule = CheckEndLabel()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Simple entity without end label",
rule, "endlabel1.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import vhdllint.utils as utils
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.elocations as elocations
class CheckEntityLayout(SyntaxRule):
"""Check layout of entity declarations.
Ports and generics must be declared one per line,
name, ':', subtype indication and ':=' must be aligned."""
rulename = 'EntityLayout'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_declarations(self, decl):
decl_col = -1
colon_col = -1
subtype_col = -1
assign_col = -1
line = -1
while decl != thin.Null_Iir:
loc = elocations.Get_Start_Location(decl)
fe, ln, co = utils.Location_To_File_Line_Col(loc)
if ln <= line:
self.error(Location.from_node(decl),
"one generic/port per line")
else:
if co != decl_col and decl_col >= 0:
self.error(Location.from_node(decl),
"name is not aligned with previous one")
# Check alignment of ':'
colon_loc = elocations.Get_Colon_Location(decl)
_, ln1, colon_co = utils.Location_To_File_Line_Col(colon_loc)
if colon_co != colon_col and colon_col >= 0:
self.error(Location.from_node(decl),
"':' is not aligned with previous one")
colon_col = colon_co
# Check alignment of subtype.
st = iirs.Get_Subtype_Indication(decl)
if st != thin.Null_Iir:
st_loc = thinutils.leftest_location(st)
_, ln1, st_co = utils.Location_To_File_Line_Col(st_loc)
if st_co != subtype_col and subtype_col >= 0:
self.error(Location.from_node(decl),
"subtype is not aligned with previous one")
subtype_col = st_co
# Check alignment of ':='
assign_loc = elocations.Get_Assign_Location(decl)
if assign_loc != thin.No_Location:
_, ln1, assign_co = \
utils.Location_To_File_Line_Col(assign_loc)
if assign_co != assign_col and assign_col >= 0:
self.error(Location.from_node(decl),
"':=' is not aligned with previous one")
assign_col = assign_co
decl_col = co
line = ln
decl = iirs.Get_Chain(decl)
def check(self, input, ast):
for du in thinutils.chain_iter(iirs.Get_First_Design_Unit(ast)):
ent = iirs.Get_Library_Unit(du)
if iirs.Get_Kind(ent) != iirs.Iir_Kind.Entity_Declaration:
continue
gen = iirs.Get_Generic_Chain(ent)
if gen != thin.Null_Iir:
self.check_declarations(gen)
ports = iirs.Get_Port_Chain(ent)
if ports != thin.Null_Iir:
self.check_declarations(ports)
port = ports
while port != thin.Null_Iir:
if not iirs.Get_Has_Mode(port):
self.error(Location.from_node(port),
"in/out/inout required for port")
port = iirs.Get_Chain(port)
@staticmethod
def test(runner):
rule = CheckEntityLayout()
TestRunOK(runner, "arch without instantiation",
rule, "hello.vhdl")
TestRunOK(runner, "Simple entity",
rule, "entitylayout1.vhdl")
TestRunFail(runner, "':=' not correctly aligned",
rule, "entitylayout2.vhdl")
TestRunFail(runner, "':' not correctly aligned",
rule, "entitylayout3.vhdl")
TestRunFail(runner, "subtype not correctly aligned",
rule, "entitylayout4.vhdl")
TestRunFail(runner, "identifier list",
rule, "entitylayout5.vhdl")
TestRunFail(runner, "missing mode for port",
rule, "entitylayout6.vhdl")
TestRunOK(runner, "Simple entity with a bit_vector",
rule, "entitylayout7.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
class CheckEntitySimple(SyntaxRule):
"""Check entities are simple: no declarations, only assert statements
are allowed.
"""
rulename = 'EntityItems'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_entity(self, ent):
decl = iirs.Get_Declaration_Chain(ent)
if decl != thin.Null_Iir:
self.error(Location.from_node(decl),
"declaration not allowed in entity")
first_stmt = iirs.Get_Concurrent_Statement_Chain(ent)
for s in thinutils.chain_iter(first_stmt):
k = iirs.Get_Kind(s)
if k != iirs.Iir_Kind.Concurrent_Assertion_Statement:
self.error(Location.from_node(s),
"concurrent statement not allowed in entity")
def check(self, input, ast):
assert iirs.Get_Kind(ast) == iirs.Iir_Kind.Design_File
for u in thinutils.chain_iter(iirs.Get_First_Design_Unit(ast)):
lu = iirs.Get_Library_Unit(u)
if iirs.Get_Kind(lu) == iirs.Iir_Kind.Entity_Declaration:
self.check_entity(lu)
@staticmethod
def test(runner):
rule = CheckEntitySimple()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Entity with a declaration",
rule, "entityitems1.vhdl")
TestRunFail(runner, "Entity with a process",
rule, "entityitems2.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
class CheckEnum(SyntaxNodeRule):
"""Check names of enumeration literals."""
rulename = 'EnumName'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Enumeration_Literal:
s = nodeutils.get_identifier_str(node)
if not s.isupper():
self.error(
Location.from_node(node),
"enumeration literal '{0}' must be in upper case".format(
s))
@staticmethod
def test(runner):
rule = CheckEnum()
TestRunOK(runner, "File without enum",
rule, "hello.vhdl")
TestRunOK(runner, "Simple enum",
rule, "enum1.vhdl")
TestRunFail(runner, "Simple enum with incorrect case",
rule, "enum2.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.std_names as std_names
class CheckEnumCharLit(SyntaxNodeRule):
"""Check no character for enumeration literal."""
rulename = 'NoCharEnumLit'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Enumeration_Literal:
if iirs.Get_Identifier(node) <= std_names.Name.Last_Character:
self.error(
Location.from_node(node),
"character not allowed in enumeration declaration")
@staticmethod
def test(runner):
rule = CheckEnumCharLit()
TestRunOK(runner, "File without attributes",
rule, "hello.vhdl")
TestRunFail(runner, "Enumerated type with character",
rule, "enumcharlit1.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
import os.path
class CheckFileName(SyntaxRule):
"""Check fiel name."""
rulename = 'FileName'
def __init__(self, name=None, extension='.vhdl'):
super(self.__class__, self).__init__(name)
self.extension = extension
def check(self, input, ast):
assert iirs.Get_Kind(ast) == iirs.Iir_Kind.Design_File
unit = iirs.Get_First_Design_Unit(ast)
lu = iirs.Get_Library_Unit(unit)
s = nodeutils.get_identifier_str(lu)
filename = s + self.extension
if os.path.basename(input.filename) != filename:
self.error(Location.from_node(unit),
"filename must be {0}".format(filename))
@staticmethod
def test(runner):
rule = CheckFileName()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "File with incorrect name",
rule, "filename1.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import vhdllint.nodeutils as nodeutils
class CheckGenerics(SyntaxNodeRule):
"""Check names of generics."""
rulename = 'GenericsName'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if nodeutils.is_generic(node):
s = nodeutils.get_identifier_str(node)
if not s.startswith("g_"):
self.error(Location.from_node(node),
"generic '{0}' must start with 'g_'".format(s))
if not s[2:].isupper():
self.error(
Location.from_node(node),
"generic '{0}' must be in upper case after 'g_'".format(s))
@staticmethod
def test(runner):
rule = CheckGenerics()
TestRunOK(runner, "File without generics",
rule, "hello.vhdl")
TestRunOK(runner, "correct generic",
rule, "generic1.vhdl")
TestRunFail(runner, "generic not in upper case",
rule, "generic2.vhdl")
TestRunFail(runner, "generic without 'g_' prefix",
rule, "generic3.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
class CheckGroup(SyntaxNodeRule):
"""Check no group nor group template declaration."""
rulename = 'GroupDeclaration'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
k = iirs.Get_Kind(node)
if k == iirs.Iir_Kind.Group_Declaration:
self.error(
Location.from_node(node),
"group declaration not allowed")
elif k == iirs.Iir_Kind.Group_Template_Declaration:
self.error(
Location.from_node(node),
"group template declaration not allowed")
@staticmethod
def test(runner):
rule = CheckGroup()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Simple disconnection specification",
rule, "group1.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import vhdllint.nodeutils as nodeutils
import libghdl.iirs as iirs
class CheckGuardedSignals(SyntaxNodeRule):
"""Check no guarded signals."""
rulename = 'GuardedSignals'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
k = iirs.Get_Kind(node)
if k == iirs.Iir_Kind.Signal_Declaration \
or k == iirs.Iir_Kind.Interface_Signal_Declaration:
if iirs.Get_Guarded_Signal_Flag(node):
self.error(
Location.from_node(node),
"signal '{0}' must not be guarded".format(
nodeutils.get_identifier_str(node)))
@staticmethod
def test(runner):
rule = CheckGuardedSignals()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Guarded signal declaration",
rule, "guardedsignal1.vhdl")
TestRunOK(runner, "resolved signal declaration",
rule, "guardedsignal2.vhdl")
TestRunFail(runner, "Guarded interface",
rule, "guardedsignal3.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
import libghdl.std_names as std_names
import vhdllint.nodeutils as nodeutils
class CheckIeeePackages(SyntaxRule):
"""Check that only standard IEEE packages are referenced in use clauses.
This check only applies to 'synth' units.
Only top-level use clauses are checked."""
rulename = 'IeeePackages'
def __init__(self, extra_pkg=[], name=None):
super(self.__class__, self).__init__(name)
# Add math_real and math_complex ?
# Add vhdl-2008 packages ?
self._allowed_name = ["std_logic_1164", "numeric_std"]
self._allowed_name.extend(extra_pkg)
self._allowed_id = None
def check_clause(self, cl):
name = iirs.Get_Selected_Name(cl)
if iirs.Get_Kind(name) == iirs.Iir_Kind.Selected_By_All_Name:
name = iirs.Get_Prefix(name)
if iirs.Get_Kind(name) != iirs.Iir_Kind.Selected_Name:
self.error(Location.from_node(name),
"unhandled use clause form")
return
lib = iirs.Get_Prefix(name)
if iirs.Get_Kind(lib) != iirs.Iir_Kind.Simple_Name:
self.error(Location.from_node(name),
"unhandled use clause form")
return
if iirs.Get_Identifier(lib) != std_names.Name.Ieee:
# User package ?
return
if iirs.Get_Identifier(name) not in self._allowed_id:
self.error(Location.from_node(name),
"non-allowed use of IEEE package {}".format(
nodeutils.get_identifier_str(name)))
def check(self, input, file):
if self._allowed_id is None:
self._allowed_id = [thin.Get_Identifier(n)
for n in self._allowed_name]
for unit in thinutils.chain_iter(iirs.Get_First_Design_Unit(file)):
for n in thinutils.chain_iter(iirs.Get_Context_Items(unit)):
if iirs.Get_Kind(n) != iirs.Iir_Kind.Use_Clause:
continue
cl = n
while cl != thin.Null_Iir:
self.check_clause(cl)
cl = iirs.Get_Use_Clause_Chain(cl)
@staticmethod
def test(runner):
rule = CheckIeeePackages()
TestRunOK(runner, "File without ieee",
rule, "hello.vhdl")
TestRunOK(runner, "standard ieee package",
rule, "ieeepkg1.vhdl")
TestRunFail(runner, "non-standard ieee package",
rule, "ieeepkg2.vhdl")
This diff is collapsed.
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import vhdllint.utils as utils
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.elocations as elocations
class CheckInstantiation(SyntaxRule):
"""Check layout of component instantiation"""
# TODO: check order (need sem)
# check 'generic' and 'port' on a different line
rulename = 'Instantiation'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_associations(self, assoc):
col = -1
line = -1
while assoc != thin.Null_Iir:
if iirs.Get_Formal(assoc) == thin.Null_Iir:
self.error(Location.from_node(assoc),
"association by name required")
else:
loc = elocations.Get_Arrow_Location(assoc)
fe, ln, co = utils.Location_To_File_Line_Col(loc)
if ln <= line:
self.error(Location.from_node(assoc),
"one association per line")
elif col != co and col >= 0:
self.error(Location.from_node(assoc),
"`=>` place is not aligned with previous one")
col = co
line = ln
assoc = iirs.Get_Chain(assoc)
def check(self, input, ast):
for node in thinutils.concurrent_stmts_iter(ast):
k = iirs.Get_Kind(node)
if k != iirs.Iir_Kind.Component_Instantiation_Statement:
continue
self.check_associations(iirs.Get_Generic_Map_Aspect_Chain(node))
self.check_associations(iirs.Get_Port_Map_Aspect_Chain(node))
@staticmethod
def test(runner):
rule = CheckInstantiation()
TestRunOK(runner, "arch without instantiation",
rule, "hello.vhdl")
TestRunOK(runner, "Correct instantiation",
rule, "instantiation1.vhdl")
TestRunFail(runner, "association not by name",
rule, "instantiation2.vhdl")
TestRunFail(runner, "association on the same line",
rule, "instantiation3.vhdl")
TestRunFail(runner, "associations not aligned",
rule, "instantiation4.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
class CheckNameDecl(SyntaxNodeRule):
"""Check name of declarations."""
rulename = 'NameDecl'
def __init__(self, kind=None, predicate=None, name=None):
"""Create the rule
:param kind: only these nodes are checked.
:param predicate: predicate on the name
"""
super(self.__class__, self).__init__(name)
self.kind = kind
self.predicate = predicate
def check(self, input, node):
if iirs.Get_Kind(node) == self.kind:
s = nodeutils.get_identifier_str(node)
if not self.predicate(s):
self.error(Location.from_node(node),
"incorrect name '{}'".format(s))
@staticmethod
def test(runner):
rule = CheckNameDecl(kind=iirs.Iir_Kind.Constant_Declaration,
predicate=(lambda s: s != 'Reserved'))
TestRunOK(runner, "File without attributes",
rule, "hello.vhdl")
TestRunFail(runner, "Incorrect name",
rule, "namedecl1.vhdl")
TestRunOK(runner, "Correct name",
rule, "namedecl2.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
class CheckOneUnit(SyntaxRule):
"""Check each file contains one module.
A module is either a design unit, or an entity and its architecture, or
an entity, its architecture and its configuration.
:param patterns: is the list of allowed units; each letter represents
a kind of unit:
E: Entity, A: Architecture, P: Package, B: package Body,
C: Configuration.
"""
rulename = 'OneModule'
def __init__(self, name=None, patterns=['E', 'EA', 'EAC',
'A', 'P', 'PB', 'C']):
super(self.__class__, self).__init__(name)
self.patterns = patterns
def check_entity(self, units):
ent = iirs.Get_Library_Unit(units[0])
assert iirs.Get_Kind(ent) == iirs.Iir_Kind.Entity_Declaration
arch = iirs.Get_Library_Unit(units[1])
if iirs.Get_Kind(arch) != iirs.Iir_Kind.Architecture_Body:
self.error(Location.from_node(arch),
"second unit of a file must be an architecture")
return
arch_ent = iirs.Get_Entity_Name(arch)
if iirs.Get_Kind(arch_ent) != iirs.Iir_Kind.Simple_Name:
# Strictly speaking, a selected name is allowed.
self.error(Location.from_node(arch_ent),
"weird entity name in architecture")
return
if iirs.Get_Identifier(arch_ent) != iirs.Get_Identifier(ent):
self.error(Location.from_node(arch_ent),
"unrelated architecture after entity")
return
if len(units) == 2:
return
conf = iirs.Get_Library_Unit(units[2])
if iirs.Get_Kind(conf) != iirs.Iir_Kind.Configuration_Declaration:
self.error(Location.from_node(arch),
"third unit must be a configuration")
# TODO: check it is related to the architecture
if len(units) > 3:
self.error(Location.from_node(units[3]),
"too many units in a file")
def check_package(self, units):
decl = iirs.Get_Library_Unit(units[0])
assert iirs.Get_Kind(decl) == iirs.Iir_Kind.Package_Declaration
bod = iirs.Get_Library_Unit(units[1])
if iirs.Get_Kind(bod) != iirs.Iir_Kind.Package_Body:
self.error(Location.from_node(bod),
"second unit of a file must be a package body")
return
if iirs.Get_Identifier(bod) != iirs.Get_Identifier(decl):
self.error(Location.from_node(bod),
"unrelated package body after package declaration")
return
if len(units) > 2:
self.error(Location.from_node(units[2]),
"too many units in a file")
def check(self, input, ast):
assert iirs.Get_Kind(ast) == iirs.Iir_Kind.Design_File
units = thinutils.chain_to_list(iirs.Get_First_Design_Unit(ast))
pattern = ''
letter = {iirs.Iir_Kind.Entity_Declaration: 'E',
iirs.Iir_Kind.Architecture_Body: 'A',
iirs.Iir_Kind.Configuration_Declaration: 'C',
iirs.Iir_Kind.Package_Declaration: 'P',
iirs.Iir_Kind.Package_Body: 'B'}
pattern = ''.join([letter[iirs.Get_Kind(iirs.Get_Library_Unit(u))]
for u in units])
if pattern not in self.patterns:
self.error(Location(input.filename),
"sequence of units not allowed")
if len(units) <= 1:
# Always ok to have one unit. Zero unit is not allowed by vhdl.
return
first = iirs.Get_Library_Unit(units[0])
if iirs.Get_Kind(first) == iirs.Iir_Kind.Entity_Declaration:
self.check_entity(units)
elif iirs.Get_Kind(first) == iirs.Iir_Kind.Package_Declaration:
self.check_package(units)
else:
self.error(Location.from_node(first),
"first unit must be either an entity or a package")
@staticmethod
def test(runner):
rule = CheckOneUnit()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunOK(runner, "File with one unit (entity)",
rule, "onemodule1.vhdl")
TestRunOK(runner, "File with one unit (architecture)",
rule, "onemodule2.vhdl")
TestRunFail(runner, "File with unrelated architecture",
rule, "onemodule3.vhdl")
TestRunOK(runner, "File with package and its body",
rule, "onemodule4.vhdl")
TestRunFail(runner, "File with package and unrelated body",
rule, "onemodule5.vhdl")
TestRunFail(runner, "File two packages",
rule, "onemodule6.vhdl")
TestRunFail(runner, "File more than a package and its body",
rule, "onemodule7.vhdl")
TestRunOK(runner, "File with entity, arch and configuration",
rule, "onemodule8.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.elocations as elocations
class CheckParenthesis(SyntaxNodeRule):
"""Check for useless parenthesis."""
rulename = 'Parenthesis'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_parenthesis(self, expr):
if expr == thin.Null_Iir:
# For else clause.
return
if iirs.Get_Kind(expr) != iirs.Iir_Kind.Parenthesis_Expression:
return
left_loc = iirs.Get_Location(expr)
right_loc = elocations.Get_Right_Paren_Location(expr)
fe = thin.Location_To_File(left_loc)
assert fe == thin.Location_To_File(right_loc)
left_line = thin.Location_File_To_Line(left_loc, fe)
right_line = thin.Location_File_To_Line(right_loc, fe)
if left_line != right_line:
# Assume that's for grouping
return
self.error(Location.from_node(expr),
"useless parenthesis around expression")
def check(self, input, node):
k = iirs.Get_Kind(node)
if k in [iirs.Iir_Kind.If_Statement,
iirs.Iir_Kind.Elsif,
iirs.Iir_Kind.While_Loop_Statement,
iirs.Iir_Kind.Exit_Statement,
iirs.Iir_Kind.Next_Statement,
iirs.Iir_Kind.If_Generate_Statement,
iirs.Iir_Kind.If_Generate_Else_Clause,
iirs.Iir_Kind.Conditional_Waveform,
iirs.Iir_Kind.Conditional_Expression]:
self.check_parenthesis(iirs.Get_Condition(node))
elif k in [iirs.Iir_Kind.Case_Generate_Statement,
iirs.Iir_Kind.Case_Statement,
iirs.Iir_Kind.Concurrent_Selected_Signal_Assignment,
iirs.Iir_Kind.Selected_Waveform_Assignment_Statement,
iirs.Iir_Kind.Return_Statement]:
self.check_parenthesis(iirs.Get_Expression(node))
@staticmethod
def test(runner):
rule = CheckParenthesis()
TestRunOK(runner, "File without ports",
rule, "hello.vhdl")
TestRunFail(runner, "Useless parenthesis for if",
rule, "paren1.vhdl")
TestRunOK(runner, "if statement",
rule, "paren2.vhdl")
TestRunOK(runner, "if statement with a very long condition",
rule, "paren3.vhdl")
TestRunOK(runner, "Return statement without parenthesis",
rule, "paren4.vhdl")
TestRunFail(runner, "Useless parenthesis for return",
rule, "paren5.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
class CheckPortsMode(SyntaxNodeRule):
"""Check mode of ports."""
rulename = 'PortMode'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if nodeutils.is_port(node):
mode = iirs.Get_Mode(node)
if mode == iirs.Iir_Mode.Buffer_Mode:
self.error(Location.from_node(node),
"buffer port '{0}' not allowed".format(
nodeutils.get_identifier_str(node)))
elif mode == iirs.Iir_Mode.Linkage_Mode:
self.error(Location.from_node(node),
"linkage port '{0}' not allowed".format(
nodeutils.get_identifier_str(node)))
@staticmethod
def test(runner):
rule = CheckPortsMode()
TestRunOK(runner, "File without ports",
rule, "hello.vhdl")
TestRunOK(runner, "correct ports",
rule, "port1.vhdl")
TestRunFail(runner, "not allowed buffer port",
rule, "port4.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
class CheckPortsName(SyntaxNodeRule):
"""Check names of ports."""
rulename = 'PortsName'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if nodeutils.is_port(node):
s = nodeutils.get_identifier_str(node)
mode = iirs.Get_Mode(node)
if mode == iirs.Iir_Mode.Out_Mode:
if not s.endswith('_o'):
self.error(Location.from_node(node),
"out port '{0}' must end with '_o'".format(s))
elif mode == iirs.Iir_Mode.In_Mode:
if not s.endswith('_i'):
self.error(Location.from_node(node),
"in port '{0}' must end with '_i'".format(s))
elif mode == iirs.Iir_Mode.Inout_Mode:
if not s.endswith('_b'):
self.error(Location.from_node(node),
"inout port '{0}' must end with '_b'".format(s))
elif mode == iirs.Iir_Mode.Buffer_Mode:
self.error(Location.from_node(node),
"buffer port '{0}' not allowed".format(s))
elif mode == iirs.Iir_Mode.Linkage_Mode:
self.error(Location.from_node(node),
"linkage port '{0}' not allowed".format(s))
@staticmethod
def test(runner):
rule = CheckPortsName()
TestRunOK(runner, "File without ports",
rule, "hello.vhdl")
TestRunOK(runner, "correct ports",
rule, "port1.vhdl")
TestRunFail(runner, "incorrect out port",
rule, "port2.vhdl")
TestRunFail(runner, "incorrect in port",
rule, "port3.vhdl")
TestRunFail(runner, "not allowed buffer port",
rule, "port4.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
class CheckProcessLabel(SyntaxRule):
"""Check each process has either a label or a preceeding comment."""
rulename = 'ProcessLabel'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, ast):
for node in thinutils.concurrent_stmts_iter(ast):
if iirs.Get_Kind(node) not in iirs.Iir_Kinds.Process_Statement:
continue
if iirs.Get_Label(node) != thin.Null_Identifier:
continue
loc = iirs.Get_Location(node)
fil = thin.Location_To_File(loc)
line = thin.Location_File_To_Line(loc, fil)
if input.comments.get(line - 1, None) is None:
self.error(
Location.from_node(node),
"missing label or comment for process")
@staticmethod
def test(runner):
rule = CheckProcessLabel()
TestRunFail(runner, "Process without label",
rule, "hello.vhdl")
TestRunOK(runner, "Process with a label",
rule, "processlabel1.vhdl")
TestRunOK(runner, "Process with a comment",
rule, "processlabel2.vhdl")
TestRunFail(runner, "Process without a comment",
rule, "processlabel3.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
class CheckSignalsName(SyntaxNodeRule):
"""Check names of signals."""
rulename = 'SignalsName'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check_name(self, node, name):
orig_name = name
if len(name) > 2 and name[-2] == '_' and name[-1] in 'oib':
name = name[:-2]
if name.endswith('_n'):
name = name[:-2]
if name.endswith('_a'):
name = name[:-2]
while True:
if name.endswith('_p'):
name = name[:-2]
elif name.endswith('_d'):
name = name[:-2]
elif (len(name) > 3 and name[-3] == '_'
and name[-2] == 'd' and name[-1].isdigit()):
name = name[:-3]
else:
break
if name.endswith('_n'):
self.error(Location.from_node(node),
"'_n' suffix of signal '{}' is too early".format(
orig_name))
if name.endswith('_a'):
self.error(Location.from_node(node),
"'_a' suffix of signal '{}' is too early".format(
orig_name))
def check(self, input, node):
if nodeutils.is_port(node):
s = nodeutils.get_identifier_str(node)
self.check_name(node, s)
elif iirs.Get_Kind(node) == iirs.Iir_Kind.Signal_Declaration:
s = nodeutils.get_identifier_str(node)
self.check_name(node, s)
@staticmethod
def test(runner):
rule = CheckSignalsName()
TestRunOK(runner, "File without ports",
rule, "hello.vhdl")
TestRunOK(runner, "correct signals",
rule, "signalsname1.vhdl")
TestRunOK(runner, "signal with a direction suffix",
rule, "signalsname2.vhdl")
TestRunFail(runner, "bad suffix order in signal name",
rule, "signalsname3.vhdl")
from vhdllint.syntaxrules import SyntaxNodeRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location
import libghdl.iirs as iirs
import libghdl.thin as thin
class CheckSimpleBlock(SyntaxNodeRule):
"""Check block statements declare neither ports, nor generics nor
implicit GUARD signal."""
rulename = 'BlockStatement'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, node):
if iirs.Get_Kind(node) == iirs.Iir_Kind.Block_Statement:
hdr = iirs.Get_Block_Header(node)
if hdr != thin.Null_Iir:
if iirs.Get_Generic_Chain(hdr) != thin.Null_Iir:
self.error(
Location.from_node(node),
"block cannot declare generics")
if iirs.Get_Port_Chain(hdr) != thin.Null_Iir:
self.error(
Location.from_node(node),
"block cannot declare ports")
if iirs.Get_Guard_Decl(node) != thin.Null_Iir:
self.error(
Location.from_node(node),
"block cannot have an implicit GUARD signal")
@staticmethod
def test(runner):
rule = CheckSimpleBlock()
TestRunOK(runner, "File with an entity and an architecture",
rule, "hello.vhdl")
TestRunFail(runner, "Block with a generic",
rule, "simpleblock1.vhdl")
TestRunFail(runner, "Block with a port",
rule, "simpleblock2.vhdl")
TestRunFail(runner, "Block with a GUARD",
rule, "simpleblock3.vhdl")
TestRunOK(runner, "Simple block",
rule, "simpleblock4.vhdl")
from vhdllint.syntaxrules import SyntaxRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
from vhdllint.utils import Location, Location_To_File_Line_Col
import libghdl.iirs as iirs
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.elocations as elocations
class CheckSubprgIsLayout(SyntaxRule):
"""Check location of `is` in subprogram bodies: must be on the same column
as function/procedure if there are declarations."""
rulename = 'SubprgIsLayout'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def check(self, input, ast):
for node in thinutils.constructs_iter(ast):
k = iirs.Get_Kind(node)
if k not in iirs.Iir_Kinds.Subprogram_Body:
continue
if iirs.Get_Declaration_Chain(node) == thin.Null_Iir:
continue
is_loc = elocations.Get_Is_Location(node)
is_file, is_ln, is_col = Location_To_File_Line_Col(is_loc)
beg_loc = elocations.Get_Begin_Location(node)
beg_file, beg_line, beg_col = Location_To_File_Line_Col(beg_loc)
if is_col != beg_col:
self.error(
Location.from_location(is_loc),
"'is' and 'begin' must be on the same column")
@staticmethod
def test(runner):
rule = CheckSubprgIsLayout()
TestRunOK(runner, "correct column for 'is' in procedure body",
rule, "subprgislayout1.vhdl")
TestRunFail(runner, "bad column for 'is' in procedure body",
rule, "subprgislayout2.vhdl")
"""Synthesis rules.
The files are analyzed. Checkers are called for each unit.
Synthesis rules are rules specific to non-testbench files."""
from vhdllint.rule import Rule
class SynthesisRule(Rule):
def __init__(self, rulename):
super(SynthesisRule, self).__init__(rulename)
def check(self, input, ast):
"""The check to be performed on an AST (a design unit)."""
assert False # Must be redefined
from vhdllint.synthrules import SynthesisRule
from vhdllint.rulesexec import TestRunOK, TestRunFail
import libghdl.thin as thin
import libghdl.thinutils as thinutils
import libghdl.iirs as iirs
import vhdllint.nodeutils as nodeutils
from vhdllint.utils import Location
class CheckProcesses(SynthesisRule):
"""Check processes: only processes with a sensitivity list."""
rulename = 'SynthProcesses'
def __init__(self, name=None):
super(self.__class__, self).__init__(name)
def is_edge_condition(self, cond):
k = iirs.Get_Kind(cond)
if k != iirs.Iir_Kind.Function_Call:
# TODO: allow 'event ?
return (None, None)
imp = iirs.Get_Implementation(cond)
if imp == thin.Ieee.Rising_Edge.value:
edge = True
elif imp == thin.Ieee.Falling_Edge.value:
edge = False
else:
return (None, None)
assoc = iirs.Get_Parameter_Association_Chain(cond)
return (iirs.Get_Actual(assoc), edge)
def is_register(self, stmt):
cond = iirs.Get_Condition(stmt)
(clk, edge) = self.is_edge_condition(cond)
if clk:
return (clk, None)
else:
# TODO: asynchronous reset
return (None, None)
def in_sensitivity(self, lst, sig):
sig = thin.Iirs_Utils.Strip_Denoting_Name(sig)
for el in thinutils.list_iter(lst):
el = thin.Iirs_Utils.Strip_Denoting_Name(el)
# FIXME: handle suffix
if el == sig:
return True
k = iirs.Get_Kind(sig)
if k == iirs.Iir_Kind.Slice_Name \
or k == iirs.Iir_Kind.Indexed_Name \
or k == iirs.Iir_Kind.Selected_Element:
if self.in_sensitivity(lst, iirs.Get_Prefix(sig)):
return True
return False
def check_register(self, proc, clk, rst):
slist = iirs.Get_Sensitivity_List(proc)
if not self.in_sensitivity(slist, clk):
self.error(Location.from_node(proc),
"clock not in sensitivity list")
if thin.Lists.Get_Nbr_Elements(slist) != 1:
self.error(Location.from_node(proc),
"too many signals in sensitivity list")
def check_process(self, proc):
stmt = iirs.Get_Sequential_Statement_Chain(proc)
if nodeutils.is_one_stmt(stmt) \
and iirs.Get_Kind(stmt) == iirs.Iir_Kind.If_Statement:
(clk, rst) = self.is_register(stmt)
if clk is not None:
self.check_register(proc, clk, rst)
return
slist = iirs.Get_Sensitivity_List(proc)
clist = thin.Lists.Create_Iir_List()
thin.Canon.Extract_Sequential_Statement_Chain_Sensitivity(
iirs.Get_Sequential_Statement_Chain(proc), clist)
for el in thinutils.list_iter(clist):
if not self.in_sensitivity(slist, el):
self.error(Location.from_node(el),
"signal not in sensitivity list")
thin.Lists.Destroy_Iir_List(clist)
def check(self, input, unit):
for n in thinutils.concurrent_stmts_iter(unit):
k = iirs.Get_Kind(n)
if k == iirs.Iir_Kind.Process_Statement:
self.error(Location.from_node(n),
"non-sentized process not allowed in synth unit")
elif k == iirs.Iir_Kind.Sensitized_Process_Statement:
self.check_process(n)
else:
# Check for non-postponed ?
pass
@staticmethod
def test(runner):
rule = CheckProcesses()
TestRunOK(runner, "simple FF",
rule, ['--synth', "synthproc1.vhdl"])
TestRunFail(runner, "non-sensitized process",
rule, ['--synth', "synthproc2.vhdl"])
TestRunOK(runner, "simple combinational",
rule, ['--synth', "synthproc3.vhdl"])
TestRunFail(runner, "missing signal in sensitivity list",
rule, ['--synth', "synthproc4.vhdl"])
entity assocs1 is
end;
architecture behav of assocs1 is
component comp is
generic (g1, g2, g3 : natural);
port (p1, p2 : bit);
end component;
signal s1, s2 : bit;
begin
inst : comp
generic map (g1 => 1, g2 => 2, g3 => 3)
port map (p1 => s1, p2 => s2);
end behav;
entity assocs2 is
end;
architecture behav of assocs2 is
component comp is
generic (g1, g2, g3 : natural);
port (p1, p2 : bit);
end component;
signal s1, s2 : bit;
begin
inst : comp
generic map (g1 => 1, g3 => 2, g2 => 3)
port map (p1 => s1, p2 => s2);
end behav;
entity assocs3 is
end;
architecture behav of assocs3 is
component comp is
port (p1, p2 : bit);
end component;
signal s1, s2 : bit;
begin
inst : comp
port map (p1 => s1, p2 => s2);
end behav;
entity assocs4 is
end;
architecture behav of assocs4 is
component comp is
port (p1, p2 : bit);
end component;
signal s1, s2 : bit;
begin
inst : comp
port map (s1, p2 => s2);
end behav;
entity attrdecl1 is
end;
architecture behav of attrdecl1 is
attribute user_attr : string;
begin
end;
entity attrdecl1 is
end;
architecture behav of attrdecl1 is
attribute reserved : boolean;
begin
end;
entity attrname1 is
end;
architecture behav of attrname1 is
attribute reserved : boolean;
signal s : bit;
attribute reserved of s : signal is True;
constant c : boolean := s'reserved;
begin
end;
entity attrname2 is
end;
architecture behav of attrname2 is
constant n : string := "hello";
constant l : natural := n'left;
begin
end;
-- File with a non vhdl extension
entity beginendlayout1 is
begin
end;
entity beginendlayout2 is
begin
end;
entity beginendlayout3 is
end;
architecture behav of beginendlayout3 is
begin
end behav;
entity beginendlayout4 is
end;
architecture behav of beginendlayout4 is
begin
b : block
begin
end block b;
end behav;
entity beginendlayout5 is
end;
architecture behav of beginendlayout5 is
begin
g : for i in 1 to 2 generate
begin
end generate g;
end behav;
entity beginendlayout6 is
end;
architecture behav of beginendlayout6 is
begin
process
begin
null;
end process;
end behav;
entity beginendlayout7 is
end;
architecture behav of beginendlayout7 is
function f return natural is
begin
return 5;
end;
begin
process
begin
null;
end process;
end behav;
entity beginendlayout8 is
end;
architecture behav of beginendlayout8 is
begin
process
procedure p is
begin
null;
end p;
begin
null;
end process;
end behav;
entity beginendlayout9 is
end;
architecture behav of beginendlayout9 is
begin
process
procedure p is
constant c : natural := 5;
begin
null;
end p;
begin
null;
end process;
end behav;
--
-- There is a blank line after this line. Do not edit
-- Bad character Ã
entity charset1 is
end;
--This is an incorrect comment (missing space).
entity comment1 is
end;
-----------------------------------------------------------------------------
-- This is a correct comment.
-----------------------------------------------------------------------------
-- Also an empty comment
--
entity complexstmtlayout1 is
end;
architecture behav of complexstmtlayout1 is
begin
process
variable a : boolean;
begin
if a then
assert false;
elsif true then
null;
end if;
end process;
end behav;
entity complexstmtlayout10 is
end;
architecture behav of complexstmtlayout10 is
begin
g1: if True
generate
assert false;
end generate;
end behav;
entity complexstmtlayout11 is
end;
architecture behav of complexstmtlayout11 is
procedure proc is
begin
null;
end proc;
begin
process
variable v : natural;
begin
case v is
when 1 =>
wait for 1 ns;
when 2 =>
wait for 2 ns;
when others =>
proc;
end case;
end process;
end behav;
entity complexstmtlayout2 is
end;
architecture behav of complexstmtlayout2 is
begin
process
variable a : boolean;
begin
if a
or a then
assert false;
end if;
end process;
end behav;
entity complexstmtlayout3 is
end;
architecture behav of complexstmtlayout3 is
begin
process
variable a : boolean;
begin
if false then
null;
elsif a
or a then
assert false;
end if;
end process;
end behav;
entity complexstmtlayout4 is
end;
architecture behav of complexstmtlayout4 is
begin
process
variable a : boolean;
begin
for i in 1 to 5 loop
null;
end loop;
end process;
end behav;
entity complexstmtlayout5 is
end;
architecture behav of complexstmtlayout5 is
begin
process
variable a : boolean;
begin
for i in 1 to 5
loop
null;
end loop;
end process;
end behav;
entity complexstmtlayout6 is
end;
architecture behav of complexstmtlayout6 is
begin
process
variable a : boolean;
begin
for i in 1 to 5
loop
null;
end loop;
end process;
end behav;
entity complexstmtlayout7 is
end;
architecture behav of complexstmtlayout7 is
begin
process
variable a : boolean;
begin
while False loop
null;
end loop;
end process;
end behav;
entity complexstmtlayout8 is
end;
architecture behav of complexstmtlayout8 is
begin
process
variable a : boolean;
begin
while False
loop
null;
end loop;
end process;
end behav;
entity complexstmtlayout9 is
end;
architecture behav of complexstmtlayout9 is
begin
g1: for i in 1 to 7
generate
assert false;
end generate;
end behav;
entity configspec1 is
end;
entity configspec1_sub is
port (a : bit);
end;
architecture behav of configspec1 is
component comp
port (a : bit);
end component;
for all: comp use entity work.configspec1_sub;
signal s : bit;
begin
c : comp port map (a => s);
end;
use std.textio.all;
entity contextclauses1 is
end contextclauses1;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment