if (FileRange.isInvalid())
return None;
- return utils::lexer::getConstQualifyingToken(FileRange, *Result.Context,
- *Result.SourceManager);
+ return utils::lexer::getQualifyingToken(
+ tok::kw_const, FileRange, *Result.Context, *Result.SourceManager);
}
namespace {
return false;
}
-llvm::Optional<Token> getConstQualifyingToken(CharSourceRange Range,
- const ASTContext &Context,
- const SourceManager &SM) {
+llvm::Optional<Token> getQualifyingToken(tok::TokenKind TK,
+ CharSourceRange Range,
+ const ASTContext &Context,
+ const SourceManager &SM) {
+ assert((TK == tok::kw_const || TK == tok::kw_volatile ||
+ TK == tok::kw_restrict) &&
+ "TK is not a qualifier keyword");
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin());
StringRef File = SM.getBufferData(LocInfo.first);
Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
File.begin(), File.data() + LocInfo.second, File.end());
- llvm::Optional<Token> FirstConstTok;
- Token LastTokInRange;
+ llvm::Optional<Token> LastMatchBeforeTemplate;
+ llvm::Optional<Token> LastMatchAfterTemplate;
+ bool SawTemplate = false;
Token Tok;
while (!RawLexer.LexFromRawLexer(Tok) &&
Range.getEnd() != Tok.getLocation() &&
Tok.setIdentifierInfo(&Info);
Tok.setKind(Info.getTokenID());
}
- if (Tok.is(tok::kw_const) && !FirstConstTok)
- FirstConstTok = Tok;
- LastTokInRange = Tok;
+ if (Tok.is(tok::less))
+ SawTemplate = true;
+ else if (Tok.isOneOf(tok::greater, tok::greatergreater))
+ LastMatchAfterTemplate = None;
+ else if (Tok.is(TK)) {
+ if (SawTemplate)
+ LastMatchAfterTemplate = Tok;
+ else
+ LastMatchBeforeTemplate = Tok;
+ }
}
- // If the last token in the range is a `const`, then it const qualifies the
- // type. Otherwise, the first `const` token, if any, is the qualifier.
- return LastTokInRange.is(tok::kw_const) ? LastTokInRange : FirstConstTok;
+ return LastMatchAfterTemplate != None ? LastMatchAfterTemplate
+ : LastMatchBeforeTemplate;
}
} // namespace lexer
} // namespace utils
const SourceManager &SM,
const LangOptions &LangOpts);
-/// Assuming that ``Range`` spans a const-qualified type, returns the ``const``
-/// token in ``Range`` that is responsible for const qualification. ``Range``
-/// must be valid with respect to ``SM``. Returns ``None`` if no ``const``
+/// Assuming that ``Range`` spans a CVR-qualified type, returns the
+/// token in ``Range`` that is responsible for the qualification. ``Range``
+/// must be valid with respect to ``SM``. Returns ``None`` if no qualifying
/// tokens are found.
-llvm::Optional<Token> getConstQualifyingToken(CharSourceRange Range,
- const ASTContext &Context,
- const SourceManager &SM);
+/// \note: doesn't support member function qualifiers.
+llvm::Optional<Token> getQualifyingToken(tok::TokenKind TK,
+ CharSourceRange Range,
+ const ASTContext &Context,
+ const SourceManager &SM);
} // namespace lexer
} // namespace utils
template <typename T>
typename std::add_const<T>::type n15(T v) { return v; }
+template <bool B>
+struct MyStruct {};
+
template <typename A>
class Klazz {
public:
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int>'
// CHECK-FIXES: Klazz<const int> p12() {}
+const Klazz<const Klazz<const int>> p33() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<
+// CHECK-FIXES: Klazz<const Klazz<const int>> p33() {}
+
const Klazz<const int>* const p13() {}
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
// CHECK-FIXES: const Klazz<const int>* p13() {}
+const Klazz<const int>* const volatile p14() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const int> *
+// CHECK-FIXES: const Klazz<const int>* volatile p14() {}
+
+const MyStruct<0 < 1> p34() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const MyStruct<0 < 1>'
+// CHECK-FIXES: MyStruct<0 < 1> p34() {}
+
+MyStruct<0 < 1> const p35() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const MyStruct<0 < 1>'
+// CHECK-FIXES: MyStruct<0 < 1> p35() {}
+
+Klazz<MyStruct<0 < 1> const> const p36() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
+// CHECK-FIXES: Klazz<MyStruct<0 < 1> const> p36() {}
+
+const Klazz<MyStruct<0 < 1> const> *const p37() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
+// CHECK-FIXES: const Klazz<MyStruct<0 < 1> const> *p37() {}
+
+Klazz<const MyStruct<0 < 1>> const p38() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
+// CHECK-FIXES: Klazz<const MyStruct<0 < 1>> p38() {}
+
+const Klazz<const MyStruct<0 < 1>> p39() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<
+// CHECK-FIXES: Klazz<const MyStruct<0 < 1>> p39() {}
+
+const Klazz<const MyStruct<(0 > 1)>> p40() {}
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const Klazz<const MyStru
+// CHECK-FIXES: Klazz<const MyStruct<(0 > 1)>> p40() {}
+
// re-declaration of p15.
const int p15();
// CHECK-FIXES: int p15();