Skip to content

Commit 9d0a295

Browse files
committed
Partially fixed danmar#4288 (handle %var%|%num% patterns).
1 parent 6b8e83a commit 9d0a295

3 files changed

Lines changed: 81 additions & 64 deletions

File tree

lib/token.cpp

Lines changed: 52 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,30 @@ int Token::firstWordLen(const char *str)
530530
return len;
531531
}
532532

533+
#define multicompare(p,cond,ismulticomp) \
534+
{ \
535+
if ((p)[0] != '|') { \
536+
if (!(cond)) \
537+
return false; \
538+
ismulticomp = false; \
539+
} else { \
540+
if (cond) { \
541+
while (*(p) && *(p) != ' ') \
542+
++(p); \
543+
ismulticomp = false; \
544+
} else { \
545+
(p) += 1; \
546+
ismulticomp = (*(p) && *(p) != ' '); \
547+
continue; \
548+
} \
549+
} \
550+
}
551+
533552
bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
534553
{
535554
const char *p = pattern;
536555
bool firstpattern = true;
556+
bool ismulticomp = false;
537557
while (*p) {
538558
// Skip spaces in pattern..
539559
while (*p == ' ')
@@ -573,9 +593,8 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
573593
// work, before that change can be made.
574594
// Any symbolname..
575595
if (p[4] == '%') { // %var%
576-
if (!tok->isName())
577-
return false;
578596
p += 5;
597+
multicompare(p,tok->isName(),ismulticomp);
579598
patternUnderstood = true;
580599
} else { // %varid%
581600
if (varid == 0) {
@@ -592,115 +611,84 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
592611
case 't':
593612
// Type (%type%)
594613
{
595-
if (!tok->isName())
596-
return false;
597-
598-
if (tok->varId() != 0)
599-
return false;
600-
601-
if (tok->str() == "delete")
602-
return false;
603-
604614
p += 6;
615+
multicompare(p,tok->isName() && tok->varId() == 0 && tok->str() != "delete",ismulticomp);
605616
patternUnderstood = true;
606617
}
607618
break;
608619
case 'a':
609620
// Accept any token (%any%)
610621
{
611622
p += 5;
623+
if (p[0] == '|')
624+
while (*p && *p != ' ')
625+
++p;
626+
ismulticomp = false;
612627
patternUnderstood = true;
613628
}
614629
break;
615630
case 'n':
616631
// Number (%num%)
617632
{
618-
if (!tok->isNumber())
619-
return false;
620633
p += 5;
634+
multicompare(p,tok->isNumber(),ismulticomp);
621635
patternUnderstood = true;
622636
}
623637
break;
624638
case 'c':
625639
// Character (%char%)
626640
{
627-
if (tok->_type != eChar)
628-
return false;
629641
p += 6;
642+
multicompare(p,tok->_type == eChar,ismulticomp);
630643
patternUnderstood = true;
631644
}
632645
break;
633646
case 's':
634647
// String (%str%)
635648
{
636-
if (tok->_str[0] != '\"')
637-
return false;
638649
p += 5;
650+
multicompare(p,tok->_type == eString,ismulticomp);
639651
patternUnderstood = true;
640652
}
641653
break;
642654
case 'b':
643655
// Bool (%bool%)
644656
{
645-
if (!tok->isBoolean())
646-
return false;
647657
p += 6;
658+
multicompare(p,tok->isBoolean(),ismulticomp);
648659
patternUnderstood = true;
649660
}
650661
break;
651662
case 'o':
652-
// Or (%or%) and Op (%op%)
653663
if (p[3] == '%') {
654-
patternUnderstood = true;
655-
656-
// multicompare..
657-
if (p[4] == '|') {
658-
int result = multiCompare(p, tok->str().c_str());
659-
if (result == -1)
660-
return false; // No match
661-
662-
while (*p && *p != ' ')
663-
p++;
664+
p += 2;
665+
// Or (%or%)
666+
if (p[0] == 'r') {
667+
p += 2;
668+
multicompare(p,tok->str() == "|",ismulticomp)
669+
patternUnderstood = true;
670+
// Op (%op%)
671+
} else if (p[0] == 'p') {
672+
p += 2;
673+
multicompare(p,tok->isOp(),ismulticomp);
674+
patternUnderstood = true;
664675
}
665-
666-
// single compare..
667-
else if (p[2] == 'r') {
668-
if (tok->str() != "|")
669-
return false;
670-
p += 4;
671-
} else if (p[2] == 'p') {
672-
if (!tok->isOp())
673-
return false;
674-
p += 4;
675-
} else
676-
patternUnderstood = false;
677676
}
678677

679678
// Oror (%oror%)
680679
else if (p[5] == '%') {
681-
// multicompare..
682-
if (p[6] == '|') {
683-
int result = multiCompare(p, tok->str().c_str());
684-
if (result == -1)
685-
return false; // No match
686-
687-
while (*p && *p != ' ')
688-
p++;
689-
}
690-
691-
// single compare..
692-
else if (tok->str() != "||")
693-
return false;
694-
695-
else
696-
p += 6;
697-
680+
p += 6;
681+
multicompare(p,tok->str() == "||",ismulticomp);
698682
patternUnderstood = true;
699683
}
700684
break;
701685
default:
702686
if (firstWordEquals(p, tok->_str.c_str())) {
703687
p += tok->_str.length();
688+
if (p[0] == '|') {
689+
while (*p && *p != ' ')
690+
p++;
691+
}
704692
patternUnderstood = true;
705693
}
706694
break;
@@ -710,13 +698,15 @@ bool Token::Match(const Token *tok, const char pattern[], unsigned int varid)
710698
return false;
711699
}
712700

713-
// debugging: assert that this is not part of a multicompare pattern..
714-
assert(*p != '|');
715-
716701
tok = tok->next();
717702
continue;
718703
}
719704

705+
else if (ismulticomp) {
706+
ismulticomp = false;
707+
continue;
708+
}
709+
720710
// [.. => search for a one-character token..
721711
else if (p[0] == '[' && chrInFirstWord(p, ']')) {
722712
if (tok->_str.length() != 1)

lib/token.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,15 @@ class CPPCHECKLIB Token {
137137
* multi-compare patterns such as "int|void|char" can contain %or%, %oror% and %op%
138138
* but it is not recommended to put such an %cmd% as the first pattern.
139139
*
140+
* It's possible to use multi-compare patterns with just %cmds%, except for %varid%.
141+
* For example: "%var%|%num%| " means yes to a variable, a number or empty string.
142+
*
140143
* The patterns can be also combined to compare to multiple tokens at once
141144
* by separating tokens with a space, e.g.
142145
* ") const|void {" will return true if first token is ')' next token is either
143146
* "const" or "void" and token after that is '{'. If even one of the tokens does not
144147
* match its pattern, false is returned.
145148
*
146-
* @todo pattern "%type%|%num%" should mean either a type or a num.
147-
*
148149
* @param tok List of tokens to be compared to the pattern
149150
* @param pattern The pattern against which the tokens are compared,
150151
* e.g. "const" or ") const|volatile| {".

test/testtoken.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,32 @@ class TestToken : public TestFixture {
172172
ASSERT_EQUALS(true, Token::Match(toks4.tokens(), "%var% >>|<<|&|%or%|^|% %var% ;"));
173173
ASSERT_EQUALS(true, Token::Match(toks4.tokens(), "%var% %|>>|<<|&|%or%|^ %var% ;"));
174174
ASSERT_EQUALS(true, Token::Match(toks4.tokens(), "%var% >>|<<|&|%or%|%|^ %var% ;"));
175+
176+
//%var%|%num% support
177+
givenACodeSampleToTokenize num("100", true);
178+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%num%|%var%"));
179+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%var%|%num%"));
180+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%var%|%num%|%bool%"));
181+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%var%|%bool%|%num%"));
182+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%var%|%bool%|%str%|%num%"));
183+
ASSERT_EQUALS(false, Token::Match(num.tokens(), "%bool%|%var%"));
184+
ASSERT_EQUALS(false, Token::Match(num.tokens(), "%type%|%bool%|%char%"));
185+
ASSERT_EQUALS(true, Token::Match(num.tokens(), "%type%|%bool%|100"));
186+
187+
givenACodeSampleToTokenize numparen("( 100 )", true);
188+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| %num%|%var% )|"));
189+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| %var%|%num% )|"));
190+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| %var%|%num%|%bool% )|"));
191+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| %var%|%bool%|%num% )|"));
192+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| %var%|%bool%|%str%|%num% )|"));
193+
ASSERT_EQUALS(false, Token::Match(numparen.tokens(), "(| %bool%|%var% )|"));
194+
195+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %num%|%var%| )|"));
196+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %var%|%num%| )|"));
197+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %var%|%num%|%bool%| )|"));
198+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %var%|%bool%|%num%| )|"));
199+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %var%|%bool%|%str%|%num%| )|"));
200+
ASSERT_EQUALS(true, Token::Match(numparen.tokens(), "(| 100 %bool%|%var%| )|"));
175201
}
176202

177203
void getStrLength() {

0 commit comments

Comments
 (0)