int parseIdentifier (CodeDocument::Iterator& source) noexcept
    {
        int tokenLength = 0;
        String::CharPointerType::CharType possibleIdentifier [100];
        String::CharPointerType possible (possibleIdentifier);

        while (isIdentifierBody (source.peekNextChar()))
        {
            const juce_wchar c = source.nextChar();

            if (tokenLength < 20)
                possible.write (c);

            ++tokenLength;
        }

        if (tokenLength > 1 && tokenLength <= 16)
        {
            possible.writeNull();

            if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
                return CPlusPlusCodeTokeniser::tokenType_builtInKeyword;
        }

        return CPlusPlusCodeTokeniser::tokenType_identifier;
    }
static int parseIdentifier (CodeDocument::Iterator& source) throw()
{
    static const tchar* keywords2Char[] =
        { T("if"), T("do"), T("or"), 0 };

    static const tchar* keywords3Char[] =
        { T("for"), T("int"), T("new"), T("try"), T("xor"), T("and"), T("asm"), T("not"), 0 };

    static const tchar* keywords4Char[] =
        { T("bool"), T("void"), T("this"), T("true"), T("long"), T("else"), T("char"),
          T("enum"), T("case"), T("goto"), T("auto"), 0 };

    static const tchar* keywords5Char[] =
        {  T("while"), T("bitor"), T("break"), T("catch"), T("class"), T("compl"), T("const"), T("false"),
            T("float"), T("short"), T("throw"), T("union"), T("using"), T("or_eq"), 0 };

    static const tchar* keywords6Char[] =
        { T("return"), T("struct"), T("and_eq"), T("bitand"), T("delete"), T("double"), T("extern"),
          T("friend"), T("inline"), T("not_eq"), T("public"), T("sizeof"), T("static"), T("signed"),
          T("switch"), T("typeid"), T("wchar_t"), T("xor_eq"), 0};

    static const tchar* keywordsOther[] =
        { T("const_cast"), T("continue"), T("default"), T("explicit"), T("mutable"), T("namespace"),
          T("operator"), T("private"), T("protected"), T("register"), T("reinterpret_cast"), T("static_cast"),
          T("template"), T("typedef"), T("typename"), T("unsigned"), T("virtual"), T("volatile"),
          T("@implementation"), T("@interface"), T("@end"), T("@synthesize"), T("@dynamic"), T("@public"),
          T("@private"), T("@property"), T("@protected"), T("@class"), 0 };

    int tokenLength = 0;
    tchar possibleIdentifier [19];

    while (isIdentifierBody (source.peekNextChar()))
    {
        const tchar c = source.nextChar();

        if (tokenLength < numElementsInArray (possibleIdentifier) - 1)
            possibleIdentifier [tokenLength] = c;

        ++tokenLength;
    }

    if (tokenLength > 1 && tokenLength <= 16)
    {
        possibleIdentifier [tokenLength] = 0;
        const tchar** k;

        switch (tokenLength)
        {
            case 2:     k = keywords2Char; break;
            case 3:     k = keywords3Char; break;
            case 4:     k = keywords4Char; break;
            case 5:     k = keywords5Char; break;
            case 6:     k = keywords6Char; break;
            default:    k = keywordsOther; break;
        }

        int i = 0;
        while (k[i] != 0)
        {
            if (k[i][0] == possibleIdentifier[0] && CharacterFunctions::compare (k[i], possibleIdentifier) == 0)
                return CPlusPlusCodeTokeniser::tokenType_builtInKeyword;

            ++i;
        }
    }

    return CPlusPlusCodeTokeniser::tokenType_identifier;
}
void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) {
  auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl");
  SourceLocation Loc = TL.getBeginLoc();

  if (Loc.isInvalid() || Loc.isMacroID())
    return;

  // Look through qualification.
  if (auto QualLoc = TL.getAs<QualifiedTypeLoc>())
    TL = QualLoc.getUnqualifiedLoc();

  auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();
  if (!BuiltinLoc)
    return;

  Token Tok = getTokenAtLoc(Loc, Result, *IdentTable);
  // Ensure the location actually points to one of the builting integral type
  // names we're interested in. Otherwise, we might be getting this match from
  // implicit code (e.g. an implicit assignment operator of a class containing
  // an array of non-POD types).
  if (!Tok.isOneOf(tok::kw_short, tok::kw_long, tok::kw_unsigned,
                   tok::kw_signed))
    return;

  bool IsSigned;
  unsigned Width;
  const TargetInfo &TargetInfo = Result.Context->getTargetInfo();

  // Look for uses of short, long, long long and their unsigned versions.
  switch (BuiltinLoc.getTypePtr()->getKind()) {
  case BuiltinType::Short:
    Width = TargetInfo.getShortWidth();
    IsSigned = true;
    break;
  case BuiltinType::Long:
    Width = TargetInfo.getLongWidth();
    IsSigned = true;
    break;
  case BuiltinType::LongLong:
    Width = TargetInfo.getLongLongWidth();
    IsSigned = true;
    break;
  case BuiltinType::UShort:
    Width = TargetInfo.getShortWidth();
    IsSigned = false;
    break;
  case BuiltinType::ULong:
    Width = TargetInfo.getLongWidth();
    IsSigned = false;
    break;
  case BuiltinType::ULongLong:
    Width = TargetInfo.getLongLongWidth();
    IsSigned = false;
    break;
  default:
    return;
  }

  // We allow "unsigned short port" as that's reasonably common and required by
  // the sockets API.
  const StringRef Port = "unsigned short port";
  const char *Data = Result.SourceManager->getCharacterData(Loc);
  if (!std::strncmp(Data, Port.data(), Port.size()) &&
      !isIdentifierBody(Data[Port.size()]))
    return;

  std::string Replacement =
      ((IsSigned ? SignedTypePrefix : UnsignedTypePrefix) + Twine(Width) +
       TypeSuffix)
          .str();

  // We don't add a fix-it as changing the type can easily break code,
  // e.g. when a function requires a 'long' argument on all platforms.
  // QualTypes are printed with implicit quotes.
  diag(Loc, "consider replacing %0 with '%1'") << BuiltinLoc.getType()
                                               << Replacement;
}