日時: | 2014-05-24 |
---|---|
作: | 時雨堂 |
バージョン: | 1.1.10 |
url: | http://shiguredo.jp/ |
Lua ソースコード静的解析ツールは 時雨堂 が開発し販売をしています
- 2014-05-24: 製品のウェブサイトを公開しました
- 2014-05-01: 製品の販売を開始しました
1ヶ月試用可能な体験版を提供しております、ご興味ある方はご連絡下さい。
このツールに興味がある方は以下までご連絡ください。
tel: | 03-6240-1490 |
---|---|
mail: | contact at shiguredo.jp |
現在は Mac OS X 版または Linux 版を提供可能です。
- 10.8.x
- 10.9.x
- CentOS 6.5
- Ubuntu 12.04
- Ubuntu 14.04
- Windows 版の提供
- vim プラグインの提供
- emacs プラグインの提供
- 法人のみが対象
- 年間ライセンス
- アップデートなどは無料
デスクトップなど「個人」向けのライセンス
- エディタとの連携
- ローカルでのソースコード変更後の自動チェック
基本ライセンス:
1 ユーザ 12,000 円 / 年
価格表:
1 ユーザ 12,000 円 / 年 10 ユーザ 108,000 円 / 年
リポジトリサーバやビルドサーバなど「不特定多数」向けのライセンス
- ビルドサーバへの組み込み
- バージョン管理のコミットフック
1 OS に対して 1 インストール 600,000 円 / 年
価格表:
1 インストール 600,000 円 / 年
最近 Lua という言語が周りでよく使われている気がします。
周りに話を聞く感じだと、以下のようなところで使われているようです。
- Nginx + Lua
- Redis + Lua
- Wireshark + Lua
- Cocos2dx + Lua
また、World of Warcraft や ファイナルファンタジーXIV といった MMORPG にも使われています。
文法がシンプルでとても高速なことから組み込み言語としての用途が多いようです。
時雨堂では仕事で開発するときは「コードの統一感」がとても重要だと考えています。 またコードレビューをする前に、ツールで探し出せる問題点は省くべきとも考えています。
つまり、コーディング規約をチェックしたりするツール (lint とも呼ばれている) が Lua には必要ではないだろうかと考えました。
また lua を使って開発していく上に以下のような問題を抱えました。
- Lua はエラー原因がわかりにくい
- 組み込み用途では、単純な文法エラーや typo にも気づきにくい
- 存在しない変数や(テーブルの)フィールドにアクセスしても nil が返る
- 関数の引数の数がまったく検査されない
- 引数は省略可能、または定義以上に与えても何も問題ない
これらの問題を気軽にツールでチェック出来ないものだろうかと考えました。
実際いくつかツールは存在しましたが、我々の要件を完全に満たすものはありませんでした。
何はともあれサンプルを見てください。
以下のコードはソースコードチェッカー開発用に作っている lua のテストスクリプトです。
-- 80 文字以上の行
-----------------------------------------------------------------------------------
-- グローバル変数
g = "hello"
-- 80 文字以上の行
-----------------------------------------------------------------------------------
local M = {}
-- 未使用の変数
local unused
-- グローバル関数
function add(a, b)
-- 未定義の変数: "c"
return a + b + c
end
-- ローカル関数
local function DoAnything()
end
-- リテラル引数 (関数との間にスペースがない)
ipairs {}
ipairs{}
ipairs "hello"
ipairs"hello"
ipairs 'hello'
ipairs'hello'
-- 演算子前後のスペース
local a=1
a=true
a = false -- ok
a = true
a = 1+1
-- 単項演算子
a = -1
a = -(a+1)
-- 文字列
local s
s = 'alo\n123"'
s = "alo\n123\""
s = '\97lo\10\04923"'
s = "\97lo\10\04923'"
s = 'a\0o a\0o a\0o'
s = "a\0o a\0o a\0o"
s = 'aa\x61aa'
s = "aa\x61aa"
s = "\a\b\f\n\r\t\v\\\'\""
s = '\a\b\f\n\r\t\v\\\'\"'
s = "[\"key\"]\n"
s = '[\'key\']\n'
-- 数値
local num
num = 3
num = 3.0
num = 3.1416
num = 314.16e-2
num = 0.31416E1
num = 0xff
num = 0x56
-- 以降 Lua 5.2 から
-- num = 0x0.1E
-- num = 0xA23p-4
-- num = 0X1.921FB54442D18P+1
-- テーブル
local t = {}
local v
t = { }
t = { key1 = 'value1', key2 = 'value2', [1 + 1] = 2 }
t = {key1='value1',key2='value2',[1+1]=2}
t = { v = v }
t = {1}
t = {1,2,3}
t = { 1, 2, 3 }
t = { 1, 2, 3, key = 4 }
print(t[0]) -- element 0
print(t[1])
-- ライブラリのロード (-r)
require "global"
-- グローバル変数の再代入
other_gvar = 0
-- if
if false then
local v = "Hello"
print(v .. ", world!")
elseif true then
local v = "Hello"
print(v..", world!")
else
local v = "Hello"
print(v..", world!")
end
-- 数値の for
for i=1,100,2 do
local j
end
-- 汎用 for
for i,v in pairs {} do
local j
end
-- ipairs の場合は先頭の引数を unused の検査対象にしない
for i, v in ipairs {} do
end
-- 括弧で囲まれた式
(ipairs{}).key = nil
( ipairs {} ).key = nil
-- エラーを無視する
ipairs"valid" -- luli: noqa
ipairs"invalid" -- luli: noqaaaa
ipairs"-- luli: noqa" -- 文字列中の指定は無効
-- 長いコメント
--[[
コメント
]]
-- 長い文字列を含む長いコメント
--[=[
[[長い文字列]]
]=]
--[===[
[[長い文字列]]
]===]
-- 長い文字列
print [[alo
123"]]
print [[alo
123"
]]
print [[alo
123"
]]
print [==[
alo
123"]==]
print[====[
alo
123"]====]
-- cocos2d オプション
local node = CCNode:create()
node:setPosition(ccp(0, 0))
-- クロージャ
local f = function (farg1, farg2, farg3)
return farg1+farg2
end
-- インデント
if M then print("expected an indent block") end
if M then
print("unexpected indentation")
elseif M then -- unexpected indent
print("not a multiple 2 spaces")
else -- unexpected indent
print("indentation contains mixed spaces and tabs")
end
-- グローバル変数の再代入
GVAR = "world"
print(GVAR)
print(other_var)
return M
このコードに対して Lua ソースコードチェッカーを実行すると以下のようなエラーが出ます。
実行結果は開発中のものです
$ luli test.lua test.lua:4:1: W1 line too long (83 > 79 characters) test.lua:7:1: W9 global variable definition `g' test.lua:10:1: W1 line too long (83 > 79 characters) test.lua:15:7: W5 unused variable `unused' test.lua:18:10: W10 global function definition `add' test.lua:18:10: W5 unused variable `add' test.lua:20:18: W6 unassigned variable `c' (did you mean `a'?) test.lua:24:16: W11 not snake case `DoAnything' test.lua:24:16: W5 unused variable `DoAnything' test.lua:29:7: W33 missing whitespace before literal argument test.lua:31:7: W33 missing whitespace before literal argument test.lua:33:7: W33 missing whitespace before literal argument test.lua:36:8: W23 missing whitespace before `=' test.lua:37:2: W23 missing whitespace before `=' test.lua:39:5: W26 too much whitespace around `=' test.lua:40:6: W29 missing whitespace before `+' test.lua:44:8: W29 missing whitespace before `+' test.lua:47:7: W5 unused variable `s' test.lua:62:7: W5 unused variable `num' test.lua:78:5: W15 whitespace after `{' test.lua:79:5: W15 whitespace after `{' test.lua:80:10: W23 missing whitespace before `=' test.lua:80:24: W23 missing whitespace before `=' test.lua:80:36: W29 missing whitespace before `+' test.lua:80:39: W23 missing whitespace before `=' test.lua:81:5: W15 whitespace after `{' test.lua:84:5: W15 whitespace after `{' test.lua:85:5: W15 whitespace after `{' test.lua:86:9: W34 use of element 0 for array-like table access test.lua:93:1: W9 global variable definition `other_gvar' test.lua:96:4: W3 block may never be used test.lua:99:8: W4 meaningless condition (block shall be run) test.lua:101:10: W29 missing whitespace before `..' test.lua:104:10: W29 missing whitespace before `..' test.lua:108:5: W5 unused variable `i' test.lua:108:6: W23 missing whitespace before `=' test.lua:108:8: W20 too much whitespace after comma test.lua:108:12: W20 too much whitespace after comma test.lua:109:9: W5 unused variable `j' test.lua:113:6: W20 too much whitespace after comma test.lua:113:7: W5 unused variable `v' test.lua:114:9: W5 unused variable `j' test.lua:118:8: W5 unused variable `v' test.lua:122:8: W33 missing whitespace before literal argument test.lua:123:1: W13 whitespace after `(' test.lua:123:13: W14 whitespace before `)' test.lua:127:7: W33 missing whitespace before literal argument test.lua:128:7: W33 missing whitespace before literal argument test.lua:155:6: W33 missing whitespace before literal argument test.lua:160:14: W6 unassigned variable `CCNode' test.lua:161:18: W6 unassigned variable `ccp' test.lua:164:7: W5 unused variable `f' test.lua:164:35: W5 unused variable `farg3' test.lua:165:15: W29 missing whitespace before `+' test.lua:169:11: W112 expected an indented block test.lua:171:5: W113 unexpected indentation test.lua:172:3: W113 unexpected indentation test.lua:173:6: W111 indentation is not a multiple of two spaces (2 spaces) test.lua:174:3: W113 unexpected indentation test.lua:175:5: W101 indentation contains mixed spaces and tabs test.lua:179:1: W9 global variable definition `GVAR' test.lua:182:7: W6 unassigned variable `other_var' (did you mean `other_gvar'?)
$ luli -h luli: Lua static analysis tool by Shiguredo Inc. luli [FILENAME] === flags === [-L] library load path [-anon-args] do not produce `unused variable' warnings for arguments which name begins with `_' [-cocos] check for cocos2d-x [-config] config file. if this option not specified, luli tries to find a directory that has "Lulifile" [-d] debug output from parser [-first] show first occurrence of each error [-ignore] skip errors and warnings (e.g. E,W,W4) [-init] create project config file (Lulifile) into the current directory [-l] load (require) the library before the script [-license] print license information [-limit] set maximum allowed errors and warnings [-lua-version] target version of Lua [5.1, 5.2] (default: 5.1) [-max-line-length] set maximum allowed line length (default: 79) [-no-autoload] disable loading libraries specified by "require()" on top level [-no-spell-check] disable spell checking [-select] select errors and warnings (e.g. E,W,W4) [-spot] print analysis result at specified position that line and column number (e.g. 12:34) (experimental) [-v] print verbose message [-warn-error-all] make all warnings into errors [-warn-error] make warnings into errors (e.g. 4,37,123) [-build-info] print info about this build and exit [-version] print the version of this build and exit [-help] print this help text and exit (alias: -?)
-max-line-length と -ignore を指定した例
$ luli -max-line-length 120 -ignore W33,W29 test.lua test.lua:7:1: W9 global variable definition `g' test.lua:15:7: W5 unused variable `unused' test.lua:18:10: W10 global function definition `add' test.lua:18:10: W5 unused variable `add' test.lua:20:18: W6 unassigned variable `c' (did you mean `a'?) test.lua:24:16: W11 not snake case `DoAnything' test.lua:24:16: W5 unused variable `DoAnything' test.lua:36:8: W23 missing whitespace before `=' test.lua:37:2: W23 missing whitespace before `=' test.lua:39:5: W26 too much whitespace around `=' test.lua:47:7: W5 unused variable `s' test.lua:62:7: W5 unused variable `num' test.lua:78:5: W15 whitespace after `{' test.lua:79:5: W15 whitespace after `{' test.lua:80:10: W23 missing whitespace before `=' test.lua:80:24: W23 missing whitespace before `=' test.lua:80:39: W23 missing whitespace before `=' test.lua:81:5: W15 whitespace after `{' test.lua:84:5: W15 whitespace after `{' test.lua:85:5: W15 whitespace after `{' test.lua:86:9: W34 use of element 0 for array-like table access test.lua:93:1: W9 global variable definition `other_gvar' test.lua:96:4: W3 block may never be used test.lua:99:8: W4 meaningless condition (block shall be run) test.lua:108:5: W5 unused variable `i' test.lua:108:6: W23 missing whitespace before `=' test.lua:108:8: W20 too much whitespace after comma test.lua:108:12: W20 too much whitespace after comma test.lua:109:9: W5 unused variable `j' test.lua:113:6: W20 too much whitespace after comma test.lua:113:7: W5 unused variable `v' test.lua:114:9: W5 unused variable `j' test.lua:118:8: W5 unused variable `v' test.lua:123:1: W13 whitespace after `(' test.lua:123:13: W14 whitespace before `)' test.lua:160:14: W6 unassigned variable `CCNode' test.lua:161:18: W6 unassigned variable `ccp' test.lua:164:7: W5 unused variable `f' test.lua:164:35: W5 unused variable `farg3' test.lua:169:11: W112 expected an indented block test.lua:171:5: W113 unexpected indentation test.lua:172:3: W113 unexpected indentation test.lua:173:6: W111 indentation is not a multiple of two spaces (2 spaces) test.lua:174:3: W113 unexpected indentation test.lua:175:5: W101 indentation contains mixed spaces and tabs test.lua:179:1: W9 global variable definition `GVAR' test.lua:182:7: W6 unassigned variable `other_var' (did you mean `other_gvar'?)
特定の行のエラーを完全に無視する仕組み
-- エラーを無視する
ipairs"valid" -- luli: noqa
Lulifile を使う事で引数に指定する必要がなくなります
$ luli -init # creating Lulifile
$ cat Lulifile [luli] ; デバッグモード ; debug = true ; 詳細メッセージの表示 ; verbose = true ; Lua のバージョン (5.1, 5.2) ; lua-version = 5.2 ; 指定したエラーコードのみを表示する ; select = E ; 指定したエラーコードを表示しない ; ignore = E, W ; ignore = E261, E701, W302, W303 ; 一行の文字数 ; max-line-length = 79 ; cocos2d-x モード ; cocos = true ; 表示するエラーの最大数 ; limit = 30 ; 指定した警告をエラーとして扱う ; warn-error = W292, W293, W391 ; すべての警告をエラーとして扱う ; warn-error-all = true ; スペルチェックを行わない ; spell-check = false ; ライブラリのロードパス ; L = /usr/lib/lua, /usr/local/lib/lua ; require で指定されているライブラリをロードする ; autoload = false ; 指定したライブラリを解析前にロードする ; l = mylib ; 検出されたそれぞれのエラーコードのうち、最初に現れた結果のみを表示する ; first = true ; 名前が '_' で始まる引数に対して未使用の警告を行わない ; anon-args = true
vim プラグインを提供する予定です。
ソースコードは公開予定です。
画像は開発中のものです
emacs のプラグインを提供する予定です。
ソースコードは公開予定です。
画像は開発中のものです
Xcode 用のプラグインを提供する予定です。
例は VIM プラグインを使って実装しました。
ビルトイン関数定義をリアルタイムに確認出来ます
string.format の型
ipairs の型
定数の中身をリアルタイムに確認出来ます
ユーザ定義関数をリアルタイムに確認出来ます
以下のリストは今後の実装内容を保証するものではありません
- インデントのサイズ、タブまたはスペース
- インデントの揃え
- ブロックのインデント検出 (new)
- タブとスペースが混在しているか
- 変数名、関数名、メソッド名のフォーマット: snake, camel, または正規表現
- 一行の文字数
- 関数の行数
- 識別子の長さ
- 代入記号前後のスペース
- 関数呼び出しのカッコの前後のスペース
- 単一のリテラルを引数に取る関数呼び出しのスペース
- 関数呼び出しの引数の前後のスペース、またはカンマの次のスペース
- テーブル生成のキーのスペース
- テーブル要素のアクセスの前後のスペース
- 演算子前後のスペース
- 未定義の変数を参照している (標準ライブラリかチェック)
- グローバル変数を定義している
- 未使用のローカル変数がある
- 未使用の関数がある
- 標準ライブラリにない変数を参照している (string.xxx など)
- 定義するローカル変数名が組み込みの変数名と重複している
- 組み込み変数、関数に代入している
- 実行されないブロック: if, while
- 意味のない文: リテラルのみなど
- 関数に与える引数が多い (確実にわかる場合のみ)
- require の戻り値があるかどうか
- テーブルのインデックスに 0 を指定すると警告 (new)
- スペルミスの候補 (new)
- グローバル変数が定義されている
- グローバル関数が定義されている
- ファイル末尾でモジュールオブジェクトが返されていない
- モジュール関数が一つも定義されていない
このツールは OCaml で開発しています。
- TAMURA YUKI
- このツールを作るきっかけを頂きました。
- アルファ版のテストに協力頂いています。
- FURUSE JUN
- OCaml に関するアドバイスを頂いています