加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
checkFile.awk 27.03 KB
一键复制 编辑 原始数据 按行查看 历史
Julian Hyde 提交于 2012-11-29 11:49 . Improve javadoc for XMLA constants.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
#!/bin/gawk
#
# Licensed to Julian Hyde under one or more contributor license
# agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership.
#
# Julian Hyde licenses this file to you under the Apache License,
# Version 2.0 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# Checks that a file is valid.
# See checkFile.sh.
function error(fname, linum, msg) {
printf "%s:%d: %s\n", fname, linum, msg;
if (0) print; # for debug
}
function _matchFile(fname) {
return fname ~ "/mondrian/" \
|| fname ~ "/org/olap4j/" \
|| fname ~ "/aspen/" \
|| fname ~ "/farrago/" \
|| fname ~ "/fennel/" \
|| fname ~ "/extensions/" \
|| fname ~ "/com/sqlstream/" \
|| fname ~ "/linq4j/" \
|| fname ~ "/optiq/" \
|| strict > 0;
}
function _isCpp(fname) {
return fname ~ /\.(cpp|h)$/;
}
function _isJava(fname) {
return fname ~ /\.(java|jj)$/;
}
function _isMondrian(fname) {
return fname ~ /mondrian/;
}
function _isOlap4j(fname) {
return fname ~ "/org/olap4j/";
}
function push(val) {
switchStack[switchStackLen++] = val;
}
function pop() {
--switchStackLen
val = switchStack[switchStackLen];
delete switchStack[switchStackLen];
return val;
}
function afterFile() {
# Compute basename. If fname="/foo/bar/baz.txt" then basename="baz.txt".
basename = fname;
gsub(".*/", "", basename);
gsub(lf, "", lastNonEmptyLine);
terminator = "// End " basename;
if (matchFile && (lastNonEmptyLine != terminator)) {
error(fname, FNR, sprintf("Last line should be %c%s%c", 39, terminator, 39));
}
}
# Returns whether there are unmatched open parentheses.
# unmatchedOpenParens("if ()") returns false.
# unmatchedOpenParens("if (") returns true.
# unmatchedOpenParens("if (foo) bar(") returns false
function unmatchedOpenParens(s) {
i = index(s, "(");
if (i == 0) {
return 0;
}
openCount = 1;
while (++i <= length(s)) {
c = substr(s, i, 1);
if (c == "(") {
++openCount;
}
if (c == ")") {
if (--openCount == 0) {
return 0;
}
}
}
return 1;
}
function countLeadingSpaces(str) {
i = 0;
while (i < length(str) && substr(str, i + 1, 1) == " ") {
++i;
}
return i;
}
function startsWith(s, p) {
return length(s) > length(p) \
&& substr(s, 1, length(p)) == p;
}
BEGIN {
# pre-compute regexp for quotes, linefeed
apos = sprintf("%c", 39);
quot = sprintf("%c", 34);
lf = sprintf("%c", 13);
pattern = apos "(\\" apos "|[^" apos "])" apos;
if (0) printf "maxLineLength=%s strict=%s\n", maxLineLength, strict;
}
FNR == 1 {
if (fname) {
afterFile();
}
fname = FILENAME;
matchFile = _matchFile(fname);
isCpp = _isCpp(fname);
isJava = _isJava(fname);
mondrian = _isMondrian(fname);
prevImport = "";
prevImportGroup = "";
delete headers;
headerCount = 0;
if ($0 ~ /Generated By:JavaCC/ \
|| $0 ~ /This class is generated/) {
# generated; skip whole file
nextfile
} else if (fname ~ /XmlaOlap4jDriverVersion.java/ \
|| fname ~ /package-info.java/) {
# generated; does not contain standard header
} else if (1) {
headers[headerCount++] = "/\\*$";
headers[headerCount++] = "// Licensed to Julian Hyde under one or more contributor license$";
headers[headerCount++] = "// agreements. See the NOTICE file distributed with this work for$";
headers[headerCount++] = "// additional information regarding copyright ownership.$";
headers[headerCount++] = "//$";
headers[headerCount++] = "// Julian Hyde licenses this file to you under the Apache License,$";
headers[headerCount++] = "// Version 2.0 \\(the \"License\"\\); you may not use this file except in$";
headers[headerCount++] = "// compliance with the License. You may obtain a copy of the License at:$";
headers[headerCount++] = "//$";
headers[headerCount++] = "// http://www.apache.org/licenses/LICENSE-2.0$";
headers[headerCount++] = "//$";
headers[headerCount++] = "// Unless required by applicable law or agreed to in writing, software$";
headers[headerCount++] = "// distributed under the License is distributed on an \"AS IS\" BASIS,$";
headers[headerCount++] = "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.$";
headers[headerCount++] = "// See the License for the specific language governing permissions and$";
headers[headerCount++] = "// limitations under the License.$";
headers[headerCount++] = "*/$";
}
}
FNR < headerCount {
if ($0 !~ headers[FNR - 1]) {
error(fname, FNR, "Does not match expected header line: " headers[FNR - 1] "\n");
headerCount = 0; # prevent further errors from this file
}
}
{
if (previousLineEndedInCloseBrace > 0) {
--previousLineEndedInCloseBrace;
}
if (previousLineEndedInOpenBrace > 0) {
--previousLineEndedInOpenBrace;
}
if (previousLineWasEmpty > 0) {
--previousLineWasEmpty;
}
s = $0;
# remove DOS linefeeds
gsub(lf, "", s);
# replace strings
gsub(/"(\\"|[^"\\]|\\[^"])*"/, "string", s);
# replace single-quoted strings
gsub(pattern, "string", s);
# replace {: and :} in .cup files
if (fname ~ /\.cup$/) {
gsub(/{:/, "{", s);
gsub(/:}/, "}", s);
gsub(/:/, " : ", s);
}
if (inComment && $0 ~ /\*\//) {
# end of multiline comment "*/"
inComment = 0;
gsub(/^.*\*\//, "/* comment */", s);
} else if (inComment) {
s = "/* comment */";
} else if ($0 ~ /\/\*/ && $0 !~ /\/\*.*\*\//) {
# beginning of multiline comment "/*"
inComment = 1;
gsub(/\/\*.*$/, "/* comment */", s);
if (strict > 0 && FNR > 1 && $0 !~ /\/\*\*/ && $0 !~ /^\/\*/) {
error(fname, FNR, "Multi-line c-style comment not allowed");
}
} else {
# mask out /* */ comments
gsub(/\/\*.*\*\//, "/* comment */", s);
}
if (mondrian && s ~ /\/\/\$NON-NLS/) {
error(fname, FNR, "NON-NLS not allowed");
}
# mask out // comments
gsub(/\/\/.*$/, "// comment", s);
# line starts with string or plus?
if (s ~ /^ *string/ \
&& s !~ /)/)
{
stringCol = index(s, "string");
} else if (s ~ /^ *[+] string/) {
if (stringCol != 0 && index(s, "+") != stringCol) {
error(fname, FNR, "String '+' must be aligned with string on line above");
}
} else if (s ~ /comment/) {
# in comment; string target carries forward
} else {
stringCol = 0;
}
# Is the line indented as expected?
if (nextIndent > 0) {
indent = countLeadingSpaces(s);
if (indent != nextIndent) {
error(fname, FNR, "Incorrect indent for first line of arg list");
}
}
nextIndent = -1;
}
/ $/ {
error(fname, FNR, "Line ends in space");
}
/[\t]/ {
if (matchFile) {
error(fname, FNR, "Tab character");
}
}
/[\r]/ {
if (matchFile) {
error(fname, FNR, "Carriage return character (file is in DOS format?)");
}
}
/./ {
lastNonEmptyLine = $0;
}
{
# Rules beyond this point only apply to Java and C++.
if (!isCpp && !isJava) {
next;
}
}
/^package / {
thisPackage = $2;
}
/^package / && previousLineWasEmpty {
error(fname, FNR, "'package' declaration must not occur after empty line");
}
/^import / {
if (previousLineWasEmpty) {
prevImport = "";
} else {
if (!prevImport) {
error(fname, FNR, "Expected blank line before first import");
}
}
thisImport = $2;
gsub(/;/, "", thisImport);
gsub(/\*/, "", thisImport);
if (thisPackage ~ /^mondrian.*/ && thisImport ~ /^mondrian.*/ \
|| thisPackage ~ /^net.hydromatic.*/ && thisImport ~ /^net.hydromatic.*/ \
|| thisPackage ~ /^org.olap4j.*/ && thisImport ~ /^org.olap4j.*/)
{
importGroup = "a";
} else if (thisImport ~ /^static/) {
importGroup = "z";
} else if (thisImport ~ /^java.*/) {
if (thisPackage ~ /^org.eigenbase.*/) {
importGroup = "aa";
} else {
importGroup = "y";
}
} else if (thisImport ~ /^junit.*/) {
importGroup = "b";
} else if (thisImport ~ /^mondrian.*/) {
importGroup = "bb";
} else if (thisImport ~ /^org.olap4j.xmla.server.*/) {
importGroup = "bc";
} else if (thisImport ~ /^openjava.*/) {
importGroup = "cc";
} else if (thisImport ~ /^org.apache.*/) {
importGroup = "c";
} else if (thisImport ~ /^org.codehaus.*/) {
importGroup = "ccc";
} else if (thisImport ~ /^org.eigenbase.*/) {
importGroup = "d";
} else if (thisImport ~ /^org.olap4j.*/) {
importGroup = "e";
} else {
importGroup = "f";
}
if (importGroup != prevImportGroup \
&& prevImportGroup)
{
if (!previousLineWasEmpty) {
error(fname, FNR, "Expected blank line between import groups");
} else if (prevImportGroup > importGroup) {
error(fname, FNR, "Import group out of sequence (should precede " prevImportGroup ")");
}
} else if (prevImport \
&& prevImport > thisImport \
&& !startsWith(prevImport, thisImport) \
&& !startsWith(thisImport, prevImport))
{
error(fname, FNR, "Import out of sorted order");
}
prevImport = thisImport;
prevImportGroup = importGroup;
}
/^\/\/ Copyright .* Julian/ && strict > 1 {
# We assume that '--strict' is only invoked on files currently being
# edited. Therefore we would expect the copyright to be current.
if ($0 !~ /-2012/) {
error(fname, FNR, "copyright is not current");
}
}
/(static|public|private|protected|final|abstract)/ && !/import/ && strict > 1 {
# Order of qualifiers: "public/private/protected static final abstract class ..."
s2 = s;
gsub(/\(.*$/, "", s2);
if (s2 ~ /abstract .*final /) {
error(fname, FNR, "'final' must come before 'abstract'");
}
if (s2 ~ /final .*static /) {
error(fname, FNR, "'static' must come before 'final'");
}
if (s2 ~ /abstract .*static /) {
error(fname, FNR, "'static' must come before 'abstract'");
}
if (s2 ~ /static .*(public|protected|private) /) {
error(fname, FNR, "'public/private/protected' must come before 'static'");
}
if (s2 ~ /final .*(public|protected|private) /) {
error(fname, FNR, "'public/private/protected' must come before 'final'");
}
if (s2 ~ /abstract .*(public|protected|private) /) {
error(fname, FNR, "'public/private/protected' must come before 'abstract'");
}
}
/^$/ {
if (matchFile && previousLineEndedInOpenBrace) {
error(fname, FNR, "Empty line following open brace");
}
}
/^ +}( catch| finally| while|[;,)])/ ||
/^ +}$/ {
if (matchFile && previousLineWasEmpty) {
error(fname, FNR - 1, "Empty line before close brace");
}
}
s ~ /\<if\>.*;$/ {
if (!matchFile) {}
else {
error(fname, FNR, "if followed by statement on same line");
}
}
s ~ /\<(if) *\(/ {
if (!matchFile) {
} else if (s !~ /\<(if) /) {
error(fname, FNR, "if must be followed by space");
} else if (s ~ / else if /) {
} else if (s ~ /^#if /) {
} else if (s !~ /^( )*(if)/) {
error(fname, FNR, "if must be correctly indented");
}
}
s ~ /\<(while) *\(/ {
if (!matchFile) {
} else if (s !~ /\<(while) /) {
error(fname, FNR, "while must be followed by space");
} else if (s ~ /} while /) {
} else if (s !~ /^( )+(while)/) {
error(fname, FNR, "while must be correctly indented");
}
}
s ~ /\<(for|switch|synchronized|} catch) *\(/ {
if (!matchFile) {}
else if (s !~ /^( )*(for|switch|synchronized|} catch)/) {
error(fname, FNR, "for/switch/synchronized/catch must be correctly indented");
} else if (s !~ /\<(for|switch|synchronized|} catch) /) {
error(fname, FNR, "for/switch/synchronized/catch must be followed by space");
}
}
s ~ /\<(if|while|for|switch|catch)\>/ {
# Check single-line if statements, such as
# if (condition) return;
# We recognize such statements because there are equal numbers of open and
# close parentheses.
opens = s;
gsub(/[^(]/, "", opens);
closes = s;
gsub(/[^)]/, "", closes);
if (!matchFile) {
} else if (s ~ /{( *\/\/ comment)?$/) {
# lines which end with { and optional comment are ok
} else if (s ~ /{.*\\$/ && isCpp) {
# lines which end with backslash are ok in c++ macros
} else if (s ~ /} while/) {
# lines like "} while (foo);" are ok
} else if (s ~ /^#/) {
# lines like "#if 0" are ok
} else if (s ~ /if \(true|false\)/) {
# allow "if (true)" and "if (false)" because they are
# used for commenting
} else if (!unmatchedOpenParens(s) \
&& length($0) != 79 \
&& length($0) != 80)
{
error(fname, FNR, "single-line if/while/for/switch/catch must end in {");
}
}
s ~ /[[:alnum:]]\(/ &&
s !~ /\<(if|while|for|switch|assert)\>/ {
ss = s;
while (match(ss, /[[:alnum:]]\(/)) {
ss = substr(ss, RSTART + RLENGTH - 1);
parens = ss;
gsub(/[^()]/, "", parens);
while (substr(parens, 1, 2) == "()") {
parens = substr(parens, 3);
}
opens = parens;
gsub(/[^(]/, "", opens);
closes = parens;
gsub(/[^)]/, "", closes);
if (length(opens) > length(closes)) {
if (ss ~ /,$/) {
bras = ss;
gsub(/[^<]/, "", bras);
kets = ss;
gsub(/->/, "", kets);
gsub(/[^>]/, "", kets);
if (length(bras) > length(kets)) {
# Ignore case like 'for (Map.Entry<Foo,{nl} Bar> entry : ...'
} else if (s ~ / for /) {
# Ignore case like 'for (int i = 1,{nl} j = 2; i < j; ...'
} else {
error( \
fname, FNR, \
"multi-line parameter list should start with newline");
break;
}
} else if (s ~ /[;(]( *\\)?$/) {
# If open paren is at end of line (with optional backslash
# for macros), we're fine.
} else if (s ~ /@.*\({/) {
# Ignore Java annotations.
} else {
error( \
fname, FNR, \
"Open parenthesis should be at end of line (function call spans several lines)");
break;
}
}
ss = substr(ss, 2); # remove initial "("
}
}
s ~ /\<switch\>/ {
push(switchCol);
switchCol = index($0, "switch");
}
s ~ /{/ {
braceCol = index($0, "{");
if (braceCol == switchCol) {
push(switchCol);
}
}
s ~ /}/ {
braceCol = index($0, "}");
if (braceCol == switchCol) {
switchCol = pop();
}
}
s ~ /\<(case|default)\>/ {
caseDefaultCol = match($0, /case|default/);
if (!matchFile) {}
else if (caseDefaultCol != switchCol) {
error(fname, FNR, "case/default must be aligned with switch");
}
}
s ~ /\<assert\>/ {
if (!matchFile) {}
else if (isCpp) {} # rule only applies to java
else if (s !~ /^( )+(assert)/) {
error(fname, FNR, "assert must be correctly indented");
} else if (s !~ /\<assert /) {
error(fname, FNR, "assert must be followed by space");
}
}
s ~ /\<return\>/ {
if (!matchFile) {}
else if (isCpp && s ~ /^#/) {
# ignore macros
} else if (s !~ /^( )+(return)/) {
error(fname, FNR, "return must be correctly indented");
} else if (s !~ /\<return[ ;]/ && s !~ /\<return$/) {
error(fname, FNR, "return must be followed by space or ;");
}
}
s ~ /\<throw\>/ {
if (!matchFile) {}
else if (isCpp) {
# cannot yet handle C++ cases like 'void foo() throw(int)'
} else if (s !~ /^( )+(throw)/) {
error(fname, FNR, "throw must be correctly indented");
} else if (s !~ /\<throw / && s !~ /\<throw$/) {
error(fname, FNR, "throw must be followed by space");
}
}
s ~ /\<else\>/ {
if (!matchFile) {}
else if (isCpp && s ~ /^# *else$/) {} # ignore "#else"
else if (s !~ /^( )+} else (if |{$|{ *\/\/|{ *\/\*)/) {
error(fname, FNR, "else must be preceded by } and followed by { or if and correctly indented");
}
}
s ~ /\<do\>/ {
if (!matchFile) {}
else if (s !~ /^( )*do {/) {
error(fname, FNR, "do must be followed by space {, and correctly indented");
}
}
s ~ /\<try\>/ {
if (!matchFile) {}
else if (s !~ /^( )+try {/) {
error(fname, FNR, "try must be followed by space {, and correctly indented");
}
}
s ~ /\<catch\>/ {
if (!matchFile) {}
else if (s !~ /^( )+} catch /) {
error(fname, FNR, "catch must be preceded by }, followed by space, and correctly indented");
}
}
s ~ /\<finally\>/ {
if (!matchFile) {}
else if (s !~ /^( )+} finally {/) {
error(fname, FNR, "finally must be preceded by }, followed by space {, and correctly indented");
}
}
s ~ /\($/ {
nextIndent = countLeadingSpaces(s) + 4;
if (s ~ / (if|while) .*\(.*\(/) {
nextIndent += 4;
}
}
match(s, /([]A-Za-z0-9()])(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:) *[A-Za-z0-9(]/, a) {
# < and > are not handled here - they have special treatment below
if (!matchFile) {}
# else if (s ~ /<.*>/) {} # ignore templates
else if (a[2] == "-" && s ~ /\(-/) {} # ignore case "foo(-1)"
else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
else if (isCpp && s ~ /[^ ][*&]/) {} # ignore e.g. "Foo* p;" in c++ - debatable
else if (isCpp && s ~ /\<operator.*\(/) {} # ignore e.g. "operator++()" in c++
else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
else {
error(fname, FNR, "operator '" a[2] "' must be preceded by space");
}
}
match(s, /([]A-Za-z0-9() ] *)(+|-|\*|\^|\/|%|=|==|+=|-=|\*=|\/=|>=|<=|!=|&|&&|\||\|\||^|\?|:|,)[A-Za-z0-9(]/, a) {
if (!matchFile) {}
# else if (s ~ /<.*>/) {} # ignore templates
else if (a[2] == "-" && s ~ /(\(|return |case |= )-/) {} # ignore prefix -
else if (a[2] == ":" && s ~ /(case.*|default):$/) {} # ignore e.g. "case 5:"
else if (s ~ /, *-/) {} # ignore case "foo(x, -1)"
else if (s ~ /-[^ ]/ && s ~ /[^A-Za-z0-9] -/) {} # ignore case "x + -1" but not "x -1" or "3 -1"
else if (a[2] == "-" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e-5
else if (a[2] == "+" && s ~ /[eE][+-][0-9]/) {} # ignore e.g. 1e+5
else if (a[2] == "*" && isCpp && s ~ /\*[^ ]/) {} # ignore e.g. "Foo *p;" in c++
else if (a[2] == "&" && isCpp && s ~ /&[^ ]/) {} # ignore case "foo(&x)" in c++
else if (isCpp && s ~ /\<operator[^ ]+\(/) {} # ignore e.g. "operator++()" in c++
else if (isCpp && a[2] == "/" && s ~ /#include/) {} # ignore e.g. "#include <x/y.hpp>" in c++
else if (strict < 2 && fname ~ /(fennel)/ && a[1] = ",") {} # not enabled yet
else {
error(fname, FNR, "operator '" a[2] "' must be followed by space");
}
}
match(s, /( )(,)/, a) {
# (, < and > are not handled here - they have special treatment below
if (!matchFile) {}
else {
error(fname, FNR, "operator '" a[2] "' must not be preceded by space");
}
}
match(s, / (+|-|\*|\/|==|>=|<=|!=|<<|<<<|>>|&|&&|\|\||\?|:)$/, a) || \
match(s, /(\.|->)$/, a) {
if (strict < 2 && fname ~ /(aspen)/ && a[1] != ":") {} # not enabled yet
else if (strict < 2 && fname ~ /(fennel|farrago|aspen)/ && a[1] = "+") {} # not enabled yet
else if (a[1] == ":" && s ~ /(case.*|default):$/) {
# ignore e.g. "case 5:"
} else if ((a[1] == "*" || a[1] == "&") && isCpp && s ~ /^[[:alnum:]:_ ]* [*&]$/) {
# ignore e.g. "const int *\nClass::Subclass2::method(int x)"
} else {
error(fname, FNR, "operator '" a[1] "' must not be at end of line");
}
}
match(s, /^ *(=) /, a) {
error(fname, FNR, "operator '" a[1] "' must not be at start of line");
}
match(s, /([[:alnum:]~]+)( )([(])/, a) {
# (, < and > are not handled here - they have special treatment below
if (!matchFile) {}
else if (isJava && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|synchronized|assert)\>/) {}
else if (isCpp && a[1] ~ /\<(if|while|for|catch|switch|case|return|throw|operator|void|PBuffer)\>/) {}
else if (isCpp && s ~ /^#define /) {}
else {
error(fname, FNR, "there must be no space before '" a[3] "' in fun call or fun decl");
}
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*</ {
# E.g. "p<" but not "Map<"
if (!matchFile) {}
else if (isCpp) {} # in C++ 'xyz<5>' could be a template
else {
error(fname, FNR, "operator '<' must be preceded by space");
}
}
s ~ /\<[[:digit:][:lower:]][[:alnum:]_]*>/ {
# E.g. "g>" but not "String>" as in "List<String>"
if (!matchFile) {}
else if (isCpp) {} # in C++ 'xyz<int>' could be a template
else {
error(fname, FNR, "operator '>' must be preceded by space");
}
}
match(s, /<([[:digit:][:lower:]][[:alnum:].]*)\>/, a) {
if (!matchFile) {}
else if (isCpp) {
# in C++, template and include generate too many false positives
} else if (isJava && a[1] ~ /(int|char|long|boolean|byte|double|float)/) {
# Allow e.g. 'List<int[]>'
} else if (isJava && a[1] ~ /^[[:lower:]]+\./) {
# Allow e.g. 'List<java.lang.String>'
} else {
error(fname, FNR, "operator '<' must be followed by space");
}
}
match(s, /^(.*[^-])>([[:digit:][:lower:]][[:alnum:]]*)\>/, a) {
if (!matchFile) {}
else if (isJava && a[1] ~ /.*\.<.*/) {
# Ignore 'Collections.<Type>member'
} else {
error(fname, FNR, "operator '>' must be followed by space");
}
}
s ~ /[[(] / {
if (!matchFile) {}
else if (s ~ /[[(] +\\$/) {} # ignore '#define foo( \'
else {
error(fname, FNR, "( or [ must not be followed by space");
}
}
s ~ / [])]/ {
if (!matchFile) {}
else if (s ~ /^ *\)/ && previousLineEndedInCloseBrace) {} # ignore "bar(new Foo() { } );"
else {
error(fname, FNR, ") or ] must not be followed by space");
}
}
s ~ /}/ {
if (!matchFile) {}
else if (s !~ /}( |;|,|$|\))/) {
error(fname, FNR, "} must be followed by space");
} else if (s !~ /( )*}/) {
error(fname, FNR, "} must be at start of line and correctly indented");
}
}
s ~ /{/ {
if (!matchFile) {}
else if (s ~ /(\]\)?|=) *{/) {} # ignore e.g. "(int[]) {1, 2}" or "int[] x = {1, 2}"
else if (s ~ /\({/) {} # ignore e.g. @SuppressWarnings({"unchecked"})
else if (s ~ /{ *(\/\/|\/\*)/) {} # ignore e.g. "do { // a comment"
else if (s ~ / \{\}$/) {} # ignore e.g. "Constructor() {}"
else if (s ~ / },$/) {} # ignore e.g. "{ yada },"
else if (s ~ / };$/) {} # ignore e.g. "{ yada };"
else if (s ~ / \{\};$/) {} # ignore e.g. "template <> class Foo<int> {};"
else if (s ~ / },? *\/\/.*$/) {} # ignore e.g. "{ yada }, // comment"
else if (s ~ /\\$/) {} # ignore multiline macros
else if (s ~ /{}/) { # e.g. "Constructor(){}"
error(fname, FNR, "{} must be preceded by space and at end of line");
} else if (isCpp && s ~ /{ *\\$/) {
# ignore - "{" can be followed by "\" in c macro
} else if (s !~ /{$/) {
error(fname, FNR, "{ must be at end of line");
} else if (s !~ /(^| ){/) {
error(fname, FNR, "{ must be preceded by space or at start of line");
} else {
opens = s;
gsub(/[^(]/, "", opens);
closes = s;
gsub(/[^)]/, "", closes);
if (0 && strict < 2 && fname ~ /aspen/) {} # not enabled
else if (length(closes) > length(opens)) {
error(fname, FNR, "Open brace should be on new line (function call/decl spans several lines)");
}
}
}
s ~ /(^| )(class|interface|enum) / ||
s ~ /(^| )namespace / && isCpp {
if (isCpp && s ~ /;$/) {} # ignore type declaration
else {
classDeclStartLine = FNR;
t = s;
gsub(/.*(class|interface|enum|namespace) /, "", t);
gsub(/ .*$/, "", t);
if (s ~ /template/) {
# ignore case "template <class INSTCLASS> static void foo()"
classDeclStartLine = 0;
} else if (t ~ /[[:upper:]][[:upper:]][[:upper:]][[:upper:]]/ \
&& t !~ /LRU/ \
&& t !~ /WAL/ \
&& t !~ /classUUID/ \
&& t !~ /classSQLException/ \
&& t !~ /BBRC/ \
&& t !~ /_/ \
&& t !~ /EncodedSqlInterval/)
{
error(fname, FNR, "Class name " t " has consecutive uppercase letters");
}
}
}
s ~ / throws\>/ {
if (s ~ /\(/) {
funDeclStartLine = FNR;
} else {
funDeclStartLine = FNR - 1;
}
}
length($0) > maxLineLength \
&& $0 !~ /@(throws|see|link)/ \
&& $0 !~ /\$Id: / \
&& $0 !~ /^import / \
&& $0 !~ /http:/ \
&& $0 !~ /https:/ \
&& $0 !~ /\/\/ Expect "/ \
&& s !~ /^ *(\+ |<< |: |\?)?string\)?[;,]?$/ {
error( \
fname, \
FNR, \
"Line length (" length($0) ") exceeds " maxLineLength " chars");
}
/}$/ {
previousLineEndedInCloseBrace = 2;
}
/;$/ {
funDeclStartLine = 0;
}
/{$/ {
# Ignore open brace if it is part of class or interface declaration.
if (classDeclStartLine) {
if (classDeclStartLine < FNR \
&& $0 !~ /^ *{$/)
{
error(fname, FNR, "Open brace should be on new line (class decl spans several lines)");
}
classDeclStartLine = 0;
} else {
previousLineEndedInOpenBrace = 2;
}
if (funDeclStartLine) {
if (funDeclStartLine < FNR \
&& $0 !~ /^ *{$/)
{
if (strict < 2 && fname ~ /aspen/) {} # not enabled
else error(fname, FNR, "Open brace should be on new line (function decl spans several lines)");
}
funDeclStartLine = 0;
}
}
/^$/ {
previousLineWasEmpty = 2;
}
{
next;
}
END {
afterFile();
}
# End checkFile.awk
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化