diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -41,6 +41,8 @@ collectFoldingRanges(Child, Result); } +void collectPPFoldingRanges(std::vector &Result) {} + } // namespace llvm::Expected getSemanticRanges(ParsedAST &AST, Position Pos) { diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -96,6 +96,8 @@ /// Return true if this is an annotation token representing a pragma. bool isPragmaAnnotation(TokenKind K); +PPKeywordKind getPPKeywordFromSpelling(const std::string &Name); + } // end namespace tok } // end namespace clang diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -271,54 +271,7 @@ } tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { - // We use a perfect hash function here involving the length of the keyword, - // the first and third character. For preprocessor ID's there are no - // collisions (if there were, the switch below would complain about duplicate - // case values). Note that this depends on 'if' being null terminated. - -#define HASH(LEN, FIRST, THIRD) \ - (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) -#define CASE(LEN, FIRST, THIRD, NAME) \ - case HASH(LEN, FIRST, THIRD): \ - return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME - - unsigned Len = getLength(); - if (Len < 2) return tok::pp_not_keyword; - const char *Name = getNameStart(); - switch (HASH(Len, Name[0], Name[2])) { - default: return tok::pp_not_keyword; - CASE( 2, 'i', '\0', if); - CASE( 4, 'e', 'i', elif); - CASE( 4, 'e', 's', else); - CASE( 4, 'l', 'n', line); - CASE( 4, 's', 'c', sccs); - CASE( 5, 'e', 'd', endif); - CASE( 5, 'e', 'r', error); - CASE( 5, 'i', 'e', ident); - CASE( 5, 'i', 'd', ifdef); - CASE( 5, 'u', 'd', undef); - - CASE( 6, 'a', 's', assert); - CASE( 6, 'd', 'f', define); - CASE( 6, 'i', 'n', ifndef); - CASE( 6, 'i', 'p', import); - CASE( 6, 'p', 'a', pragma); - - CASE( 7, 'd', 'f', defined); - CASE( 7, 'i', 'c', include); - CASE( 7, 'w', 'r', warning); - - CASE( 8, 'u', 'a', unassert); - CASE(12, 'i', 'c', include_next); - - CASE(14, '_', 'p', __public_macro); - - CASE(15, '_', 'p', __private_macro); - - CASE(16, '_', 'i', __include_macros); -#undef CASE -#undef HASH - } + return tok::getPPKeywordFromSpelling(getNameStart()); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Basic/TokenKinds.cpp b/clang/lib/Basic/TokenKinds.cpp --- a/clang/lib/Basic/TokenKinds.cpp +++ b/clang/lib/Basic/TokenKinds.cpp @@ -65,3 +65,56 @@ } return false; } + +tok::PPKeywordKind tok::getPPKeywordFromSpelling(const std::string &Name) { + // We use a perfect hash function here involving the length of the keyword, + // the first and third character. For preprocessor ID's there are no + // collisions (if there were, the switch below would complain about duplicate + // case values). Note that this depends on 'if' being null terminated. + unsigned Len = Name.size(); + +#define HASH(LEN, FIRST, THIRD) \ + (LEN << 5) + (((FIRST - 'a') + (THIRD - 'a')) & 31) +#define CASE(LEN, FIRST, THIRD, NAME) \ + case HASH(LEN, FIRST, THIRD): \ + return memcmp(Name.c_str(), #NAME, LEN) ? tok::pp_not_keyword \ + : tok::pp_##NAME + + if (Len < 2) + return tok::pp_not_keyword; + switch (HASH(Len, Name[0], Name[2])) { + default: + return tok::pp_not_keyword; + CASE(2, 'i', '\0', if); + CASE(4, 'e', 'i', elif); + CASE(4, 'e', 's', else); + CASE(4, 'l', 'n', line); + CASE(4, 's', 'c', sccs); + CASE(5, 'e', 'd', endif); + CASE(5, 'e', 'r', error); + CASE(5, 'i', 'e', ident); + CASE(5, 'i', 'd', ifdef); + CASE(5, 'u', 'd', undef); + + CASE(6, 'a', 's', assert); + CASE(6, 'd', 'f', define); + CASE(6, 'i', 'n', ifndef); + CASE(6, 'i', 'p', import); + CASE(6, 'p', 'a', pragma); + + CASE(7, 'd', 'f', defined); + CASE(7, 'i', 'c', include); + CASE(7, 'w', 'r', warning); + + CASE(8, 'u', 'a', unassert); + CASE(12, 'i', 'c', include_next); + + CASE(14, '_', 'p', __public_macro); + + CASE(15, '_', 'p', __private_macro); + + CASE(16, '_', 'i', __include_macros); +#undef CASE +#undef HASH + } +}