IsClassOrFunction: Handle signedness modifiers

When using these modifiers, a type can consist of multiple tokens
as for example "unsigned int". However the keyword "int" can also
be omitted, making "unsigned" itself also a valid type.

Note that this only handles the most basic case for the modifiers.
The size modifiers "short", "long", and "long long" would need
similar treatment. Moreover the standard permits any order for the
type specifiers, ie "unsigned long long int" and "long int unsigned
long" are both valid (and actually the same type).
This commit is contained in:
Jonas Hahnfeld 2020-04-29 10:00:41 +02:00 committed by jenkins
parent 8b34a4ce85
commit f2b3a8408e
2 changed files with 76 additions and 16 deletions

View File

@ -60,6 +60,31 @@ class MinimalPPLexer: public Lexer {
return llvm::StringRef();
}
///\brief Skip an identifier of a function.
bool SkipIdentifier(Token& Tok) {
if (Tok.isNot(tok::raw_identifier)) {
// If we're not at an identifier, we might be still be in return value:
// A::B::C funcname() or int * funcname()
if (!SkipScopes(Tok))
return false;
if (!SkipPointerRefs(Tok))
return false;
}
// Function or class name should be in Tok now
if (Identifier(Tok).empty())
return false;
// Advance to argument list or method name
if (!LexClean(Tok))
return false;
if (!SkipScopes(Tok))
return false;
return true;
}
public:
///\brief Construct a Lexer from LangOpts and source.
MinimalPPLexer(const LangOptions &LangOpts, llvm::StringRef source):
@ -204,6 +229,7 @@ public:
Ctor = false;
}
} else {
bool SeenSignedness = false;
if (First.equals("struct") || First.equals("class")) {
do {
// Identifier(Tok).empty() is redundant 1st time, but simplifies code
@ -220,29 +246,24 @@ public:
} else if (First.equals("static") || First.equals("constexpr") ||
First.equals("inline") || First.equals("const")) {
// First check if the current keyword is "unsigned".
llvm::StringRef Modifier = Identifier(Tok);
if (Modifier.equals("signed") || Modifier.equals("unsigned"))
SeenSignedness = true;
// Advance past keyword for below
if (!LexClean(Tok))
return kNONE;
} else if (First.equals("signed") || First.equals("unsigned")) {
SeenSignedness = true;
}
if (Tok.isNot(tok::raw_identifier)) {
// If we're not at an identifier, we might be still be in return value:
// A::B::C funcname() or int * funcname()
if (!SkipScopes(Tok))
return kNONE;
if (!SkipPointerRefs(Tok))
return kNONE;
}
// Function or class name should be in Tok now
if (Identifier(Tok).empty())
if (!SkipIdentifier(Tok))
return kNONE;
// Advance to argument list or method name
if (!LexClean(Tok))
return kNONE;
if (!SkipScopes(Tok))
// If we have not yet reached the argument list and seen a signedness
// modifier keyword, try to skip this once.
if (SeenSignedness && Tok.isNot(tok::l_paren) && !SkipIdentifier(Tok))
return kNONE;
}

View File

@ -59,6 +59,45 @@ localFun(0)
localFun(5, 6, 7)
// CHECK: localFun(5, 6, 7)
// CHECK: (int) 3
unsigned uFun(int a) {
printf("uFun(%d)\n", a);
return 7;
}
unsigned int uiFun(int a, int b) {
printf("uiFun(%d, %d)\n", a, b);
return 9;
}
uFun(6)
// CHECK: uFun(6)
// CHECK: (unsigned int) 7
uiFun(7, 8)
// CHECK: uiFun(7, 8)
// CHECK: (unsigned int) 9
static unsigned suFun(int a) {
printf("suFun(%d)\n", a);
return 11;
}
static unsigned int suiFun(int a, int b) {
printf("suiFun(%d, %d)\n", a, b);
return 13;
}
suFun(10)
// CHECK: suFun(10)
// CHECK: (unsigned int) 11
suiFun(11, 12)
// CHECK: suiFun(11, 12)
// CHECK: (unsigned int) 13
class Test {
public: