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; }
void ClangIndexer::handleInclude(const CXCursor &cursor, CXCursorKind kind, const Location &location) { assert(kind == CXCursor_InclusionDirective); (void)kind; CXFile includedFile = clang_getIncludedFile(cursor); if (includedFile) { const Location refLoc = createLocation(includedFile, 1, 1); if (!refLoc.isNull()) { { String include = "#include "; const Path path = refLoc.path(); assert(mSource.fileId); mData->dependencies[refLoc.fileId()].insert(mSource.fileId); mData->symbolNames[(include + path)].insert(location); mData->symbolNames[(include + path.fileName())].insert(location); } std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(refLoc); info->kind = cursor.kind; info->definition = false; info->symbolName = "#include " + RTags::eatString(clang_getCursorDisplayName(cursor)); info->symbolLength = info->symbolName.size() + 2; // this fails for things like: // # include <foobar.h> } } }
static CXChildVisitResult parseFunctionMember (CXCursor cursor, CXCursor parent, CXClientData clientData) { auto functionDef = static_cast<FunctionDefinition*>(clientData); auto displayName = CXStringToString(clang_getCursorDisplayName(cursor)); auto kind = clang_getCursorKind(cursor); std::map<std::string, std::string> location; getSourceLocation(cursor, functionDef->getContext(), location); // std::cerr << "function: " << displayName << " kind: " << kind << ", " << hyperloop::toJSON(location) << std::endl; switch (kind) { case CXCursor_ParmDecl: { auto argType = clang_getCursorType(cursor); auto typeValue= CXStringToString(clang_getTypeSpelling(argType)); auto encoding = CXStringToString(clang_getDeclObjCTypeEncoding(cursor)); functionDef->addArgument(displayName, argType, typeValue, encoding); break; } case CXCursor_ObjCClassRef: case CXCursor_TypeRef: case CXCursor_UnexposedAttr: case CXCursor_CompoundStmt: case CXCursor_AsmLabelAttr: case CXCursor_ConstAttr: case CXCursor_PureAttr: { break; } default: { std::cerr << "not handled, function: " << displayName << " kind: " << kind << std::endl; break; } } return CXChildVisit_Continue; }
void IndexerJob::handleInclude(const CXCursor &cursor, CXCursorKind kind, const Location &location) { assert(kind == CXCursor_InclusionDirective); (void)kind; CXFile includedFile = clang_getIncludedFile(cursor); if (includedFile) { const Location refLoc(includedFile, 0); if (!refLoc.isNull()) { { String include = "#include "; const Path path = refLoc.path(); mData->symbolNames[(include + path)].insert(location); mData->symbolNames[(include + path.fileName())].insert(location); } CursorInfo &info = mData->symbols[location]; info.targets.insert(refLoc); info.kind = cursor.kind; info.definition = false; info.symbolName = "#include " + RTags::eatString(clang_getCursorDisplayName(cursor)); info.symbolLength = info.symbolName.size() + 2; // this fails for things like: // # include <foobar.h> } } }
OovString Tokenizer::getClassNameAtLocation(size_t origOffset) { CLangAutoLock lock(mCLangLock, __LINE__, this); CXCursor classCursor = getCursorAtOffset(mTransUnit, mSourceFile, origOffset); std::string className = getDisposedString(clang_getCursorDisplayName(classCursor)); return ModelData::getBaseType(className); }
std::string TranslationUnit::GetEnclosingFunctionAtLocation( const std::string &filename, 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 "Internal error: no translation unit"; } CXCursor cursor = GetCursor( filename, line, column ); if ( !CursorIsValid( cursor ) ) { return "Internal error: cursor not valid"; } CXCursor parent = clang_getCursorSemanticParent( cursor ); std::string parent_str = CXStringToString( clang_getCursorDisplayName( parent ) ); if ( parent_str.empty() ) { return "Unknown semantic parent"; } return parent_str; }
enum CXChildVisitResult visitor(CXCursor cursor, CXCursor parent, CXClientData data) { enum CXCursorKind cKind = clang_getCursorKind(cursor); CXString nameString = clang_getCursorDisplayName(cursor); CXString typeString = clang_getCursorKindSpelling(cKind); printf("Name:%s, Kind:%s\n", clang_getCString(nameString), clang_getCString(typeString)); clang_disposeString(nameString); clang_disposeString(typeString); return CXChildVisit_Continue; }
std::string Cursor::displayname() const { if ( m_displayname.empty() ) { UniqueCXString cx_string(clang_getCursorDisplayName(m_cx_cursor)); if ( !cx_string ) { CLANGXX_THROW_LogicError("Error retrieving the display name for the entity referenced by this cursor."); } m_displayname = clang_getCString(cx_string.get()); } return m_displayname; }
void QAnnotatedTokenSet::dump(std::string &str){ Q_D(QAnnotatedTokenSet); CXString displayName = clang_getCursorDisplayName(d->cursor); str.append("Cursor :"); str.append(clang_getCString(displayName)); str.append("\n Tokens :"); clang_disposeString(displayName); for ( QAnnotatedTokenSet::Iterator it = begin(); it != end(); ++it ){ CXString tokenString = clang_getTokenSpelling(d->translationUnit, (*it)->token().token); CXSourceLocation tokenLocation = clang_getTokenLocation(d->translationUnit, (*it)->token().token); unsigned int column, line; clang_getSpellingLocation(tokenLocation, 0, &line, &column, 0); std::stringstream stream; stream << " (" << line << "," << column << ") \""; str.append(stream.str() + clang_getCString(tokenString) + "\""); clang_disposeString(tokenString); } str.append("\n"); }
static void printCursor(CXCursor cursor) { CXFile file; unsigned int off, line, col; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); CXString fileName = clang_getFileName(file); const char *fileNameCStr = clang_getCString(fileName); if (fileNameCStr) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned int start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); printf("%s:%d:%d (%d, %d-%d) ", fileNameCStr, line, col, off, start, end); } clang_disposeString(fileName); printString("kind", clang_getCursorKindSpelling(clang_getCursorKind(cursor))); printString("display name", clang_getCursorDisplayName(cursor)); printString("usr", clang_getCursorUSR(cursor)); if (clang_isCursorDefinition(cursor)) printf("definition "); printf("\n"); }
String IndexerJob::addNamePermutations(const CXCursor &cursor, const Location &location) { CXCursorKind kind = clang_getCursorKind(cursor); const CXCursorKind originalKind = kind; char buf[1024]; int pos = sizeof(buf) - 1; buf[pos] = '\0'; int cutoff = -1; CXCursor c = cursor; bool hasTemplates = false; do { CXStringScope displayName(clang_getCursorDisplayName(c)); const char *name = displayName.data(); if (!name) break; const int len = strlen(name); if (!len) break; if (kind == CXCursor_ClassTemplate) hasTemplates = true; if (pos != sizeof(buf) - 1 && (pos -= 2) >= 0) { memset(buf + pos, ':', 2); } pos -= len; if (pos < 0) { error("SymbolName too long. Giving up"); return String(); } memcpy(buf + pos, name, len); c = clang_getCursorSemanticParent(c); kind = clang_getCursorKind(c); if (cutoff == -1) { switch (kind) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_StructDecl: break; case CXCursor_Namespace: // namespaces can include all namespaces in their symbolname if (originalKind == CXCursor_Namespace) break; default: cutoff = pos; break; } } } while (RTags::needsQualifiers(kind)); String type; switch (originalKind) { case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: break; default: type = typeName(cursor); break; } if (cutoff == -1) cutoff = pos; String ret; for (int i=0; i<2; ++i) { char *ch = buf + pos; while (true) { const String name(ch, sizeof(buf) - (ch - buf) - 1); mData->symbolNames[name].insert(location); if (!type.isEmpty()) { mData->symbolNames[type + name].insert(location); } ch = strstr(ch + 1, "::"); if (ch) { ch += 2; } else { break; } } if (i == 0) { ret.assign(buf + cutoff, sizeof(buf) - cutoff - 1); if (!type.isEmpty()) ret.prepend(type); } if (!hasTemplates) { break; } else if (i == 0) { char *start = strchr(buf + pos, '<'); assert(start); char *end = strchr(start, '>'); const int templateSize = (end - start) + 1; assert(end); memmove(buf + pos + templateSize, buf + pos, start - (buf + pos)); pos += templateSize; } } return ret; }
Utf8String Cursor::displayName() const { return ClangString(clang_getCursorDisplayName(cxCursor)); }
void IndexerJob::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref, 0); if (!reffedLoc.isValid()) return; CursorInfo &refInfo = mData->symbols[reffedLoc]; if (!refInfo.symbolLength && !handleCursor(ref, refKind, reffedLoc)) return; refInfo.references.insert(location); CursorInfo &info = mData->symbols[location]; info.targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info.kind) && (!info.symbolLength || info.bestTarget(mData->symbols).kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; info.definition = false; info.kind = kind; info.symbolLength = isOperator ? end - start : refInfo.symbolLength; info.symbolName = refInfo.symbolName; info.type = clang_getCursorType(cursor).kind; switch (kind) { case CXCursor_CallExpr: nestedClassConstructorCallUgleHack(parent, info, refKind, reffedLoc); // see rtags/tests/nestedClassConstructorCallUgleHack/ break; default: break; } } Set<Location> &val = mData->references[location]; val.insert(reffedLoc); }
enum CXChildVisitResult visit_program(CXCursor cursor, CXCursor parent, CXClientData data){ json_t* program = (json_t*)data; json_t* js = NULL; enum CXChildVisitResult ret = CXChildVisit_Continue; switch (clang_getCursorKind(cursor)) { case CXCursor_FunctionDecl: case CXCursor_VarDecl: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "display_name", render_string(clang_getCursorDisplayName(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { json_object_set_new(js, "argument_names", json_array()); json_object_set_new(js, "kind", json_string("function")); } else { json_object_set_new(js, "kind", json_string("variable")); } switch (clang_getCursorLinkage(cursor)) { case CXLinkage_Internal: json_object_set_new(js, "linkage", json_string("static")); break; case CXLinkage_UniqueExternal: json_object_set_new(js, "linkage", json_string("anonymous")); break; case CXLinkage_External: break; default: json_object_set_new(js, "linkage", json_string("unknown")); } clang_visitChildren(cursor, visit_object, (CXClientData)js); break; case CXCursor_StructDecl: case CXCursor_UnionDecl: js = json_object(); json_object_set_new(js, "kind", json_string(clang_getCursorKind(cursor) == CXCursor_UnionDecl ? "union" : "struct")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "fields", json_array()); clang_visitChildren(cursor, visit_structure, (CXClientData)js); ret = CXChildVisit_Recurse; break; case CXCursor_EnumDecl: js = json_object(); json_object_set_new(js, "kind", json_string("enum")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "values", json_array()); clang_visitChildren(cursor, visit_enum, (CXClientData)js); break; case CXCursor_TypedefDecl: js = json_object(); json_object_set_new(js, "kind", json_string("typedef")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getTypedefDeclUnderlyingType(cursor))); ret = CXChildVisit_Recurse; break; case CXCursor_FieldDecl: break; case CXCursor_MacroDefinition: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); { CXToken* tokens; unsigned ntokens, i; CXString name = clang_getCursorSpelling(cursor); char value_buf[1024] = ""; json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); clang_tokenize(TU, clang_getCursorExtent(cursor), &tokens, &ntokens); for (i=0; i<ntokens; i++) { CXString str = clang_getTokenSpelling(TU, tokens[i]); CXTokenKind tkind = clang_getTokenKind(tokens[i]); if (i == 0 && !strcmp(clang_getCString(name), clang_getCString(str))) { // macro name } else if (i == ntokens - 1 && tkind == CXToken_Punctuation && !strcmp("#", clang_getCString(str))) { // weird clang terminator thingy } else if (tkind == CXToken_Comment) { // comment } else { if (strlen(value_buf) > 0) { strncat(value_buf, " ", sizeof(value_buf) - strlen(value_buf) - 1); } strncat(value_buf, clang_getCString(str), sizeof(value_buf) - strlen(value_buf) - 1); } clang_disposeString(str); } clang_disposeTokens(TU, tokens, ntokens); if (strlen(value_buf) > 0) { long int intval; double dblval; char* endptr_int; char* endptr_dbl; intval = strtol(value_buf, &endptr_int, 0); dblval = strtod(value_buf, &endptr_dbl); if (endptr_int[0] == 0 || (endptr_int[1] == 0 && strchr("UuLl", endptr_int[0]) != NULL)) { json_object_set_new(js, "value", json_integer(intval)); } else if (endptr_dbl[0] == 0 || (endptr_dbl[1] == 0 && strchr("fF", endptr_dbl[0]) != NULL)) { json_object_set_new(js, "value", json_real(dblval)); } else { json_object_set_new(js, "value", json_string(value_buf)); } } } break; /* case CXCursor_PreprocessingDirective: case CXCursor_MacroExpansion: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); putstring(clang_getCursorSpelling(cursor)); putstring(clang_getCursorDisplayName(cursor)); printf("%d\n", clang_getEnumConstantDeclValue(cursor)); ret = CXChildVisit_Recurse; */ default: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); json_object_set_new(js, "kind", json_string("wtf")); json_object_set_new(js, "wtf", render_string(clang_getCursorKindSpelling(clang_getCursorKind(cursor)))); } if (js) { json_t* str; if (!json_object_get(program, "")) json_object_set_new(program, "", json_array()); str = render_string(clang_getCursorUSR(cursor)); if (strlen(json_string_value(str)) == 0) { json_decref(str); json_array_append_new(json_object_get(program, ""), js); } else { json_object_set_with_key_new(program, render_string(clang_getCursorUSR(cursor)), js); } } return ret; }
String Cursor::GetDisplayName() const { return clang_getCursorDisplayName(cursor_); }
std::string cursor::display_name() { return string(clang_getCursorDisplayName(cur)).str(); }
std::string Generator::stringize(const CXType &type, const std::string &varName, bool makeConstReference) const { std::string result; if (makeConstReference) { switch (type.kind) { case CXType_LValueReference: case CXType_RValueReference: case CXType_Pointer: case CXType_Enum: case CXType_Bool: case CXType_Char_S: case CXType_Char_U: case CXType_Char16: case CXType_Int: case CXType_Long: case CXType_LongLong: case CXType_Float: case CXType_Double: case CXType_LongDouble: makeConstReference = false; break; default: break; } } if (makeConstReference || clang_isConstQualifiedType(type)) result += "const "; switch (type.kind) { case CXType_Void: result += "void"; if (!varName.empty()) result += ' '; break; case CXType_Bool: result += "bool"; if (!varName.empty()) result += ' '; break; case CXType_Int: result += "int"; if (!varName.empty()) result += ' '; break; case CXType_Float: result += "float"; if (!varName.empty()) result += ' '; break; case CXType_Double: result += "double"; if (!varName.empty()) result += ' '; break; case CXType_Pointer: { CXType pointee = clang_getPointeeType(type); result += stringize(pointee); result += " *"; } break; case CXType_LValueReference: { CXType pointee = clang_getPointeeType(type); result += stringize(pointee); } break; case CXType_Record: case CXType_Enum: { result += stringize(clang_getTypeDeclaration(type)); if (!varName.empty()) result += ' '; } break; case CXType_Unexposed: result += stringize(clang_getCursorDisplayName(clang_getTypeDeclaration(type))); if (!varName.empty()) result += ' '; break; case CXType_Overload: result += "<CXType_Overload>"; reportWarning("stringize: CXType_Overload not handled: " + stringize(clang_getCursorDisplayName(clang_getTypeDeclaration(type)))); break; case CXType_Dependent: result += "<CXType_Dependent>"; reportWarning("stringize: CXType_Dependent not handled: " + stringize(clang_getCursorDisplayName(clang_getTypeDeclaration(type)))); break; case CXType_Invalid: result += "<CXType_Invalid>"; reportWarning("stringize: CXType_Invalid not handled: " + stringize(clang_getCursorDisplayName(clang_getTypeDeclaration(type)))); break; default: result += "<other CXTypeKind>"; reportWarning("stringize: such CXTypeKind not handled: " + stringize(clang_getCursorDisplayName(clang_getTypeDeclaration(type)))); break; } if (makeConstReference) { result += "&"; } result += varName; return result; }
enum CXChildVisitResult visitor( CXCursor cursor, CXCursor parent, CXClientData client_data ) { enum CXCursorKind kind = clang_getCursorKind(cursor); #if 0 CXString str = clang_getCursorKindSpelling(kind); printf("%s\n", getCString(str)); disposeString(str); #endif if (kind != CXCursor_FunctionDecl) { return CXChildVisit_Recurse; } CXString str; CXType retType = clang_getCursorResultType(cursor); str = clang_getTypeSpelling(retType); printf("%s\n", clang_getCString(str)); clang_disposeString(str); CXString funcSpelling = clang_getCursorSpelling(cursor); const char* funcSpellingCStr = clang_getCString(funcSpelling); const char* prefix = (const char*) client_data; size_t prefixLen = strlen(prefix); if (strncmp(prefix, funcSpellingCStr, prefixLen) == 0) { funcSpellingCStr += prefixLen; } printf("\t%s(\n", funcSpellingCStr); int nArgs = clang_Cursor_getNumArguments(cursor); argNames.resize(nArgs); char nameBuff[32]; for (int i=0; i<nArgs; ++i) { CXCursor arg = clang_Cursor_getArgument(cursor, i); CXType type = clang_getCursorType(arg); CXString typeSpelling = clang_getTypeSpelling(type); CXString name = clang_getCursorDisplayName(arg); argNames[i] = name; const char* nameStr = getArgNameCString(nameBuff, name, i); printf("\t\t%s %s", clang_getCString(typeSpelling), nameStr); clang_disposeString(typeSpelling); if (i+1 != nArgs) { printf(","); } printf("\n"); } printf("\t)\n"); printf("{\n"); printf("\t"); if (retType.kind != CXType_Void) { printf("return "); } printf("%s(", funcSpelling); for (int i=0; i<nArgs; ++i) { const char* nameStr = getArgNameCString(nameBuff, argNames[i], i); printf("%s", nameStr); if (i+1 != nArgs) { printf(", "); } clang_disposeString(argNames[i]); } printf(");\n"); printf("}\n"); clang_disposeString(funcSpelling); return CXChildVisit_Continue; }
String cursorToString(CXCursor cursor, unsigned flags) { const CXCursorKind kind = clang_getCursorKind(cursor); String ret; ret.reserve(256); ret += eatString(clang_getCursorKindSpelling(kind)); if (clang_isInvalid(kind)) return ret; switch (RTags::cursorType(kind)) { case Reference: ret += " r"; break; case Cursor: ret += " c"; break; case Other: ret += " o"; break; case Include: ret += " i"; break; } const String name = eatString(clang_getCursorDisplayName(cursor)); const String other = eatString(clang_getCursorSpelling(cursor)); if (!name.isEmpty()) ret += " " + name; if (other != name && !other.isEmpty()) ret += " " + other; if (clang_isCursorDefinition(cursor)) ret += " def"; if (flags & IncludeUSR) ret += " " + eatString(clang_getCursorUSR(cursor)); CXFile file; unsigned off, line, col; //presumedLine, presumedCol, instantiationLoc, expansionLoc; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); // clang_getPresumedLocation(location, 0, &presumedLine, &presumedCol); // clang_getInstantiationLocation(location, 0, 0, 0, &instantiationLoc); // clang_getExpansionLocation(location, 0, 0, 0, &expansionLoc); const Str fileName(clang_getFileName(file)); if (fileName.data() && *fileName.data()) { ret += ' '; ret += fileName.data(); ret += ','; ret += String::number(off); if (flags & IncludeRange) { ret += " ("; CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); ret += String::number(start); ret += '-'; ret += String::number(end); ret += ')'; } // if (presumedLine != line || presumedCol != col) // ret += String::snprintf<32>("presumed: %d:%d", presumedLine, presumedCol); // if (instantiationLoc != off) // ret += String::snprintf<32>("instantiation: %d", instantiationLoc); // if (expansionLoc != off) // ret += String::snprintf<32>("expansion: %d", expansionLoc); } return ret; }
String ClangIndexer::addNamePermutations(const CXCursor &cursor, const Location &location) { CXCursorKind kind = clang_getCursorKind(cursor); const CXCursorKind originalKind = kind; char buf[32768]; int pos = sizeof(buf) - 1; buf[pos] = '\0'; int cutoff = -1; CXCursor c = cursor; do { CXStringScope displayName(clang_getCursorDisplayName(c)); const char *name = displayName.data(); if (!name) break; const int len = strlen(name); if (!len) break; if (pos != sizeof(buf) - 1 && (pos -= 2) >= 0) { memset(buf + pos, ':', 2); } pos -= len; if (pos < 0) { error("SymbolName too long. Giving up"); return String(); } memcpy(buf + pos, name, len); c = clang_getCursorSemanticParent(c); kind = clang_getCursorKind(c); if (cutoff == -1) { switch (kind) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_StructDecl: break; case CXCursor_Namespace: // namespaces can include all namespaces in their symbolname if (originalKind == CXCursor_Namespace) break; default: cutoff = pos; break; } } } while (RTags::needsQualifiers(kind)); String type; switch (originalKind) { case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: break; default: type = RTags::typeName(cursor); break; } if (cutoff == -1) cutoff = pos; String ret; int templateStart, templateEnd, colonColonCount; int colonColons[512]; ::tokenize(buf, pos, &templateStart, &templateEnd, &colonColonCount, colonColons); // i == 0 --> with templates, // i == 1 without templates or without EnumConstantDecl part for (int i=0; i<2; ++i) { for (int j=0; j<colonColonCount; ++j) { const char *ch = buf + colonColons[j]; const String name(ch, sizeof(buf) - (ch - buf) - 1); mData->symbolNames[name].insert(location); if (!type.isEmpty() && (originalKind != CXCursor_ParmDecl || !strchr(ch, '('))) { // We only want to add the type to the final declaration for ParmDecls // e.g. // void foo(int)::bar // and // int bar // // not // int void foo(int)::bar // or // void foo(int)::int bar mData->symbolNames[type + name].insert(location); } } if (i == 0) { // create actual symbol name that will go into CursorInfo. This doesn't include namespaces etc if (!type.isEmpty()) { ret = type; ret.append(buf + cutoff, sizeof(buf) - cutoff - 1); } else { ret.assign(buf + cutoff, sizeof(buf) - cutoff - 1); } } if (i == 1 || (templateStart == -1 && originalKind != CXCursor_EnumConstantDecl)) { // nothing more to do break; } if (originalKind == CXCursor_EnumConstantDecl) { // remove CXCursor_EnumDecl // struct A { enum B { C } }; // Will by default generate a A::B::C symbolname. // This code removes the B:: part from it if (colonColonCount > 2) { const char *last = buf + colonColons[colonColonCount - 1]; const char *secondLast = buf + colonColons[colonColonCount - 2]; const int len = (last - secondLast); memmove(buf + pos + len, buf + pos, secondLast - (buf + pos)); pos += len; // ### We could/should just move the colon colon values but this // should be pretty quick and I don't want to write the code to // do it. ::tokenize(buf, pos, &templateStart, &templateEnd, &colonColonCount, colonColons); } } else { // remove templates assert(templateStart != -1); assert(templateEnd != -1); const int templateSize = (templateEnd - templateStart) + 1; memmove(buf + pos + templateSize, buf + pos, (buf + templateStart) - (buf + pos)); pos += templateSize; } } return ret; }
void ClangIndexer::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref); if (!reffedLoc.isValid()) { if (kind == CXCursor_ObjCMessageExpr) { mData->pendingReferenceMap[RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(ref)))].insert(location); // insert it, we'll hook up the target and references later handleCursor(cursor, kind, location); } return; } std::shared_ptr<CursorInfo> &refInfo = mData->symbols[reffedLoc]; if ((!refInfo || !refInfo->symbolLength) && !handleCursor(ref, refKind, reffedLoc)) return; refInfo->references.insert(location); std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info->kind) && (!info->symbolLength || info->bestTarget(mData->symbols)->kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; info->definition = false; info->kind = kind; if (isOperator) { unsigned start, end; clang_getSpellingLocation(rangeStart, 0, 0, 0, &start); clang_getSpellingLocation(rangeEnd, 0, 0, 0, &end); info->symbolLength = end - start; } else { info->symbolLength = refInfo->symbolLength; } info->symbolName = refInfo->symbolName; info->type = clang_getCursorType(cursor).kind; } }