Blame src/clangparser.cpp

Packit Service 50c9f2
#include "clangparser.h"
Packit Service 50c9f2
#include "settings.h"
Packit Service 50c9f2
#include <stdio.h>
Packit Service 50c9f2
Packit Service 50c9f2
#if USE_LIBCLANG
Packit Service 50c9f2
#include <clang-c/Index.h>
Packit Service 50c9f2
#include "clang/Tooling/Tooling.h"
Packit Service 50c9f2
#include <qfileinfo.h>
Packit Service 50c9f2
#include <stdlib.h>
Packit Service 50c9f2
#include "message.h"
Packit Service 50c9f2
#include "sortdict.h"
Packit Service 50c9f2
#include "outputgen.h"
Packit Service 50c9f2
#include "filedef.h"
Packit Service 50c9f2
#include "memberdef.h"
Packit Service 50c9f2
#include "doxygen.h"
Packit Service 50c9f2
#include "util.h"
Packit Service 50c9f2
#include "config.h"
Packit Service 50c9f2
#include "growbuf.h"
Packit Service 50c9f2
#include "membername.h"
Packit Service 50c9f2
#include "filename.h"
Packit Service 50c9f2
#include "tooltip.h"
Packit Service 50c9f2
Packit Service 50c9f2
static Definition *g_currentDefinition=0;
Packit Service 50c9f2
static MemberDef  *g_currentMemberDef=0;
Packit Service 50c9f2
static uint        g_currentLine=0;
Packit Service 50c9f2
static bool        g_searchForBody=FALSE;
Packit Service 50c9f2
static bool        g_insideBody=FALSE;
Packit Service 50c9f2
static uint        g_bracketCount=0;
Packit Service 50c9f2
#endif
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser *ClangParser::instance()
Packit Service 50c9f2
{
Packit Service 50c9f2
  if (!s_instance) s_instance = new ClangParser;
Packit Service 50c9f2
  return s_instance;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser *ClangParser::s_instance = 0;
Packit Service 50c9f2
Packit Service 50c9f2
//--------------------------------------------------------------------------
Packit Service 50c9f2
#if USE_LIBCLANG
Packit Service 50c9f2
Packit Service 50c9f2
class ClangParser::Private
Packit Service 50c9f2
{
Packit Service 50c9f2
  public:
Packit Service 50c9f2
    enum DetectedLang { Detected_Cpp, Detected_ObjC, Detected_ObjCpp };
Packit Service 50c9f2
    Private() : tu(0), tokens(0), numTokens(0), cursors(0), 
Packit Service 50c9f2
                ufs(0), sources(0), numFiles(0), fileMapping(257),
Packit Service 50c9f2
                detectedLang(Detected_Cpp)
Packit Service 50c9f2
    { fileMapping.setAutoDelete(TRUE); }
Packit Service 50c9f2
    int getCurrentTokenLine();
Packit Service 50c9f2
    CXIndex index;
Packit Service 50c9f2
    CXTranslationUnit tu;
Packit Service 50c9f2
    QCString fileName;
Packit Service 50c9f2
    CXToken *tokens;
Packit Service 50c9f2
    uint numTokens;
Packit Service 50c9f2
    CXCursor *cursors;
Packit Service 50c9f2
    uint curLine;
Packit Service 50c9f2
    uint curToken;
Packit Service 50c9f2
    CXUnsavedFile *ufs;
Packit Service 50c9f2
    QCString *sources;
Packit Service 50c9f2
    uint numFiles;
Packit Service 50c9f2
    QDict<uint> fileMapping;
Packit Service 50c9f2
    DetectedLang detectedLang;
Packit Service 50c9f2
};
Packit Service 50c9f2
Packit Service 50c9f2
static QCString detab(const QCString &s)
Packit Service 50c9f2
{
Packit Service 50c9f2
  static int tabSize = Config_getInt(TAB_SIZE);
Packit Service 50c9f2
  GrowBuf out;
Packit Service 50c9f2
  int size = s.length();
Packit Service 50c9f2
  const char *data = s.data();
Packit Service 50c9f2
  int i=0;
Packit Service 50c9f2
  int col=0;
Packit Service 50c9f2
  const int maxIndent=1000000; // value representing infinity
Packit Service 50c9f2
  int minIndent=maxIndent;
Packit Service 50c9f2
  while (i
Packit Service 50c9f2
  {
Packit Service 50c9f2
    char c = data[i++];
Packit Service 50c9f2
    switch(c)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      case '\t': // expand tab
Packit Service 50c9f2
        {
Packit Service 50c9f2
          int stop = tabSize - (col%tabSize);
Packit Service 50c9f2
          //printf("expand at %d stop=%d\n",col,stop);
Packit Service 50c9f2
          col+=stop;
Packit Service 50c9f2
          while (stop--) out.addChar(' '); 
Packit Service 50c9f2
        }
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      case '\n': // reset colomn counter
Packit Service 50c9f2
        out.addChar(c);
Packit Service 50c9f2
        col=0;
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      case ' ': // increment column counter
Packit Service 50c9f2
        out.addChar(c);
Packit Service 50c9f2
        col++;
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      default: // non-whitespace => update minIndent
Packit Service 50c9f2
        out.addChar(c);
Packit Service 50c9f2
        if (c<0 && i
Packit Service 50c9f2
        {
Packit Service 50c9f2
          out.addChar(data[i++]); // >= 2 bytes
Packit Service 50c9f2
          if (((uchar)c&0xE0)==0xE0 && i
Packit Service 50c9f2
          {
Packit Service 50c9f2
            out.addChar(data[i++]); // 3 bytes
Packit Service 50c9f2
          }
Packit Service 50c9f2
          if (((uchar)c&0xF0)==0xF0 && i
Packit Service 50c9f2
          {
Packit Service 50c9f2
            out.addChar(data[i++]); // 4 byres
Packit Service 50c9f2
          }
Packit Service 50c9f2
        }
Packit Service 50c9f2
        if (col
Packit Service 50c9f2
        col++;
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  out.addChar(0);
Packit Service 50c9f2
  //printf("detab refIndent=%d\n",refIndent);
Packit Service 50c9f2
  return out.get();
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
/** Callback function called for each include in a translation unit */
Packit Service 50c9f2
static void inclusionVisitor(CXFile includedFile,
Packit Service 50c9f2
                             CXSourceLocation* /*inclusionStack*/,
Packit Service 50c9f2
                             unsigned /*includeLen*/,
Packit Service 50c9f2
                             CXClientData clientData)
Packit Service 50c9f2
{
Packit Service 50c9f2
  QDict<void> *fileDict = (QDict<void> *)clientData;
Packit Service 50c9f2
  CXString incFileName = clang_getFileName(includedFile);
Packit Service 50c9f2
  //printf("--- file %s includes %s\n",fileName,clang_getCString(incFileName));
Packit Service 50c9f2
  fileDict->insert(clang_getCString(incFileName),(void*)0x8);
Packit Service 50c9f2
  clang_disposeString(incFileName);
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
/** filter the \a files and only keep those that are found as include files
Packit Service 50c9f2
 *  within the current translation unit.
Packit Service 50c9f2
 *  @param[in,out] files The list of files to filter.
Packit Service 50c9f2
 */ 
Packit Service 50c9f2
void ClangParser::determineInputFilesInSameTu(QStrList &files)
Packit Service 50c9f2
{
Packit Service 50c9f2
  // put the files in this translation unit in a dictionary
Packit Service 50c9f2
  QDict<void> incFound(257);
Packit Service 50c9f2
  clang_getInclusions(p->tu,
Packit Service 50c9f2
      inclusionVisitor,
Packit Service 50c9f2
      (CXClientData)&incFound
Packit Service 50c9f2
      );
Packit Service 50c9f2
  // create a new filtered file list
Packit Service 50c9f2
  QStrList resultIncludes;
Packit Service 50c9f2
  QStrListIterator it2(files);
Packit Service 50c9f2
  for (it2.toFirst();it2.current();++it2)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    if (incFound.find(it2.current()))
Packit Service 50c9f2
    {
Packit Service 50c9f2
      resultIncludes.append(it2.current());
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  // replace the original list
Packit Service 50c9f2
  files=resultIncludes;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit)
Packit Service 50c9f2
{
Packit Service 50c9f2
  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
Packit Service 50c9f2
  static QStrList &includePath = Config_getList(INCLUDE_PATH);
Packit Service 50c9f2
  static QStrList clangOptions = Config_getList(CLANG_OPTIONS);
Packit Service 50c9f2
  static QCString clangCompileDatabase = Config_getList(CLANG_COMPILATION_DATABASE_PATH);
Packit Service 50c9f2
  if (!clangAssistedParsing) return;
Packit Service 50c9f2
  //printf("ClangParser::start(%s)\n",fileName);
Packit Service 50c9f2
  p->fileName = fileName;
Packit Service 50c9f2
  p->index    = clang_createIndex(0, 0);
Packit Service 50c9f2
  p->curLine  = 1;
Packit Service 50c9f2
  p->curToken = 0;
Packit Service 50c9f2
  QDictIterator<void> di(Doxygen::inputPaths);
Packit Service 50c9f2
  int argc=0;
Packit Service 50c9f2
  std::string error;
Packit Service 50c9f2
  // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
Packit Service 50c9f2
  // this only needs to be loaded once, and could be refactored to a higher level function
Packit Service 50c9f2
  static std::unique_ptr<clang::tooling::CompilationDatabase> db =
Packit Service 50c9f2
      clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error);
Packit Service 50c9f2
  int clang_option_len = 0;
Packit Service 50c9f2
  std::vector<clang::tooling::CompileCommand> command;
Packit Service 50c9f2
  if (strcmp(clangCompileDatabase, "0") != 0) {
Packit Service 50c9f2
      if (db == nullptr) {
Packit Service 50c9f2
          // user specified a path, but DB file was not found
Packit Service 50c9f2
          err("%s using clang compilation database path of: \"%s\"\n", error.c_str(),
Packit Service 50c9f2
              clangCompileDatabase.data());
Packit Service 50c9f2
      } else {
Packit Service 50c9f2
          // check if the file we are parsing is in the DB
Packit Service 50c9f2
          command = db->getCompileCommands(fileName);
Packit Service 50c9f2
          if (!command.empty() ) {
Packit Service 50c9f2
              // it's possible to have multiple entries for the same file, so use the last entry
Packit Service 50c9f2
              clang_option_len = command[command.size()-1].CommandLine.size();
Packit Service 50c9f2
          }
Packit Service 50c9f2
      }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  char **argv = (char**)malloc(sizeof(char*)*(4+Doxygen::inputPaths.count()+includePath.count()+clangOptions.count()+clang_option_len));
Packit Service 50c9f2
  if (!command.empty() ) {
Packit Service 50c9f2
      std::vector<std::string> options = command[command.size()-1].CommandLine;
Packit Service 50c9f2
      // copy each compiler option used from the database. Skip the first which is compiler exe.
Packit Service 50c9f2
      for (auto option = options.begin()+1; option != options.end(); option++) {
Packit Service 50c9f2
          argv[argc++] = strdup(option->c_str());
Packit Service 50c9f2
      }
Packit Service 50c9f2
      // this extra addition to argv is accounted for as we are skipping the first entry in
Packit Service 50c9f2
      argv[argc++]=strdup("-w"); // finally, turn off warnings.
Packit Service 50c9f2
  } else {
Packit Service 50c9f2
  // add include paths for input files
Packit Service 50c9f2
  for (di.toFirst();di.current();++di,++argc)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    QCString inc = QCString("-I")+di.currentKey();
Packit Service 50c9f2
    argv[argc]=strdup(inc.data());
Packit Service 50c9f2
    //printf("argv[%d]=%s\n",argc,argv[argc]);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  // add external include paths
Packit Service 50c9f2
  for (uint i=0;i
Packit Service 50c9f2
  {
Packit Service 50c9f2
    QCString inc = QCString("-I")+includePath.at(i);
Packit Service 50c9f2
    argv[argc++]=strdup(inc.data());
Packit Service 50c9f2
  }
Packit Service 50c9f2
  // user specified options
Packit Service 50c9f2
  for (uint i=0;i
Packit Service 50c9f2
  {
Packit Service 50c9f2
    argv[argc++]=strdup(clangOptions.at(i));
Packit Service 50c9f2
  }
Packit Service 50c9f2
  // extra options
Packit Service 50c9f2
  argv[argc++]=strdup("-ferror-limit=0");
Packit Service 50c9f2
  argv[argc++]=strdup("-x");
Packit Service 50c9f2
Packit Service 50c9f2
  // Since we can be presented with a .h file that can contain C/C++ or
Packit Service 50c9f2
  // Objective C code and we need to configure the parser before knowing this,
Packit Service 50c9f2
  // we use the source file to detected the language. Detection will fail if you
Packit Service 50c9f2
  // pass a bunch of .h files containing ObjC code, and no sources :-(
Packit Service 50c9f2
  SrcLangExt lang = getLanguageFromFileName(fileName);
Packit Service 50c9f2
  if (lang==SrcLangExt_ObjC || p->detectedLang!=ClangParser::Private::Detected_Cpp)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    QCString fn = fileName;
Packit Service 50c9f2
    if (p->detectedLang==ClangParser::Private::Detected_Cpp && 
Packit Service 50c9f2
        (fn.right(4).lower()==".cpp" || fn.right(4).lower()==".cxx" ||
Packit Service 50c9f2
         fn.right(3).lower()==".cc" || fn.right(2).lower()==".c"))
Packit Service 50c9f2
    { // fall back to C/C++ once we see an extension that indicates this
Packit Service 50c9f2
      p->detectedLang = ClangParser::Private::Detected_Cpp;
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else if (fn.right(3).lower()==".mm") // switch to Objective C++
Packit Service 50c9f2
    {
Packit Service 50c9f2
      p->detectedLang = ClangParser::Private::Detected_ObjCpp;
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else if (fn.right(2).lower()==".m") // switch to Objective C
Packit Service 50c9f2
    {
Packit Service 50c9f2
      p->detectedLang = ClangParser::Private::Detected_ObjC;
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  switch(p->detectedLang)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    case ClangParser::Private::Detected_Cpp: 
Packit Service 50c9f2
      argv[argc++]=strdup("c++"); 
Packit Service 50c9f2
      break;
Packit Service 50c9f2
    case ClangParser::Private::Detected_ObjC: 
Packit Service 50c9f2
      argv[argc++]=strdup("objective-c"); 
Packit Service 50c9f2
      break;
Packit Service 50c9f2
    case ClangParser::Private::Detected_ObjCpp: 
Packit Service 50c9f2
      argv[argc++]=strdup("objective-c++"); 
Packit Service 50c9f2
      break;
Packit Service 50c9f2
  }
Packit Service 50c9f2
Packit Service 50c9f2
  // provide the input and and its dependencies as unsaved files so we can
Packit Service 50c9f2
  // pass the filtered versions
Packit Service 50c9f2
  argv[argc++]=strdup(fileName);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
Packit Service 50c9f2
  //printf("source %s ----------\n%s\n-------------\n\n",
Packit Service 50c9f2
  //    fileName,p->source.data());
Packit Service 50c9f2
  uint numUnsavedFiles = filesInTranslationUnit.count()+1;
Packit Service 50c9f2
  p->numFiles = numUnsavedFiles;
Packit Service 50c9f2
  p->sources = new QCString[numUnsavedFiles];
Packit Service 50c9f2
  p->ufs     = new CXUnsavedFile[numUnsavedFiles];
Packit Service 50c9f2
  p->sources[0]      = detab(fileToString(fileName,filterSourceFiles,TRUE));
Packit Service 50c9f2
  p->ufs[0].Filename = strdup(fileName);
Packit Service 50c9f2
  p->ufs[0].Contents = p->sources[0].data();
Packit Service 50c9f2
  p->ufs[0].Length   = p->sources[0].length();
Packit Service 50c9f2
  QStrListIterator it(filesInTranslationUnit);
Packit Service 50c9f2
  uint i=1;
Packit Service 50c9f2
  for (it.toFirst();it.current() && i
Packit Service 50c9f2
  {
Packit Service 50c9f2
    p->fileMapping.insert(it.current(),new uint(i));
Packit Service 50c9f2
    p->sources[i]      = detab(fileToString(it.current(),filterSourceFiles,TRUE));
Packit Service 50c9f2
    p->ufs[i].Filename = strdup(it.current());
Packit Service 50c9f2
    p->ufs[i].Contents = p->sources[i].data();
Packit Service 50c9f2
    p->ufs[i].Length   = p->sources[i].length();
Packit Service 50c9f2
  }
Packit Service 50c9f2
Packit Service 50c9f2
  // let libclang do the actual parsing
Packit Service 50c9f2
  p->tu = clang_parseTranslationUnit(p->index, 0,
Packit Service 50c9f2
                                     argv, argc, p->ufs, numUnsavedFiles, 
Packit Service 50c9f2
                                     CXTranslationUnit_DetailedPreprocessingRecord);
Packit Service 50c9f2
  // free arguments
Packit Service 50c9f2
  for (int i=0;i
Packit Service 50c9f2
  {
Packit Service 50c9f2
    free(argv[i]);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  free(argv);
Packit Service 50c9f2
Packit Service 50c9f2
  if (p->tu)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    // filter out any includes not found by the clang parser
Packit Service 50c9f2
    determineInputFilesInSameTu(filesInTranslationUnit);
Packit Service 50c9f2
Packit Service 50c9f2
    // show any warnings that the compiler produced
Packit Service 50c9f2
    for (uint i=0, n=clang_getNumDiagnostics(p->tu); i!=n; ++i) 
Packit Service 50c9f2
    {
Packit Service 50c9f2
      CXDiagnostic diag = clang_getDiagnostic(p->tu, i); 
Packit Service 50c9f2
      CXString string = clang_formatDiagnostic(diag,
Packit Service 50c9f2
          clang_defaultDiagnosticDisplayOptions()); 
Packit Service 50c9f2
      err("%s [clang]\n",clang_getCString(string));
Packit Service 50c9f2
      clang_disposeString(string);
Packit Service 50c9f2
      clang_disposeDiagnostic(diag);
Packit Service 50c9f2
    }
Packit Service 50c9f2
Packit Service 50c9f2
    // create a source range for the given file
Packit Service 50c9f2
    QFileInfo fi(fileName);
Packit Service 50c9f2
    CXFile f = clang_getFile(p->tu, fileName);
Packit Service 50c9f2
    CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0);
Packit Service 50c9f2
    CXSourceLocation fileEnd   = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length);
Packit Service 50c9f2
    CXSourceRange    fileRange = clang_getRange(fileBegin, fileEnd);
Packit Service 50c9f2
Packit Service 50c9f2
    // produce a token stream for the file
Packit Service 50c9f2
    clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens);
Packit Service 50c9f2
Packit Service 50c9f2
    // produce cursors for each token in the stream
Packit Service 50c9f2
    p->cursors=new CXCursor[p->numTokens];
Packit Service 50c9f2
    clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  else
Packit Service 50c9f2
  {
Packit Service 50c9f2
    p->tokens    = 0;
Packit Service 50c9f2
    p->numTokens = 0;
Packit Service 50c9f2
    p->cursors   = 0;
Packit Service 50c9f2
    err("clang: Failed to parse translation unit %s\n",fileName);
Packit Service 50c9f2
  }
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::switchToFile(const char *fileName)
Packit Service 50c9f2
{
Packit Service 50c9f2
  if (p->tu)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    delete[] p->cursors;
Packit Service 50c9f2
    clang_disposeTokens(p->tu,p->tokens,p->numTokens);
Packit Service 50c9f2
    p->tokens    = 0;
Packit Service 50c9f2
    p->numTokens = 0;
Packit Service 50c9f2
    p->cursors   = 0;
Packit Service 50c9f2
Packit Service 50c9f2
    QFileInfo fi(fileName);
Packit Service 50c9f2
    CXFile f = clang_getFile(p->tu, fileName);
Packit Service 50c9f2
    uint *pIndex=p->fileMapping.find(fileName);
Packit Service 50c9f2
    if (pIndex && *pIndex<p->numFiles)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      uint i=*pIndex;
Packit Service 50c9f2
      //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length);
Packit Service 50c9f2
      CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0);
Packit Service 50c9f2
      CXSourceLocation fileEnd   = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length);
Packit Service 50c9f2
      CXSourceRange    fileRange = clang_getRange(fileBegin, fileEnd);
Packit Service 50c9f2
Packit Service 50c9f2
      clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens);
Packit Service 50c9f2
      p->cursors=new CXCursor[p->numTokens];
Packit Service 50c9f2
      clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors);
Packit Service 50c9f2
Packit Service 50c9f2
      p->curLine  = 1;
Packit Service 50c9f2
      p->curToken = 0;
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else
Packit Service 50c9f2
    {
Packit Service 50c9f2
      err("clang: Failed to find input file %s in mapping\n",fileName);
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::finish()
Packit Service 50c9f2
{
Packit Service 50c9f2
  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
Packit Service 50c9f2
  if (!clangAssistedParsing) return;
Packit Service 50c9f2
  if (p->tu)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    //printf("ClangParser::finish()\n");
Packit Service 50c9f2
    delete[] p->cursors;
Packit Service 50c9f2
    clang_disposeTokens(p->tu,p->tokens,p->numTokens);
Packit Service 50c9f2
    clang_disposeTranslationUnit(p->tu);
Packit Service 50c9f2
    clang_disposeIndex(p->index);
Packit Service 50c9f2
    p->fileMapping.clear();
Packit Service 50c9f2
    p->tokens    = 0;
Packit Service 50c9f2
    p->numTokens = 0;
Packit Service 50c9f2
    p->cursors   = 0;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  for (uint i=0;i<p->numFiles;i++)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    free((void *)p->ufs[i].Filename);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  delete[] p->ufs;
Packit Service 50c9f2
  delete[] p->sources;
Packit Service 50c9f2
  p->ufs       = 0;
Packit Service 50c9f2
  p->sources   = 0;
Packit Service 50c9f2
  p->numFiles  = 0;
Packit Service 50c9f2
  p->tu        = 0;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
int ClangParser::Private::getCurrentTokenLine()
Packit Service 50c9f2
{
Packit Service 50c9f2
  uint l, c;
Packit Service 50c9f2
  if (numTokens==0) return 1;
Packit Service 50c9f2
  // guard against filters that reduce the number of lines
Packit Service 50c9f2
  if (curToken>=numTokens) curToken=numTokens-1;
Packit Service 50c9f2
  CXSourceLocation start = clang_getTokenLocation(tu,tokens[curToken]);
Packit Service 50c9f2
  clang_getSpellingLocation(start, 0, &l, &c, 0);
Packit Service 50c9f2
  return l;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
QCString ClangParser::lookup(uint line,const char *symbol)
Packit Service 50c9f2
{
Packit Service 50c9f2
  //printf("ClangParser::lookup(%d,%s)\n",line,symbol);
Packit Service 50c9f2
  QCString result;
Packit Service 50c9f2
  if (symbol==0) return result;
Packit Service 50c9f2
  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
Packit Service 50c9f2
  if (!clangAssistedParsing) return result;
Packit Service 50c9f2
Packit Service 50c9f2
  int sl = strlen(symbol);
Packit Service 50c9f2
  uint l = p->getCurrentTokenLine();
Packit Service 50c9f2
  while (l>=line && p->curToken>0)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    if (l==line) // already at the right line
Packit Service 50c9f2
    {
Packit Service 50c9f2
      p->curToken--; // linear search to start of the line
Packit Service 50c9f2
      l = p->getCurrentTokenLine();
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else 
Packit Service 50c9f2
    {
Packit Service 50c9f2
      p->curToken/=2; // binary search backward
Packit Service 50c9f2
      l = p->getCurrentTokenLine();
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  bool found=FALSE;
Packit Service 50c9f2
  while (l<=line && p->curToken<p->numTokens && !found)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    CXString tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]);
Packit Service 50c9f2
    //if (l==line)
Packit Service 50c9f2
    //{
Packit Service 50c9f2
    //  printf("try to match symbol %s with token %s\n",symbol,clang_getCString(tokenString));
Packit Service 50c9f2
    //}
Packit Service 50c9f2
    const char *ts = clang_getCString(tokenString);
Packit Service 50c9f2
    int tl = strlen(ts);
Packit Service 50c9f2
    int startIndex = p->curToken;
Packit Service 50c9f2
    if (l==line && strncmp(ts,symbol,tl)==0) // found partial match at the correct line
Packit Service 50c9f2
    {
Packit Service 50c9f2
      int offset = tl;
Packit Service 50c9f2
      while (offset
Packit Service 50c9f2
      {
Packit Service 50c9f2
        //printf("found partial match\n");
Packit Service 50c9f2
        p->curToken++;
Packit Service 50c9f2
        if (p->curToken>=p->numTokens)
Packit Service 50c9f2
        {
Packit Service 50c9f2
          break; // end of token stream
Packit Service 50c9f2
        }
Packit Service 50c9f2
        l = p->getCurrentTokenLine();
Packit Service 50c9f2
        clang_disposeString(tokenString);
Packit Service 50c9f2
        tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]);
Packit Service 50c9f2
        ts = clang_getCString(tokenString);
Packit Service 50c9f2
        tl = ts ? strlen(ts) : 0;
Packit Service 50c9f2
        // skip over any spaces in the symbol
Packit Service 50c9f2
        char c;
Packit Service 50c9f2
        while (offset
Packit Service 50c9f2
        {
Packit Service 50c9f2
          offset++;
Packit Service 50c9f2
        }
Packit Service 50c9f2
        if (strncmp(ts,symbol+offset,tl)!=0) // next token matches?
Packit Service 50c9f2
        {
Packit Service 50c9f2
          //printf("no match '%s'<->'%s'\n",ts,symbol+offset);
Packit Service 50c9f2
          break; // no match
Packit Service 50c9f2
        }
Packit Service 50c9f2
        //printf("partial match '%s'<->'%s'\n",ts,symbol+offset);
Packit Service 50c9f2
        offset+=tl;
Packit Service 50c9f2
      }
Packit Service 50c9f2
      if (offset==sl) // symbol matches the token(s)
Packit Service 50c9f2
      {
Packit Service 50c9f2
        CXCursor c = p->cursors[p->curToken];
Packit Service 50c9f2
        CXString usr = clang_getCursorUSR(c);
Packit Service 50c9f2
        //printf("found full match %s usr='%s'\n",symbol,clang_getCString(usr));
Packit Service 50c9f2
        result = clang_getCString(usr);
Packit Service 50c9f2
        clang_disposeString(usr);
Packit Service 50c9f2
        found=TRUE;
Packit Service 50c9f2
      }
Packit Service 50c9f2
      else // reset token cursor to start of the search
Packit Service 50c9f2
      {
Packit Service 50c9f2
        p->curToken = startIndex;
Packit Service 50c9f2
      }
Packit Service 50c9f2
    }
Packit Service 50c9f2
    clang_disposeString(tokenString);
Packit Service 50c9f2
    p->curToken++;
Packit Service 50c9f2
    if (p->curToken<p->numTokens)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      l = p->getCurrentTokenLine();
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  //if (!found)
Packit Service 50c9f2
  //{
Packit Service 50c9f2
  //  printf("Did not find symbol %s at line %d :-(\n",symbol,line);
Packit Service 50c9f2
  //}
Packit Service 50c9f2
  //else
Packit Service 50c9f2
  //{
Packit Service 50c9f2
  //  printf("Found symbol %s usr=%s\n",symbol,result.data());
Packit Service 50c9f2
  //}
Packit Service 50c9f2
  return result;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
static QCString keywordToType(const char *keyword)
Packit Service 50c9f2
{
Packit Service 50c9f2
  static bool init=TRUE;
Packit Service 50c9f2
  static QDict<void> flowKeywords(47);
Packit Service 50c9f2
  static QDict<void> typeKeywords(47);
Packit Service 50c9f2
  if (init)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    flowKeywords.insert("break",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("case",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("catch",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("continue",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("default",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("do",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("else",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("finally",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("for",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("foreach",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("for each",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("goto",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("if",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("return",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("switch",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("throw",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("throws",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("try",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("while",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("@try",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("@catch",(void*)0x8);
Packit Service 50c9f2
    flowKeywords.insert("@finally",(void*)0x8);
Packit Service 50c9f2
Packit Service 50c9f2
    typeKeywords.insert("bool",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("char",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("double",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("float",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("int",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("long",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("object",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("short",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("signed",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("unsigned",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("void",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("wchar_t",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("size_t",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("boolean",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("id",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("SEL",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("string",(void*)0x8);
Packit Service 50c9f2
    typeKeywords.insert("nullptr",(void*)0x8);
Packit Service 50c9f2
    init=FALSE;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  if (flowKeywords[keyword]) return "keywordflow";
Packit Service 50c9f2
  if (typeKeywords[keyword]) return "keywordtype";
Packit Service 50c9f2
  return "keyword";
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line)
Packit Service 50c9f2
{
Packit Service 50c9f2
  Definition *d = fd ? fd->getSourceDefinition(line) : 0;
Packit Service 50c9f2
  if (d && d->isLinkable())
Packit Service 50c9f2
  {
Packit Service 50c9f2
    g_currentDefinition=d;
Packit Service 50c9f2
    g_currentLine=line;
Packit Service 50c9f2
    MemberDef *md = fd->getSourceMember(line);
Packit Service 50c9f2
    if (md && md->isLinkable())  // link to member
Packit Service 50c9f2
    {
Packit Service 50c9f2
      if (g_currentMemberDef!=md) // new member, start search for body
Packit Service 50c9f2
      {
Packit Service 50c9f2
        g_searchForBody=TRUE;
Packit Service 50c9f2
        g_insideBody=FALSE;
Packit Service 50c9f2
        g_bracketCount=0;
Packit Service 50c9f2
      }
Packit Service 50c9f2
      g_currentMemberDef=md;
Packit Service 50c9f2
      ol.writeLineNumber(md->getReference(),
Packit Service 50c9f2
                         md->getOutputFileBase(),
Packit Service 50c9f2
                         md->anchor(),
Packit Service 50c9f2
                         line);
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else // link to compound
Packit Service 50c9f2
    {
Packit Service 50c9f2
      g_currentMemberDef=0;
Packit Service 50c9f2
      ol.writeLineNumber(d->getReference(),
Packit Service 50c9f2
                         d->getOutputFileBase(),
Packit Service 50c9f2
                         d->anchor(),
Packit Service 50c9f2
                         line);
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  else // no link
Packit Service 50c9f2
  {
Packit Service 50c9f2
    ol.writeLineNumber(0,0,0,line);
Packit Service 50c9f2
  }
Packit Service 50c9f2
Packit Service 50c9f2
  // set search page target
Packit Service 50c9f2
  if (Doxygen::searchIndex)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    QCString lineAnchor;
Packit Service 50c9f2
    lineAnchor.sprintf("l%05d",line);
Packit Service 50c9f2
    ol.setCurrentDoc(fd,lineAnchor,TRUE);
Packit Service 50c9f2
  }
Packit Service 50c9f2
Packit Service 50c9f2
  //printf("writeLineNumber(%d) g_searchForBody=%d\n",line,g_searchForBody);
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
static void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text,
Packit Service 50c9f2
                        uint &line,uint &column,const char *fontClass=0)
Packit Service 50c9f2
{
Packit Service 50c9f2
  if (fontClass) ol.startFontClass(fontClass);
Packit Service 50c9f2
  const char *p=text,*sp=p;
Packit Service 50c9f2
  char c;
Packit Service 50c9f2
  bool done=FALSE;
Packit Service 50c9f2
  while (!done)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    sp=p;
Packit Service 50c9f2
    while ((c=*p++) && c!='\n') { column++; }
Packit Service 50c9f2
    if (c=='\n')
Packit Service 50c9f2
    {
Packit Service 50c9f2
      line++;
Packit Service 50c9f2
      int l = (int)(p-sp-1);
Packit Service 50c9f2
      column=l+1;
Packit Service 50c9f2
      char *tmp = (char*)malloc(l+1);
Packit Service 50c9f2
      memcpy(tmp,sp,l);
Packit Service 50c9f2
      tmp[l]='\0';
Packit Service 50c9f2
      ol.codify(tmp);
Packit Service 50c9f2
      free(tmp);
Packit Service 50c9f2
      if (fontClass) ol.endFontClass();
Packit Service 50c9f2
      ol.endCodeLine();
Packit Service 50c9f2
      ol.startCodeLine(TRUE);
Packit Service 50c9f2
      writeLineNumber(ol,fd,line);
Packit Service 50c9f2
      if (fontClass) ol.startFontClass(fontClass);
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else
Packit Service 50c9f2
    {
Packit Service 50c9f2
      ol.codify(sp);
Packit Service 50c9f2
      done=TRUE;
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  if (fontClass) ol.endFontClass();
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
static void writeMultiLineCodeLink(CodeOutputInterface &ol,
Packit Service 50c9f2
                  FileDef *fd,uint &line,uint &column,
Packit Service 50c9f2
                  Definition *d,
Packit Service 50c9f2
                  const char *text)
Packit Service 50c9f2
{
Packit Service 50c9f2
  static bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
Packit Service 50c9f2
  TooltipManager::instance()->addTooltip(d);
Packit Service 50c9f2
  QCString ref  = d->getReference();
Packit Service 50c9f2
  QCString file = d->getOutputFileBase();
Packit Service 50c9f2
  QCString anchor = d->anchor();
Packit Service 50c9f2
  QCString tooltip;
Packit Service 50c9f2
  if (!sourceTooltips) // fall back to simple "title" tooltips
Packit Service 50c9f2
  {
Packit Service 50c9f2
   tooltip = d->briefDescriptionAsTooltip();
Packit Service 50c9f2
  }
Packit Service 50c9f2
  bool done=FALSE;
Packit Service 50c9f2
  char *p=(char *)text;
Packit Service 50c9f2
  while (!done)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    char *sp=p;
Packit Service 50c9f2
    char c;
Packit Service 50c9f2
    while ((c=*p++) && c!='\n') { column++; }
Packit Service 50c9f2
    if (c=='\n')
Packit Service 50c9f2
    {
Packit Service 50c9f2
      line++;
Packit Service 50c9f2
      *(p-1)='\0';
Packit Service 50c9f2
      //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
Packit Service 50c9f2
      ol.writeCodeLink(ref,file,anchor,sp,tooltip);
Packit Service 50c9f2
      ol.endCodeLine();
Packit Service 50c9f2
      ol.startCodeLine(TRUE);
Packit Service 50c9f2
      writeLineNumber(ol,fd,line);
Packit Service 50c9f2
    }
Packit Service 50c9f2
    else
Packit Service 50c9f2
    {
Packit Service 50c9f2
      //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
Packit Service 50c9f2
      ol.writeCodeLink(ref,file,anchor,sp,tooltip);
Packit Service 50c9f2
      done=TRUE;
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::linkInclude(CodeOutputInterface &ol,FileDef *fd,
Packit Service 50c9f2
    uint &line,uint &column,const char *text)
Packit Service 50c9f2
{
Packit Service 50c9f2
  QCString incName = text;
Packit Service 50c9f2
  incName = incName.mid(1,incName.length()-2); // strip ".." or  <..>
Packit Service 50c9f2
  FileDef *ifd=0;
Packit Service 50c9f2
  if (!incName.isEmpty())
Packit Service 50c9f2
  {
Packit Service 50c9f2
    FileName *fn = Doxygen::inputNameDict->find(incName);
Packit Service 50c9f2
    if (fn)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      bool found=false;
Packit Service 50c9f2
      FileNameIterator fni(*fn);
Packit Service 50c9f2
      // for each include name
Packit Service 50c9f2
      for (fni.toFirst();!found && (ifd=fni.current());++fni)
Packit Service 50c9f2
      {
Packit Service 50c9f2
        // see if this source file actually includes the file
Packit Service 50c9f2
        found = fd->isIncluded(ifd->absFilePath());
Packit Service 50c9f2
        //printf("      include file %s found=%d\n",ifd->absFilePath().data(),found);
Packit Service 50c9f2
      }
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  if (ifd)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    ol.writeCodeLink(ifd->getReference(),ifd->getOutputFileBase(),0,text,ifd->briefDescriptionAsTooltip());
Packit Service 50c9f2
  }
Packit Service 50c9f2
  else
Packit Service 50c9f2
  {
Packit Service 50c9f2
    codifyLines(ol,ifd,text,line,column,"preprocessor");
Packit Service 50c9f2
  }
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::linkMacro(CodeOutputInterface &ol,FileDef *fd,
Packit Service 50c9f2
    uint &line,uint &column,const char *text)
Packit Service 50c9f2
{
Packit Service 50c9f2
  MemberName *mn=Doxygen::functionNameSDict->find(text);
Packit Service 50c9f2
  if (mn)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    MemberNameIterator mni(*mn);
Packit Service 50c9f2
    MemberDef *md;
Packit Service 50c9f2
    for (mni.toFirst();(md=mni.current());++mni)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      if (md->isDefine())
Packit Service 50c9f2
      {
Packit Service 50c9f2
        writeMultiLineCodeLink(ol,fd,line,column,md,text);
Packit Service 50c9f2
        return;
Packit Service 50c9f2
      }
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
  codifyLines(ol,fd,text,line,column);
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd,
Packit Service 50c9f2
    uint &line,uint &column,const char *text,int tokenIndex)
Packit Service 50c9f2
{
Packit Service 50c9f2
  CXCursor c = p->cursors[tokenIndex];
Packit Service 50c9f2
  CXCursor r = clang_getCursorReferenced(c);
Packit Service 50c9f2
  if (!clang_equalCursors(r, c))
Packit Service 50c9f2
  {
Packit Service 50c9f2
    c=r; // link to referenced location
Packit Service 50c9f2
  }
Packit Service 50c9f2
  CXCursor t = clang_getSpecializedCursorTemplate(c);
Packit Service 50c9f2
  if (!clang_Cursor_isNull(t) && !clang_equalCursors(t,c))
Packit Service 50c9f2
  {
Packit Service 50c9f2
    c=t; // link to template 
Packit Service 50c9f2
  }
Packit Service 50c9f2
  CXString usr = clang_getCursorUSR(c);
Packit Service 50c9f2
  const char *usrStr = clang_getCString(usr);
Packit Service 50c9f2
Packit Service 50c9f2
  Definition *d = usrStr ? Doxygen::clangUsrMap->find(usrStr) : 0;
Packit Service 50c9f2
  //CXCursorKind kind = clang_getCursorKind(c);
Packit Service 50c9f2
  //if (d==0)
Packit Service 50c9f2
  //{
Packit Service 50c9f2
  //  printf("didn't find definition for '%s' usr='%s' kind=%d\n",
Packit Service 50c9f2
  //      text,usrStr,kind);
Packit Service 50c9f2
  //}
Packit Service 50c9f2
  //else
Packit Service 50c9f2
  //{
Packit Service 50c9f2
  //  printf("found definition for '%s' usr='%s' name='%s'\n",
Packit Service 50c9f2
  //      text,usrStr,d->name().data());
Packit Service 50c9f2
  //}
Packit Service 50c9f2
  if (d && d->isLinkable())
Packit Service 50c9f2
  {
Packit Service 50c9f2
    if (g_insideBody &&
Packit Service 50c9f2
        g_currentMemberDef && d->definitionType()==Definition::TypeMember && 
Packit Service 50c9f2
        (g_currentMemberDef!=d || g_currentLine
Packit Service 50c9f2
    {
Packit Service 50c9f2
      addDocCrossReference(g_currentMemberDef,(MemberDef*)d);
Packit Service 50c9f2
    }
Packit Service 50c9f2
    writeMultiLineCodeLink(ol,fd,line,column,d,text);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  else
Packit Service 50c9f2
  {
Packit Service 50c9f2
    codifyLines(ol,fd,text,line,column);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  clang_disposeString(usr);
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
static void detectFunctionBody(const char *s)
Packit Service 50c9f2
{
Packit Service 50c9f2
  //printf("punct=%s g_searchForBody=%d g_insideBody=%d g_bracketCount=%d\n",
Packit Service 50c9f2
  //  s,g_searchForBody,g_insideBody,g_bracketCount);
Packit Service 50c9f2
Packit Service 50c9f2
  if (g_searchForBody && (qstrcmp(s,":")==0 || qstrcmp(s,"{")==0)) // start of 'body' (: is for constructor)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    g_searchForBody=FALSE;
Packit Service 50c9f2
    g_insideBody=TRUE;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  else if (g_searchForBody && qstrcmp(s,";")==0) // declaration only
Packit Service 50c9f2
  {
Packit Service 50c9f2
    g_searchForBody=FALSE;
Packit Service 50c9f2
    g_insideBody=FALSE;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  if (g_insideBody && qstrcmp(s,"{")==0) // increase scoping level
Packit Service 50c9f2
  {
Packit Service 50c9f2
    g_bracketCount++;
Packit Service 50c9f2
  }
Packit Service 50c9f2
  if (g_insideBody && qstrcmp(s,"}")==0) // decrease scoping level
Packit Service 50c9f2
  {
Packit Service 50c9f2
    g_bracketCount--;
Packit Service 50c9f2
    if (g_bracketCount<=0) // got outside of function body
Packit Service 50c9f2
    {
Packit Service 50c9f2
      g_insideBody=FALSE;
Packit Service 50c9f2
      g_bracketCount=0;
Packit Service 50c9f2
    }
Packit Service 50c9f2
  }
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::writeSources(CodeOutputInterface &ol,FileDef *fd)
Packit Service 50c9f2
{
Packit Service 50c9f2
  TooltipManager::instance()->clearTooltips();
Packit Service 50c9f2
  // (re)set global parser state
Packit Service 50c9f2
  g_currentDefinition=0;
Packit Service 50c9f2
  g_currentMemberDef=0;
Packit Service 50c9f2
  g_currentLine=0;
Packit Service 50c9f2
  g_searchForBody=FALSE;
Packit Service 50c9f2
  g_insideBody=FALSE;
Packit Service 50c9f2
  g_bracketCount=0;
Packit Service 50c9f2
Packit Service 50c9f2
  unsigned int line=1,column=1;
Packit Service 50c9f2
  QCString lineNumber,lineAnchor;
Packit Service 50c9f2
  ol.startCodeLine(TRUE);
Packit Service 50c9f2
  writeLineNumber(ol,fd,line);
Packit Service 50c9f2
  for (unsigned int i=0;i<p->numTokens;i++)
Packit Service 50c9f2
  {
Packit Service 50c9f2
    CXSourceLocation start = clang_getTokenLocation(p->tu, p->tokens[i]);
Packit Service 50c9f2
    unsigned int l, c;
Packit Service 50c9f2
    clang_getSpellingLocation(start, 0, &l, &c, 0);
Packit Service 50c9f2
    if (l > line) column = 1;
Packit Service 50c9f2
    while (line
Packit Service 50c9f2
    { 
Packit Service 50c9f2
      line++; 
Packit Service 50c9f2
      ol.endCodeLine();
Packit Service 50c9f2
      ol.startCodeLine(TRUE);
Packit Service 50c9f2
      writeLineNumber(ol,fd,line);
Packit Service 50c9f2
    } 
Packit Service 50c9f2
    while (column
Packit Service 50c9f2
    CXString tokenString = clang_getTokenSpelling(p->tu, p->tokens[i]);
Packit Service 50c9f2
    char const *s = clang_getCString(tokenString);
Packit Service 50c9f2
    CXCursorKind cursorKind  = clang_getCursorKind(p->cursors[i]);
Packit Service 50c9f2
    CXTokenKind tokenKind = clang_getTokenKind(p->tokens[i]);
Packit Service 50c9f2
    //printf("%d:%d %s cursorKind=%d tokenKind=%d\n",line,column,s,cursorKind,tokenKind);
Packit Service 50c9f2
    switch (tokenKind)
Packit Service 50c9f2
    {
Packit Service 50c9f2
      case CXToken_Keyword: 
Packit Service 50c9f2
        if (strcmp(s,"operator")==0)
Packit Service 50c9f2
        {
Packit Service 50c9f2
          linkIdentifier(ol,fd,line,column,s,i);
Packit Service 50c9f2
        }
Packit Service 50c9f2
        else
Packit Service 50c9f2
        {
Packit Service 50c9f2
          codifyLines(ol,fd,s,line,column,
Packit Service 50c9f2
              cursorKind==CXCursor_PreprocessingDirective ? "preprocessor" :
Packit Service 50c9f2
              keywordToType(s));
Packit Service 50c9f2
        }
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      case CXToken_Literal: 
Packit Service 50c9f2
        if (cursorKind==CXCursor_InclusionDirective)
Packit Service 50c9f2
        {
Packit Service 50c9f2
          linkInclude(ol,fd,line,column,s);
Packit Service 50c9f2
        }
Packit Service 50c9f2
        else if (s[0]=='"' || s[0]=='\'') 
Packit Service 50c9f2
        {
Packit Service 50c9f2
          codifyLines(ol,fd,s,line,column,"stringliteral");
Packit Service 50c9f2
        }
Packit Service 50c9f2
        else 
Packit Service 50c9f2
        {
Packit Service 50c9f2
          codifyLines(ol,fd,s,line,column);
Packit Service 50c9f2
        }
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      case CXToken_Comment: 
Packit Service 50c9f2
        codifyLines(ol,fd,s,line,column,"comment");
Packit Service 50c9f2
        break;
Packit Service 50c9f2
      default:  // CXToken_Punctuation or CXToken_Identifier
Packit Service 50c9f2
        if (tokenKind==CXToken_Punctuation)
Packit Service 50c9f2
        {
Packit Service 50c9f2
          detectFunctionBody(s);
Packit Service 50c9f2
          //printf("punct %s: %d\n",s,cursorKind);
Packit Service 50c9f2
        }
Packit Service 50c9f2
        switch (cursorKind)
Packit Service 50c9f2
        {
Packit Service 50c9f2
          case CXCursor_PreprocessingDirective:
Packit Service 50c9f2
            codifyLines(ol,fd,s,line,column,"preprocessor");
Packit Service 50c9f2
            break;
Packit Service 50c9f2
          case CXCursor_MacroDefinition:
Packit Service 50c9f2
            codifyLines(ol,fd,s,line,column,"preprocessor");
Packit Service 50c9f2
            break;
Packit Service 50c9f2
          case CXCursor_InclusionDirective:
Packit Service 50c9f2
            linkInclude(ol,fd,line,column,s);
Packit Service 50c9f2
            break;
Packit Service 50c9f2
          case CXCursor_MacroExpansion:
Packit Service 50c9f2
            linkMacro(ol,fd,line,column,s);
Packit Service 50c9f2
            break;
Packit Service 50c9f2
          default:
Packit Service 50c9f2
            if (tokenKind==CXToken_Identifier ||
Packit Service 50c9f2
                (tokenKind==CXToken_Punctuation && // for operators
Packit Service 50c9f2
                 (cursorKind==CXCursor_DeclRefExpr ||
Packit Service 50c9f2
                  cursorKind==CXCursor_MemberRefExpr ||
Packit Service 50c9f2
                  cursorKind==CXCursor_CallExpr ||
Packit Service 50c9f2
                  cursorKind==CXCursor_ObjCMessageExpr)
Packit Service 50c9f2
                 )
Packit Service 50c9f2
               )
Packit Service 50c9f2
            {
Packit Service 50c9f2
              linkIdentifier(ol,fd,line,column,s,i);
Packit Service 50c9f2
              if (Doxygen::searchIndex)
Packit Service 50c9f2
              {
Packit Service 50c9f2
                ol.addWord(s,FALSE);
Packit Service 50c9f2
              }
Packit Service 50c9f2
            }
Packit Service 50c9f2
            else
Packit Service 50c9f2
            {
Packit Service 50c9f2
              codifyLines(ol,fd,s,line,column);
Packit Service 50c9f2
            }
Packit Service 50c9f2
            break;
Packit Service 50c9f2
        }
Packit Service 50c9f2
    }
Packit Service 50c9f2
    clang_disposeString(tokenString);
Packit Service 50c9f2
  }
Packit Service 50c9f2
  ol.endCodeLine();
Packit Service 50c9f2
  TooltipManager::instance()->writeTooltips(ol);
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser::ClangParser()
Packit Service 50c9f2
{
Packit Service 50c9f2
  p = new Private;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser::~ClangParser()
Packit Service 50c9f2
{
Packit Service 50c9f2
  delete p;
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
//--------------------------------------------------------------------------
Packit Service 50c9f2
#else // use stubbed functionality in case libclang support is disabled.
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::start(const char *,QStrList &)
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::switchToFile(const char *)
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::finish()
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
QCString ClangParser::lookup(uint,const char *)
Packit Service 50c9f2
{
Packit Service 50c9f2
  return "";
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
void ClangParser::writeSources(CodeOutputInterface &,FileDef *)
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser::ClangParser()
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
ClangParser::~ClangParser()
Packit Service 50c9f2
{
Packit Service 50c9f2
}
Packit Service 50c9f2
Packit Service 50c9f2
Packit Service 50c9f2
#endif
Packit Service 50c9f2
//--------------------------------------------------------------------------
Packit Service 50c9f2