Location TranslationUnit::GetDefinitionLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return Location(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return Location(); CXCursor definition_cursor = clang_getCursorDefinition( cursor ); if ( !CursorIsValid( definition_cursor ) ) return Location(); return Location( clang_getCursorLocation( definition_cursor ) ); }
Location TranslationUnit::GetDefinitionLocationForCursor( CXCursor cursor ) { CXCursor definition_cursor = clang_getCursorDefinition( cursor ); if ( !CursorIsValid( definition_cursor ) ) { return Location(); } return Location( clang_getCursorLocation( definition_cursor ) ); }
Cursor Cursor::get_definition() const { CXCursor cx_cursor(clang_getCursorDefinition(m_cx_cursor)); if ( is_null(cx_cursor) ) { if ( is_null(m_cx_cursor) ) { CLANGXX_THROW_LogicError("Error retrieving a cursor that points to the definition of that entity."); } return Cursor(); } return Cursor(std::move(cx_cursor), m_translation_unit); }
void Tokenizer::getMethodNameAtLocation(size_t origOffset, OovString &className, OovString &methodName) { CLangAutoLock lock(mCLangLock, __LINE__, this); CXCursor startCursor = getCursorAtOffset(mTransUnit, mSourceFile, origOffset); std::string method = getDisposedString(clang_getCursorDisplayName(startCursor)); size_t pos = method.find('('); if(pos != std::string::npos) { method.erase(pos); } methodName = method; // Attempt to go to the definition from the following places: // A header file method declaration or inline definition. // A source file where the method is defined. // A call to a method through a pointer, or directly (self) // Attempt to go directly to the definition, it will work if it is in this // translation unit. CXCursor methodDefCursor = clang_getCursorDefinition(startCursor); CXCursor classCursor = startCursor; // Just default to something. // Method call can return invalid file when the definition is not in this // translation unit. if(clang_getCursorKind(methodDefCursor) != CXCursor_InvalidFile) { // In this translation unit (either header or source) // At this point, the semantic parent of the method definition is // the class. classCursor = clang_getCursorSemanticParent(methodDefCursor); } else { // In a file that isn't in this translation unit if(startCursor.kind == CXCursor_CXXMethod) { classCursor = clang_getCursorSemanticParent(startCursor); } else // Handle a call - The cursor is usually a compound statement? { // The definition was not available, so instead, look for the // declaration and class from through the referenced cursor. CXCursor refCursor = clang_getCursorReferenced(startCursor); classCursor = clang_getCursorSemanticParent(refCursor); } } std::string classCursorStr = getDisposedString(clang_getCursorDisplayName(classCursor)); className = classCursorStr; }
location translation_unit::definition_location_at(uint32_t row, uint32_t col) { CXCursor cursor = get_cursor_at(row, col); CXCursor ref = clang_getCursorDefinition( cursor ); if (clang_Cursor_isNull(ref) || clang_isInvalid(clang_getCursorKind(ref))) return {"", 0, 0}; CXSourceLocation loc = clang_getCursorLocation(ref); CXFile file; uint32_t nrow, ncol, offset = 0; clang_getExpansionLocation( loc, &file, &nrow, &ncol, &offset ); return { cx2std(clang_getFileName(file)), nrow, ncol }; }
bool ClangWorkerThread::DoGotoDefinition(CXTranslationUnit& TU, ClangThreadRequest* request, ClangThreadReply* reply) { // Test to see if we are pointing a function CXCursor cur; if(ClangUtils::GetCursorAt(TU, request->GetFileName(), request->GetLine(), request->GetColumn(), cur)) { if(request->GetContext() == CTX_GotoImpl && !clang_isCursorDefinition(cur)) { cur = clang_getCursorDefinition(cur); } ClangUtils::GetCursorLocation(cur, reply->filename, reply->line, reply->col); return true; } return false; }
void Html_File::write_token(FILE* f, CXFile file, CXToken tok, const char* str, unsigned line, unsigned column) { static bool preprocessor = false; static bool include = false; CXSourceLocation tloc = clang_getTokenLocation(tu_file_->tu(), tok); CXCursor c = clang_getCursor(tu_file_->tu(), tloc); if (cur_line_ <= line) cur_column_ = 1; for (; cur_line_ <= line; ++cur_line_) fprintf (f, "\n<a name=\"l%05i\"></a>%05i", cur_line_, cur_line_); for (; cur_column_ <= column; ++cur_column_) fprintf (f , " "); switch (clang_getTokenKind(tok)) { case (CXToken_Punctuation): if (str[0] == '#') preprocessor = true; fprintf(f, "%s", str); break; case (CXToken_Keyword): fprintf(f, "<span class=\"keyword\">%s</span>", str); break; case (CXToken_Comment): fprintf(f, "<span class=\"comment\">%s</span>", str); break; case (CXToken_Literal): { //include = false; // disable include links for now if (include) { include = false; // found an include file std::string t; const char* p = str; while (*p) { if (*p != '"') t += *p; ++p; } // first, use this file's path, then all the include paths bool found_include = false; char path[PATH_MAX]; std::string includefile = realpath(dirname(tu_file_->source_filename()), path); includefile += "/" + t; struct stat st; if (stat(includefile.c_str(), &st) == 0) { found_include = true; } else { for (std::vector<std::string>::const_iterator i = includes_.begin(), e = includes_.end(); i != e; ++i) { includefile = realpath((*i).c_str(), path); includefile += "/" + t; if (stat(includefile.c_str(), &st) == 0) { found_include = true; break; } } } if (found_include) { if (files_.find(includefile) != files_.end()) { t = make_filename(includefile, html_dir_, prefix_, ".html", false); fprintf(f, "<a class=\"code\" href=\"%s\" title="">%s</a>", t.c_str(), str); break; } std::map<std::string, Definition>::iterator i = defmap_.find(includefile); if (i != defmap_.end()) { t = i->second.file.c_str(); fprintf(f, "<a class=\"code\" href=\"%s\" title="">%s</a>", t.c_str(), str); break; } } } // not an include or include not found std::string s = fix(str); fprintf(f, "%s", s.c_str() ); break; } case (CXToken_Identifier): { if (preprocessor) { preprocessor = false; if (strcmp(str, "include") == 0) include = true; fprintf(f, "<span class=\"code\">%s</span>", str); break; } if (clang_isUnexposed(c.kind)) { fprintf(f, "<span class=\"code\">%s</span>", str); fprintf(f, "<!-- origin line: %i : %s : kind = %i -->", __LINE__, str, c.kind); break; } // Calling clang_getCursorDefinition() does not work properly // for template classes, i.e., it will find the method // declaration, not the definition, if they differ. However, // once you have the declaration's location, you can use it // get that cursor, and find the definition that way. CXSourceLocation decloc = clang_getCursorLocation(clang_getCursorDefinition(c)); CXCursor cref = clang_getCursorDefinition(clang_getCursor(tu_file_->tu(), decloc)); if (clang_isUnexposed(cref.kind)) { fprintf(f, "<span class=\"code\">%s</span>", str); fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); break; } std::string rfile; std::string html_dir; unsigned refl = line; bool found = false; if (!clang_Cursor_isNull(cref) && cref.kind != CXCursor_Namespace) { CXSourceLocation refloc = clang_getCursorLocation(cref); if (!clang_equalLocations(tloc, refloc)) { CXFile cxfile; unsigned col; unsigned off; clang_getExpansionLocation(refloc, &cxfile, &refl, &col, &off); if (cxfile == file) { found = true; fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); } else { CXString cxfn = clang_getFileName(cxfile); const char* fn = clang_getCString(cxfn); if (fn) { if (files_.find(fn) != files_.end()) { rfile = fn; found = true; fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); } } clang_disposeString(cxfn); } } } else if (!clang_isDeclaration(c.kind) && c.kind != CXCursor_Namespace) { CXCursor ref = clang_getCursorReferenced(c); if (ref.kind != CXCursor_Namespace) { std::string fsn = munge_fullyscopedname(fullyScopedName(ref)); if (fsn.empty()) { fprintf(f, "<!-- origin line: %i : (fsn empty) %s : kind = %i -->", __LINE__, str, c.kind); } else { std::map<std::string, Definition>::iterator r = defmap_.find(fsn); if (r != defmap_.end()) { found = true; fprintf(f, "<!-- origin line: %i : %s : kind = %i -->", __LINE__, fsn.c_str(), c.kind); rfile = r->second.file.c_str(); html_dir = r->second.html_path.c_str(); refl = r->second.line; } } } } // since we are linking to lines, no need to link to same line if (found && (!rfile.empty() || refl != line)) { if (!rfile.empty()) rfile = make_filename(rfile, html_dir, prefix_, ".html", !html_dir.empty()); fprintf(f, "<a class=\"code\" href=\"%s#l%05i\" title="">%s</a>", rfile.c_str(), refl , str); break; } fprintf(f, "<span class=\"code\">%s</span>", str); break; } } cur_column_ += strlen(str); }
cursor cursor::getCursorDefinition() { return { clang_getCursorDefinition(cur) }; }
// Desired functions: // Go to definition of variable/function // Go to declaration of function/class bool Tokenizer::findToken(eFindTokenTypes ft, size_t origOffset, std::string &fn, size_t &line) { CLangAutoLock lock(mCLangLock, __LINE__, this); CXCursor startCursor = getCursorAtOffset(mTransUnit, mSourceFile, origOffset); DUMP_PARSE("find:start cursor", startCursor); // Instantiating type - <class> <type> - CXCursor_TypeRef // Method declaration - <class> { <method>(); }; CXCursor_NoDeclFound // Method definition - <class>::<method>(){} - CXCursor_CXXMethod // Class/method usage - <class>.<method>() // Instance usage - method(){ int v = typename[4]; } - CXCursor_DeclStmt // clang_getCursorSemanticParent returns method // clang_getCursorDefinition returns invalid if(startCursor.kind == CXCursor_InclusionDirective) { CXFile file = clang_getIncludedFile(startCursor); if(file) { fn = getDisposedString(clang_getFileName(file)); line = 1; } else { /// @todo - need to get the full path. // CXStringDisposer cfn = clang_getCursorSpelling(cursor); // fn = cfn; line = 1; } } else { CXCursor cursor = startCursor; switch(ft) { case FT_FindDecl: cursor = clang_getCursorReferenced(startCursor); DUMP_PARSE("find:decl", cursor); break; case FT_FindDef: // If instantiating a type (CXCursor_TypeRef), this goes to the type declaration. cursor = clang_getCursorDefinition(startCursor); // Method call can return invalid file when the definition is not in this // translation unit. if(clang_getCursorKind(cursor) == CXCursor_InvalidFile) { DUMP_PARSE("find:def-invalid", cursor); cursor = clang_getCursorReferenced(startCursor); } DUMP_PARSE("find:def", cursor); // cursor = clang_getCursor(mTransUnit, clang_getCursorLocation(cursor)); // cursor = clang_getCursorDefinition(cursor); break; // cursor = clang_getCursorReferenced(cursor); // cursor = clang_getCanonicalCursor(cursor); // cursor = clang_getCursorSemanticParent(cursor); // cursor = clang_getCursorLexicalParent(cursor); } if(!clang_Cursor_isNull(cursor)) { CXSourceLocation loc = clang_getCursorLocation(cursor); CXFile file; unsigned int uline; clang_getFileLocation(loc, &file, &uline, nullptr, nullptr); if(file) { line = uline; fn = getDisposedString(clang_getFileName(file)); } } } return(fn.size() > 0); }
Cursor Cursor::definition() const { return clang_getCursorDefinition(cxCursor); }