xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Lex/TokenConcatenation.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- TokenConcatenation.cpp - Token Concatenation Avoidance -----------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the TokenConcatenation class.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "clang/Lex/TokenConcatenation.h"
147330f729Sjoerg #include "clang/Basic/CharInfo.h"
157330f729Sjoerg #include "clang/Lex/Preprocessor.h"
167330f729Sjoerg #include "llvm/Support/ErrorHandling.h"
177330f729Sjoerg using namespace clang;
187330f729Sjoerg 
197330f729Sjoerg 
207330f729Sjoerg /// IsStringPrefix - Return true if Str is a string prefix.
217330f729Sjoerg /// 'L', 'u', 'U', or 'u8'. Including raw versions.
IsStringPrefix(StringRef Str,bool CPlusPlus11)227330f729Sjoerg static bool IsStringPrefix(StringRef Str, bool CPlusPlus11) {
237330f729Sjoerg 
247330f729Sjoerg   if (Str[0] == 'L' ||
257330f729Sjoerg       (CPlusPlus11 && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) {
267330f729Sjoerg 
277330f729Sjoerg     if (Str.size() == 1)
287330f729Sjoerg       return true; // "L", "u", "U", and "R"
297330f729Sjoerg 
307330f729Sjoerg     // Check for raw flavors. Need to make sure the first character wasn't
317330f729Sjoerg     // already R. Need CPlusPlus11 check for "LR".
327330f729Sjoerg     if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus11)
337330f729Sjoerg       return true; // "LR", "uR", "UR"
347330f729Sjoerg 
357330f729Sjoerg     // Check for "u8" and "u8R"
367330f729Sjoerg     if (Str[0] == 'u' && Str[1] == '8') {
377330f729Sjoerg       if (Str.size() == 2) return true; // "u8"
387330f729Sjoerg       if (Str.size() == 3 && Str[2] == 'R') return true; // "u8R"
397330f729Sjoerg     }
407330f729Sjoerg   }
417330f729Sjoerg 
427330f729Sjoerg   return false;
437330f729Sjoerg }
447330f729Sjoerg 
457330f729Sjoerg /// IsIdentifierStringPrefix - Return true if the spelling of the token
467330f729Sjoerg /// is literally 'L', 'u', 'U', or 'u8'. Including raw versions.
IsIdentifierStringPrefix(const Token & Tok) const477330f729Sjoerg bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const {
487330f729Sjoerg   const LangOptions &LangOpts = PP.getLangOpts();
497330f729Sjoerg 
507330f729Sjoerg   if (!Tok.needsCleaning()) {
517330f729Sjoerg     if (Tok.getLength() < 1 || Tok.getLength() > 3)
527330f729Sjoerg       return false;
537330f729Sjoerg     SourceManager &SM = PP.getSourceManager();
547330f729Sjoerg     const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
557330f729Sjoerg     return IsStringPrefix(StringRef(Ptr, Tok.getLength()),
567330f729Sjoerg                           LangOpts.CPlusPlus11);
577330f729Sjoerg   }
587330f729Sjoerg 
597330f729Sjoerg   if (Tok.getLength() < 256) {
607330f729Sjoerg     char Buffer[256];
617330f729Sjoerg     const char *TokPtr = Buffer;
627330f729Sjoerg     unsigned length = PP.getSpelling(Tok, TokPtr);
637330f729Sjoerg     return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus11);
647330f729Sjoerg   }
657330f729Sjoerg 
667330f729Sjoerg   return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus11);
677330f729Sjoerg }
687330f729Sjoerg 
TokenConcatenation(const Preprocessor & pp)697330f729Sjoerg TokenConcatenation::TokenConcatenation(const Preprocessor &pp) : PP(pp) {
707330f729Sjoerg   memset(TokenInfo, 0, sizeof(TokenInfo));
717330f729Sjoerg 
727330f729Sjoerg   // These tokens have custom code in AvoidConcat.
737330f729Sjoerg   TokenInfo[tok::identifier      ] |= aci_custom;
747330f729Sjoerg   TokenInfo[tok::numeric_constant] |= aci_custom_firstchar;
757330f729Sjoerg   TokenInfo[tok::period          ] |= aci_custom_firstchar;
767330f729Sjoerg   TokenInfo[tok::amp             ] |= aci_custom_firstchar;
777330f729Sjoerg   TokenInfo[tok::plus            ] |= aci_custom_firstchar;
787330f729Sjoerg   TokenInfo[tok::minus           ] |= aci_custom_firstchar;
797330f729Sjoerg   TokenInfo[tok::slash           ] |= aci_custom_firstchar;
807330f729Sjoerg   TokenInfo[tok::less            ] |= aci_custom_firstchar;
817330f729Sjoerg   TokenInfo[tok::greater         ] |= aci_custom_firstchar;
827330f729Sjoerg   TokenInfo[tok::pipe            ] |= aci_custom_firstchar;
837330f729Sjoerg   TokenInfo[tok::percent         ] |= aci_custom_firstchar;
847330f729Sjoerg   TokenInfo[tok::colon           ] |= aci_custom_firstchar;
857330f729Sjoerg   TokenInfo[tok::hash            ] |= aci_custom_firstchar;
867330f729Sjoerg   TokenInfo[tok::arrow           ] |= aci_custom_firstchar;
877330f729Sjoerg 
887330f729Sjoerg   // These tokens have custom code in C++11 mode.
897330f729Sjoerg   if (PP.getLangOpts().CPlusPlus11) {
907330f729Sjoerg     TokenInfo[tok::string_literal      ] |= aci_custom;
917330f729Sjoerg     TokenInfo[tok::wide_string_literal ] |= aci_custom;
927330f729Sjoerg     TokenInfo[tok::utf8_string_literal ] |= aci_custom;
937330f729Sjoerg     TokenInfo[tok::utf16_string_literal] |= aci_custom;
947330f729Sjoerg     TokenInfo[tok::utf32_string_literal] |= aci_custom;
957330f729Sjoerg     TokenInfo[tok::char_constant       ] |= aci_custom;
967330f729Sjoerg     TokenInfo[tok::wide_char_constant  ] |= aci_custom;
977330f729Sjoerg     TokenInfo[tok::utf16_char_constant ] |= aci_custom;
987330f729Sjoerg     TokenInfo[tok::utf32_char_constant ] |= aci_custom;
997330f729Sjoerg   }
1007330f729Sjoerg 
1017330f729Sjoerg   // These tokens have custom code in C++17 mode.
1027330f729Sjoerg   if (PP.getLangOpts().CPlusPlus17)
1037330f729Sjoerg     TokenInfo[tok::utf8_char_constant] |= aci_custom;
1047330f729Sjoerg 
1057330f729Sjoerg   // These tokens have custom code in C++2a mode.
106*e038c9c4Sjoerg   if (PP.getLangOpts().CPlusPlus20)
1077330f729Sjoerg     TokenInfo[tok::lessequal ] |= aci_custom_firstchar;
1087330f729Sjoerg 
1097330f729Sjoerg   // These tokens change behavior if followed by an '='.
1107330f729Sjoerg   TokenInfo[tok::amp         ] |= aci_avoid_equal;           // &=
1117330f729Sjoerg   TokenInfo[tok::plus        ] |= aci_avoid_equal;           // +=
1127330f729Sjoerg   TokenInfo[tok::minus       ] |= aci_avoid_equal;           // -=
1137330f729Sjoerg   TokenInfo[tok::slash       ] |= aci_avoid_equal;           // /=
1147330f729Sjoerg   TokenInfo[tok::less        ] |= aci_avoid_equal;           // <=
1157330f729Sjoerg   TokenInfo[tok::greater     ] |= aci_avoid_equal;           // >=
1167330f729Sjoerg   TokenInfo[tok::pipe        ] |= aci_avoid_equal;           // |=
1177330f729Sjoerg   TokenInfo[tok::percent     ] |= aci_avoid_equal;           // %=
1187330f729Sjoerg   TokenInfo[tok::star        ] |= aci_avoid_equal;           // *=
1197330f729Sjoerg   TokenInfo[tok::exclaim     ] |= aci_avoid_equal;           // !=
1207330f729Sjoerg   TokenInfo[tok::lessless    ] |= aci_avoid_equal;           // <<=
1217330f729Sjoerg   TokenInfo[tok::greatergreater] |= aci_avoid_equal;         // >>=
1227330f729Sjoerg   TokenInfo[tok::caret       ] |= aci_avoid_equal;           // ^=
1237330f729Sjoerg   TokenInfo[tok::equal       ] |= aci_avoid_equal;           // ==
1247330f729Sjoerg }
1257330f729Sjoerg 
1267330f729Sjoerg /// GetFirstChar - Get the first character of the token \arg Tok,
1277330f729Sjoerg /// avoiding calls to getSpelling where possible.
GetFirstChar(const Preprocessor & PP,const Token & Tok)1287330f729Sjoerg static char GetFirstChar(const Preprocessor &PP, const Token &Tok) {
1297330f729Sjoerg   if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
1307330f729Sjoerg     // Avoid spelling identifiers, the most common form of token.
1317330f729Sjoerg     return II->getNameStart()[0];
1327330f729Sjoerg   } else if (!Tok.needsCleaning()) {
1337330f729Sjoerg     if (Tok.isLiteral() && Tok.getLiteralData()) {
1347330f729Sjoerg       return *Tok.getLiteralData();
1357330f729Sjoerg     } else {
1367330f729Sjoerg       SourceManager &SM = PP.getSourceManager();
1377330f729Sjoerg       return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
1387330f729Sjoerg     }
1397330f729Sjoerg   } else if (Tok.getLength() < 256) {
1407330f729Sjoerg     char Buffer[256];
1417330f729Sjoerg     const char *TokPtr = Buffer;
1427330f729Sjoerg     PP.getSpelling(Tok, TokPtr);
1437330f729Sjoerg     return TokPtr[0];
1447330f729Sjoerg   } else {
1457330f729Sjoerg     return PP.getSpelling(Tok)[0];
1467330f729Sjoerg   }
1477330f729Sjoerg }
1487330f729Sjoerg 
1497330f729Sjoerg /// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
1507330f729Sjoerg /// the two individual tokens to be lexed as a single token, return true
1517330f729Sjoerg /// (which causes a space to be printed between them).  This allows the output
1527330f729Sjoerg /// of -E mode to be lexed to the same token stream as lexing the input
1537330f729Sjoerg /// directly would.
1547330f729Sjoerg ///
1557330f729Sjoerg /// This code must conservatively return true if it doesn't want to be 100%
1567330f729Sjoerg /// accurate.  This will cause the output to include extra space characters,
1577330f729Sjoerg /// but the resulting output won't have incorrect concatenations going on.
1587330f729Sjoerg /// Examples include "..", which we print with a space between, because we
1597330f729Sjoerg /// don't want to track enough to tell "x.." from "...".
AvoidConcat(const Token & PrevPrevTok,const Token & PrevTok,const Token & Tok) const1607330f729Sjoerg bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
1617330f729Sjoerg                                      const Token &PrevTok,
1627330f729Sjoerg                                      const Token &Tok) const {
1637330f729Sjoerg   // Conservatively assume that every annotation token that has a printable
1647330f729Sjoerg   // form requires whitespace.
1657330f729Sjoerg   if (PrevTok.isAnnotation())
1667330f729Sjoerg     return true;
1677330f729Sjoerg 
1687330f729Sjoerg   // First, check to see if the tokens were directly adjacent in the original
1697330f729Sjoerg   // source.  If they were, it must be okay to stick them together: if there
1707330f729Sjoerg   // were an issue, the tokens would have been lexed differently.
1717330f729Sjoerg   SourceManager &SM = PP.getSourceManager();
1727330f729Sjoerg   SourceLocation PrevSpellLoc = SM.getSpellingLoc(PrevTok.getLocation());
1737330f729Sjoerg   SourceLocation SpellLoc = SM.getSpellingLoc(Tok.getLocation());
1747330f729Sjoerg   if (PrevSpellLoc.getLocWithOffset(PrevTok.getLength()) == SpellLoc)
1757330f729Sjoerg     return false;
1767330f729Sjoerg 
1777330f729Sjoerg   tok::TokenKind PrevKind = PrevTok.getKind();
1787330f729Sjoerg   if (!PrevTok.isAnnotation() && PrevTok.getIdentifierInfo())
1797330f729Sjoerg     PrevKind = tok::identifier; // Language keyword or named operator.
1807330f729Sjoerg 
1817330f729Sjoerg   // Look up information on when we should avoid concatenation with prevtok.
1827330f729Sjoerg   unsigned ConcatInfo = TokenInfo[PrevKind];
1837330f729Sjoerg 
1847330f729Sjoerg   // If prevtok never causes a problem for anything after it, return quickly.
1857330f729Sjoerg   if (ConcatInfo == 0) return false;
1867330f729Sjoerg 
1877330f729Sjoerg   if (ConcatInfo & aci_avoid_equal) {
1887330f729Sjoerg     // If the next token is '=' or '==', avoid concatenation.
1897330f729Sjoerg     if (Tok.isOneOf(tok::equal, tok::equalequal))
1907330f729Sjoerg       return true;
1917330f729Sjoerg     ConcatInfo &= ~aci_avoid_equal;
1927330f729Sjoerg   }
1937330f729Sjoerg   if (Tok.isAnnotation()) {
1947330f729Sjoerg     // Modules annotation can show up when generated automatically for includes.
1957330f729Sjoerg     assert(Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin,
1967330f729Sjoerg                        tok::annot_module_end) &&
1977330f729Sjoerg            "unexpected annotation in AvoidConcat");
1987330f729Sjoerg     ConcatInfo = 0;
1997330f729Sjoerg   }
2007330f729Sjoerg 
2017330f729Sjoerg   if (ConcatInfo == 0)
2027330f729Sjoerg     return false;
2037330f729Sjoerg 
2047330f729Sjoerg   // Basic algorithm: we look at the first character of the second token, and
2057330f729Sjoerg   // determine whether it, if appended to the first token, would form (or
2067330f729Sjoerg   // would contribute) to a larger token if concatenated.
2077330f729Sjoerg   char FirstChar = 0;
2087330f729Sjoerg   if (ConcatInfo & aci_custom) {
2097330f729Sjoerg     // If the token does not need to know the first character, don't get it.
2107330f729Sjoerg   } else {
2117330f729Sjoerg     FirstChar = GetFirstChar(PP, Tok);
2127330f729Sjoerg   }
2137330f729Sjoerg 
2147330f729Sjoerg   switch (PrevKind) {
2157330f729Sjoerg   default:
2167330f729Sjoerg     llvm_unreachable("InitAvoidConcatTokenInfo built wrong");
2177330f729Sjoerg 
2187330f729Sjoerg   case tok::raw_identifier:
2197330f729Sjoerg     llvm_unreachable("tok::raw_identifier in non-raw lexing mode!");
2207330f729Sjoerg 
2217330f729Sjoerg   case tok::string_literal:
2227330f729Sjoerg   case tok::wide_string_literal:
2237330f729Sjoerg   case tok::utf8_string_literal:
2247330f729Sjoerg   case tok::utf16_string_literal:
2257330f729Sjoerg   case tok::utf32_string_literal:
2267330f729Sjoerg   case tok::char_constant:
2277330f729Sjoerg   case tok::wide_char_constant:
2287330f729Sjoerg   case tok::utf8_char_constant:
2297330f729Sjoerg   case tok::utf16_char_constant:
2307330f729Sjoerg   case tok::utf32_char_constant:
2317330f729Sjoerg     if (!PP.getLangOpts().CPlusPlus11)
2327330f729Sjoerg       return false;
2337330f729Sjoerg 
2347330f729Sjoerg     // In C++11, a string or character literal followed by an identifier is a
2357330f729Sjoerg     // single token.
2367330f729Sjoerg     if (Tok.getIdentifierInfo())
2377330f729Sjoerg       return true;
2387330f729Sjoerg 
2397330f729Sjoerg     // A ud-suffix is an identifier. If the previous token ends with one, treat
2407330f729Sjoerg     // it as an identifier.
2417330f729Sjoerg     if (!PrevTok.hasUDSuffix())
2427330f729Sjoerg       return false;
2437330f729Sjoerg     LLVM_FALLTHROUGH;
2447330f729Sjoerg   case tok::identifier:   // id+id or id+number or id+L"foo".
2457330f729Sjoerg     // id+'.'... will not append.
2467330f729Sjoerg     if (Tok.is(tok::numeric_constant))
2477330f729Sjoerg       return GetFirstChar(PP, Tok) != '.';
2487330f729Sjoerg 
2497330f729Sjoerg     if (Tok.getIdentifierInfo() ||
2507330f729Sjoerg         Tok.isOneOf(tok::wide_string_literal, tok::utf8_string_literal,
2517330f729Sjoerg                     tok::utf16_string_literal, tok::utf32_string_literal,
2527330f729Sjoerg                     tok::wide_char_constant, tok::utf8_char_constant,
2537330f729Sjoerg                     tok::utf16_char_constant, tok::utf32_char_constant))
2547330f729Sjoerg       return true;
2557330f729Sjoerg 
2567330f729Sjoerg     // If this isn't identifier + string, we're done.
2577330f729Sjoerg     if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal))
2587330f729Sjoerg       return false;
2597330f729Sjoerg 
2607330f729Sjoerg     // Otherwise, this is a narrow character or string.  If the *identifier*
2617330f729Sjoerg     // is a literal 'L', 'u8', 'u' or 'U', avoid pasting L "foo" -> L"foo".
2627330f729Sjoerg     return IsIdentifierStringPrefix(PrevTok);
2637330f729Sjoerg 
2647330f729Sjoerg   case tok::numeric_constant:
2657330f729Sjoerg     return isPreprocessingNumberBody(FirstChar) ||
2667330f729Sjoerg            FirstChar == '+' || FirstChar == '-';
2677330f729Sjoerg   case tok::period:          // ..., .*, .1234
2687330f729Sjoerg     return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
2697330f729Sjoerg            isDigit(FirstChar) ||
2707330f729Sjoerg            (PP.getLangOpts().CPlusPlus && FirstChar == '*');
2717330f729Sjoerg   case tok::amp:             // &&
2727330f729Sjoerg     return FirstChar == '&';
2737330f729Sjoerg   case tok::plus:            // ++
2747330f729Sjoerg     return FirstChar == '+';
2757330f729Sjoerg   case tok::minus:           // --, ->, ->*
2767330f729Sjoerg     return FirstChar == '-' || FirstChar == '>';
2777330f729Sjoerg   case tok::slash:           //, /*, //
2787330f729Sjoerg     return FirstChar == '*' || FirstChar == '/';
2797330f729Sjoerg   case tok::less:            // <<, <<=, <:, <%
2807330f729Sjoerg     return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
2817330f729Sjoerg   case tok::greater:         // >>, >>=
2827330f729Sjoerg     return FirstChar == '>';
2837330f729Sjoerg   case tok::pipe:            // ||
2847330f729Sjoerg     return FirstChar == '|';
2857330f729Sjoerg   case tok::percent:         // %>, %:
2867330f729Sjoerg     return FirstChar == '>' || FirstChar == ':';
2877330f729Sjoerg   case tok::colon:           // ::, :>
2887330f729Sjoerg     return FirstChar == '>' ||
2897330f729Sjoerg     (PP.getLangOpts().CPlusPlus && FirstChar == ':');
2907330f729Sjoerg   case tok::hash:            // ##, #@, %:%:
2917330f729Sjoerg     return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
2927330f729Sjoerg   case tok::arrow:           // ->*
2937330f729Sjoerg     return PP.getLangOpts().CPlusPlus && FirstChar == '*';
2947330f729Sjoerg   case tok::lessequal:       // <=> (C++2a)
295*e038c9c4Sjoerg     return PP.getLangOpts().CPlusPlus20 && FirstChar == '>';
2967330f729Sjoerg   }
2977330f729Sjoerg }
298