X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/e5da08fbfa01a4d812d0f88abbb98faa9a410e03..fe555c380f0388cf711e219f84dd8b49fefb2cbb:/Analyze.cpp diff --git a/Analyze.cpp b/Analyze.cpp index ffc7c09..5bf4914 100644 --- a/Analyze.cpp +++ b/Analyze.cpp @@ -1,3 +1,25 @@ +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) +*/ + +/* GNU Affero General Public License, Version 3 {{{ */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ +/* }}} */ + +#include #include #include #include @@ -6,6 +28,30 @@ #include +#include "Bridge.hpp" +#include "Functor.hpp" +#include "Replace.hpp" +#include "Syntax.hpp" + +static CXChildVisitResult CYVisit(CXCursor cursor, CXCursor parent, CXClientData arg) { + (*reinterpret_cast *>(arg))(cursor); + return CXChildVisit_Continue; +} + +static unsigned CYForChild(CXCursor cursor, const Functor &visitor) { + return clang_visitChildren(cursor, &CYVisit, const_cast(static_cast(&visitor))); +} + +static bool CYOneChild(CXCursor cursor, const Functor &visitor) { + bool visited(false); + CYForChild(cursor, fun([&](CXCursor child) { + _assert(!visited); + visited = true; + visitor(child); + })); + return visited; +} + struct CYCXString { CXString value_; @@ -14,6 +60,26 @@ struct CYCXString { { } + CYCXString(CXCursor cursor) : + value_(clang_getCursorSpelling(cursor)) + { + } + + CYCXString(CXCursorKind kind) : + value_(clang_getCursorKindSpelling(kind)) + { + } + + CYCXString(CXFile file) : + value_(clang_getFileName(file)) + { + } + + CYCXString(CXTranslationUnit unit, CXToken token) : + value_(clang_getTokenSpelling(unit, token)) + { + } + ~CYCXString() { clang_disposeString(value_); } @@ -21,39 +87,54 @@ struct CYCXString { operator const char *() const { return clang_getCString(value_); } -}; -struct CYFieldBaton { - std::ostringstream types; - std::ostringstream names; + const char *Pool(CYPool &pool) const { + return pool.strdup(*this); + } + + bool operator ==(const char *rhs) const { + const char *lhs(*this); + return lhs == rhs || strcmp(lhs, rhs) == 0; + } }; -static CXChildVisitResult CYFieldVisit(CXCursor cursor, CXCursor parent, CXClientData arg) { - CYFieldBaton &baton(*static_cast(arg)); +template +struct CYCXPosition { + CXFile file_; + unsigned line_; + unsigned column_; + unsigned offset_; - if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) { - CXType type(clang_getCursorType(cursor)); - baton.types << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << "),"; - baton.names << "'" << CYCXString(clang_getCursorSpelling(cursor)) << "',"; + CYCXPosition(CXSourceLocation location) { + clang_get_Location(location, &file_, &line_, &column_, &offset_); } - return CXChildVisit_Continue; -} + CYCXPosition(CXTranslationUnit unit, CXToken token) : + CYCXPosition(clang_getTokenLocation(unit, token)) + { + } -struct CYAttributeBaton { - std::string label; + CXSourceLocation Get(CXTranslationUnit unit) const { + return clang_getLocation(unit, file_, line_, column_); + } }; -static CXChildVisitResult CYAttributeVisit(CXCursor cursor, CXCursor parent, CXClientData arg) { - CYAttributeBaton &baton(*static_cast(arg)); +template +std::ostream &operator <<(std::ostream &out, const CYCXPosition &position) { + if (position.file_ != NULL) + out << "[" << CYCXString(position.file_) << "]:"; + out << position.line_ << ":" << position.column_ << "@" << position.offset_; + return out; +} - if (clang_getCursorKind(cursor) == CXCursor_AsmLabelAttr) - baton.label = CYCXString(clang_getCursorSpelling(cursor)); +struct CYKey { + unsigned priority_ = 0; - return CXChildVisit_Continue; -} + std::string code_; + unsigned flags_; +}; -typedef std::map CYKeyMap; +typedef std::map CYKeyMap; struct CYChildBaton { CXTranslationUnit unit; @@ -67,112 +148,548 @@ struct CYChildBaton { }; struct CYTokens { - CXTranslationUnit unit; - CXToken *tokens; - unsigned count; + private: + CXTranslationUnit unit_; + CXToken *tokens_; + unsigned count_; + unsigned valid_; + + public: + CYTokens(CXTranslationUnit unit, CXSourceRange range) : + unit_(unit) + { + clang_tokenize(unit_, range, &tokens_, &count_); + + + // libclang's tokenizer is horribly broken and returns "extra" tokens. + // this code goes back through the tokens and filters for good ones :/ + + CYCXPosition<> end(clang_getRangeEnd(range)); + CYCXString file(end.file_); + + for (valid_ = 0; valid_ != count_; ++valid_) { + CYCXPosition<> position(unit, tokens_[valid_]); + _assert(CYCXString(position.file_) == file); + if (position.offset_ >= end.offset_) + break; + } + } CYTokens(CXTranslationUnit unit, CXCursor cursor) : - unit(unit) + CYTokens(unit, clang_getCursorExtent(cursor)) { - CXSourceRange range(clang_getCursorExtent(cursor)); - clang_tokenize(unit, range, &tokens, &count); } ~CYTokens() { - clang_disposeTokens(unit, tokens, count); + clang_disposeTokens(unit_, tokens_, count_); } operator CXToken *() const { - return tokens; + return tokens_; + } + + size_t size() const { + return valid_; } }; +static CYUTF8String CYCXPoolUTF8Range(CYPool &pool, CXSourceRange range) { + CYCXPosition<> start(clang_getRangeStart(range)); + CYCXPosition<> end(clang_getRangeEnd(range)); + CYCXString file(start.file_); + _assert(file == CYCXString(end.file_)); + + CYPool temp; + size_t size; + char *data(static_cast(CYPoolFile(temp, file, &size))); + _assert(start.offset_ <= size && end.offset_ <= size && start.offset_ <= end.offset_); + + CYUTF8String code; + code.size = end.offset_ - start.offset_; + code.data = pool.strndup(data + start.offset_, code.size); + return code; +} + +static CYExpression *CYTranslateExpression(CXTranslationUnit unit, CXCursor cursor) { + switch (CXCursorKind kind = clang_getCursorKind(cursor)) { + case CXCursor_CallExpr: { + CYExpression *function(NULL); + CYList arguments; + CYForChild(cursor, fun([&](CXCursor child) { + CYExpression *expression(CYTranslateExpression(unit, child)); + if (function == NULL) + function = expression; + else + arguments->*$C_(expression); + })); + return $C(function, arguments); + } break; + + case CXCursor_DeclRefExpr: { + return $V(CYCXString(cursor).Pool($pool)); + } break; + + case CXCursor_IntegerLiteral: { + // libclang doesn't provide any reasonable way to do this + // note: clang_tokenize doesn't work if this is a macro + // the token range starts inside the macro but ends after it + // the tokenizer freaks out and either fails with 0 tokens + // or returns some massive number of tokens ending here :/ + + CYUTF8String token(CYCXPoolUTF8Range($pool, clang_getCursorExtent(cursor))); + double value(CYCastDouble(token)); + if (std::isnan(value)) + return $V(token.data); + return $ CYNumber(value); + } break; + + case CXCursor_CStyleCastExpr: + // XXX: most of the time, this is a "NoOp" integer cast; but we should check it + + case CXCursor_UnexposedExpr: + // there is a very high probability that this is actually an "ImplicitCastExpr" + // "Douglas Gregor" err'd on the incorrect side of this one + // http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20110926/046998.html + + case CXCursor_ParenExpr: { + CYExpression *pass(NULL); + CYOneChild(cursor, fun([&](CXCursor child) { + pass = CYTranslateExpression(unit, child); + })); + return pass; + } break; + + default: + //std::cerr << "E:" << CYCXString(kind) << std::endl; + _assert(false); + } +} + +static CYStatement *CYTranslateStatement(CXTranslationUnit unit, CXCursor cursor) { + switch (CXCursorKind kind = clang_getCursorKind(cursor)) { + case CXCursor_ReturnStmt: { + CYExpression *value(NULL); + CYOneChild(cursor, fun([&](CXCursor child) { + value = CYTranslateExpression(unit, child); + })); + return $ CYReturn(value); + } break; + + default: + //std::cerr << "S:" << CYCXString(kind) << std::endl; + _assert(false); + } +} + +static CYStatement *CYTranslateBlock(CXTranslationUnit unit, CXCursor cursor) { + CYList statements; + CYForChild(cursor, fun([&](CXCursor child) { + statements->*CYTranslateStatement(unit, child); + })); + return $ CYBlock(statements); +} + +static CYType *CYDecodeType(CXType type); +static void CYParseType(CXType type, CYType *typed); + +static void CYParseEnumeration(CXCursor cursor, CYType *typed) { + CYList constants; + + CYForChild(cursor, fun([&](CXCursor child) { + if (clang_getCursorKind(child) == CXCursor_EnumConstantDecl) + constants->*$ CYEnumConstant($I($pool.strdup(CYCXString(child))), $D(clang_getEnumConstantDeclValue(child))); + })); + + CYType *integer(CYDecodeType(clang_getEnumDeclIntegerType(cursor))); + typed->specifier_ = $ CYTypeEnum(NULL, integer->specifier_, constants); +} + +static void CYParseStructure(CXCursor cursor, CYType *typed) { + CYList fields; + CYForChild(cursor, fun([&](CXCursor child) { + if (clang_getCursorKind(child) == CXCursor_FieldDecl) + fields->*$ CYTypeStructField(CYDecodeType(clang_getCursorType(child)), $I(CYCXString(child).Pool($pool))); + })); + + typed->specifier_ = $ CYTypeStruct(NULL, $ CYStructTail(fields)); +} + +static void CYParseCursor(CXType type, CXCursor cursor, CYType *typed) { + CYCXString spelling(cursor); + + switch (CXCursorKind kind = clang_getCursorKind(cursor)) { + case CXCursor_EnumDecl: + if (spelling[0] != '\0') + typed->specifier_ = $ CYTypeReference(CYTypeReferenceEnum, $I(spelling.Pool($pool))); + else + CYParseEnumeration(cursor, typed); + break; + + case CXCursor_StructDecl: { + if (spelling[0] != '\0') + typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I(spelling.Pool($pool))); + else + CYParseStructure(cursor, typed); + } break; + + case CXCursor_UnionDecl: { + _assert(false); + } break; + + default: + std::cerr << "C:" << CYCXString(kind) << std::endl; + _assert(false); + break; + } +} + +static CYTypedParameter *CYParseSignature(CXType type, CYType *typed) { + CYParseType(clang_getResultType(type), typed); + CYList parameters; + for (int i(0), e(clang_getNumArgTypes(type)); i != e; ++i) + parameters->*$ CYTypedParameter(CYDecodeType(clang_getArgType(type, i)), NULL); + return parameters; +} + +static void CYParseFunction(CXType type, CYType *typed) { + typed = typed->Modify($ CYTypeFunctionWith(clang_isFunctionTypeVariadic(type), CYParseSignature(type, typed))); +} + +static void CYParseType(CXType type, CYType *typed) { + switch (CXTypeKind kind = type.kind) { + case CXType_Unexposed: { + CXType result(clang_getResultType(type)); + if (result.kind == CXType_Invalid) + CYParseCursor(type, clang_getTypeDeclaration(type), typed); + else + // clang marks function pointers as Unexposed but still supports them + CYParseFunction(type, typed); + } break; + + case CXType_Bool: typed->specifier_ = $ CYTypeVariable("bool"); break; + case CXType_WChar: typed->specifier_ = $ CYTypeVariable("wchar_t"); break; + case CXType_Float: typed->specifier_ = $ CYTypeFloating(0); break; + case CXType_Double: typed->specifier_ = $ CYTypeFloating(1); break; + case CXType_LongDouble: typed->specifier_ = $ CYTypeFloating(2); break; + + case CXType_Char_U: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break; + case CXType_Char_S: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break; + case CXType_SChar: typed->specifier_ = $ CYTypeCharacter(CYTypeSigned); break; + case CXType_UChar: typed->specifier_ = $ CYTypeCharacter(CYTypeUnsigned); break; + + case CXType_Short: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 0); break; + case CXType_UShort: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 0); break; + + case CXType_Int: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 1); break; + case CXType_UInt: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 1); break; + + case CXType_Long: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 2); break; + case CXType_ULong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 2); break; + + case CXType_LongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 3); break; + case CXType_ULongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 3); break; + + case CXType_Int128: typed->specifier_ = $ CYTypeInt128(CYTypeSigned); break; + case CXType_UInt128: typed->specifier_ = $ CYTypeInt128(CYTypeUnsigned); break; + + case CXType_BlockPointer: { + CXType pointee(clang_getPointeeType(type)); + _assert(!clang_isFunctionTypeVariadic(pointee)); + typed = typed->Modify($ CYTypeBlockWith(CYParseSignature(pointee, typed))); + } break; + + case CXType_ConstantArray: + CYParseType(clang_getArrayElementType(type), typed); + typed = typed->Modify($ CYTypeArrayOf($D(clang_getArraySize(type)))); + break; + + case CXType_Enum: + typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type)))); + break; + + case CXType_FunctionProto: + CYParseFunction(type, typed); + break; + + case CXType_IncompleteArray: + // XXX: I probably should not decay to Pointer + CYParseType(clang_getArrayElementType(type), typed); + typed = typed->Modify($ CYTypePointerTo()); + break; + + case CXType_ObjCClass: + typed->specifier_ = $ CYTypeVariable("Class"); + break; + + case CXType_ObjCId: + typed->specifier_ = $ CYTypeVariable("id"); + break; + + case CXType_ObjCInterface: + typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type)))); + break; + + case CXType_ObjCObjectPointer: { + CXType pointee(clang_getPointeeType(type)); + if (pointee.kind != CXType_Unexposed) { + CYParseType(pointee, typed); + typed = typed->Modify($ CYTypePointerTo()); + } else + // Clang seems to have internal typedefs for id and Class that are awkward + _assert(false); + } break; + + case CXType_ObjCSel: + typed->specifier_ = $ CYTypeVariable("SEL"); + break; + + case CXType_Pointer: + CYParseType(clang_getPointeeType(type), typed); + typed = typed->Modify($ CYTypePointerTo()); + break; + + case CXType_Record: + typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I($pool.strdup(CYCXString(clang_getTypeSpelling(type))))); + break; + + case CXType_Typedef: + // use the declaration in order to isolate the name of the typedef itself + typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeDeclaration(type)))); + break; + + case CXType_Vector: + _assert(false); + break; + + case CXType_Void: + typed->specifier_ = $ CYTypeVoid(); + break; + + default: + std::cerr << "T:" << CYCXString(clang_getTypeKindSpelling(kind)) << std::endl; + std::cerr << "_: " << CYCXString(clang_getTypeSpelling(type)) << std::endl; + _assert(false); + } + + if (clang_isConstQualifiedType(type)) + typed = typed->Modify($ CYTypeConstant()); +} + +static CYType *CYDecodeType(CXType type) { + CYType *typed($ CYType(NULL)); + CYParseType(type, typed); + return typed; +} + static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClientData arg) { CYChildBaton &baton(*static_cast(arg)); CXTranslationUnit &unit(baton.unit); - CYCXString spelling(clang_getCursorSpelling(cursor)); + CXChildVisitResult result(CXChildVisit_Continue); + CYCXString spelling(cursor); std::string name(spelling); std::ostringstream value; + unsigned priority(2); + unsigned flags(CYBridgeHold); /*CXSourceLocation location(clang_getCursorLocation(cursor)); + CYCXPosition<> position(location); + std::cerr << spelling << " " << position << std::endl;*/ - CXFile file; - unsigned line; - unsigned column; - unsigned offset; - clang_getSpellingLocation(location, &file, &line, &column, &offset); - - if (file != NULL) { - CYCXString path(clang_getFileName(file)); - std::cout << spelling << " " << path << ":" << line << std::endl; - }*/ - - switch (clang_getCursorKind(cursor)) { + try { switch (CXCursorKind kind = clang_getCursorKind(cursor)) { case CXCursor_EnumConstantDecl: { value << clang_getEnumConstantDeclValue(cursor); } break; - case CXCursor_MacroDefinition: { - CYTokens tokens(unit, cursor); - if (tokens.count <= 2) + case CXCursor_EnumDecl: { + if (spelling[0] == '\0') goto skip; + // XXX: this was blindly copied from StructDecl + if (!clang_isCursorDefinition(cursor)) + priority = 1; + + CYLocalPool pool; + + CYType typed; + CYParseEnumeration(cursor, &typed); + + CYOptions options; + CYOutput out(*value.rdbuf(), options); + CYTypeExpression(&typed).Output(out, CYNoBFC); + + value << ".withName(\"" << name << "\")"; + name = "$cye" + name; + flags = CYBridgeType; - CXCursor cursors[tokens.count]; - clang_annotateTokens(unit, tokens, tokens.count, cursors); + // the enum constants are implemented separately *also* + // XXX: maybe move output logic to function we can call + result = CXChildVisit_Recurse; + } break; - for (unsigned i(1); i != tokens.count - 1; ++i) { - CYCXString token(clang_getTokenSpelling(unit, tokens[i])); - if (i != 1) - value << " "; - else if (strcmp(token, "(") == 0) - goto skip; - value << token; + case CXCursor_MacroDefinition: { + CXSourceRange range(clang_getCursorExtent(cursor)); + CYTokens tokens(unit, range); + _assert(tokens.size() != 0); + + CXCursor cursors[tokens.size()]; + clang_annotateTokens(unit, tokens, tokens.size(), cursors); + + CYLocalPool local; + CYList parameters; + unsigned offset(1); + + if (tokens.size() != 1) { + CYCXPosition<> start(clang_getRangeStart(range)); + CYCXString first(unit, tokens[offset]); + if (first == "(") { + CYCXPosition<> paren(unit, tokens[offset]); + if (start.offset_ + strlen(spelling) == paren.offset_) { + for (;;) { + _assert(++offset != tokens.size()); + CYCXString token(unit, tokens[offset]); + parameters->*$P($B($I(token.Pool($pool)))); + _assert(++offset != tokens.size()); + CYCXString comma(unit, tokens[offset]); + if (comma == ")") + break; + _assert(comma == ","); + } + ++offset; + } + } + } + + std::ostringstream body; + for (unsigned i(offset); i != tokens.size(); ++i) { + CYCXString token(unit, tokens[i]); + if (i != offset) + body << " "; + body << token; + } + + if (!parameters) + value << body.str(); + else { + CYOptions options; + CYOutput out(*value.rdbuf(), options); + out << '(' << "function" << '('; + out << parameters; + out << ')' << '{'; + out << "return" << ' '; + value << body.str(); + out << ';' << '}' << ')'; } } break; case CXCursor_StructDecl: { - if (!clang_isCursorDefinition(cursor)) - goto skip; if (spelling[0] == '\0') goto skip; + if (!clang_isCursorDefinition(cursor)) + priority = 1; - CYFieldBaton baton; - clang_visitChildren(cursor, &CYFieldVisit, &baton); + CYLocalPool pool; - name += "$cy"; - value << "new Type([" << baton.types.str() << "],[" << baton.names.str() << "])"; + CYType typed; + CYParseStructure(cursor, &typed); + + CYOptions options; + CYOutput out(*value.rdbuf(), options); + CYTypeExpression(&typed).Output(out, CYNoBFC); + + value << ".withName(\"" << name << "\")"; + name = "$cys" + name; + flags = CYBridgeType; } break; case CXCursor_TypedefDecl: { - CXType type(clang_getTypedefDeclUnderlyingType(cursor)); - value << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << ")"; + CYLocalPool local; + + CYType *typed(CYDecodeType(clang_getTypedefDeclUnderlyingType(cursor))); + if (typed->specifier_ == NULL) + value << "(typedef " << CYCXString(clang_getTypeSpelling(clang_getTypedefDeclUnderlyingType(cursor))) << ")"; + else { + CYOptions options; + CYOutput out(*value.rdbuf(), options); + CYTypeExpression(typed).Output(out, CYNoBFC); + } } break; case CXCursor_FunctionDecl: case CXCursor_VarDecl: { - CYAttributeBaton baton; - clang_visitChildren(cursor, &CYAttributeVisit, &baton); - - if (baton.label.empty()) { - baton.label = spelling; - baton.label = '_' + baton.label; - } else if (baton.label[0] != '_') + std::string label; + + CYList parameters; + CYStatement *code(NULL); + + CYLocalPool local; + + CYForChild(cursor, fun([&](CXCursor child) { + switch (CXCursorKind kind = clang_getCursorKind(child)) { + case CXCursor_AsmLabelAttr: + label = CYCXString(child); + break; + + case CXCursor_CompoundStmt: + code = CYTranslateBlock(unit, child); + break; + + case CXCursor_ParmDecl: + parameters->*$P($B($I(CYCXString(child).Pool($pool)))); + break; + + case CXCursor_IntegerLiteral: + case CXCursor_ObjCClassRef: + case CXCursor_TypeRef: + case CXCursor_UnexposedAttr: + break; + + default: + //std::cerr << "A:" << CYCXString(child) << std::endl; + break; + } + })); + + if (label.empty()) { + label = spelling; + label = '_' + label; + } else if (label[0] != '_') goto skip; - CXType type(clang_getCursorType(cursor)); - value << "*(typedef " << CYCXString(clang_getTypeSpelling(type)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << baton.label.substr(1) << "'))"; + if (code == NULL) { + value << "*"; + CXType type(clang_getCursorType(cursor)); + CYType *typed(CYDecodeType(type)); + CYOptions options; + CYOutput out(*value.rdbuf(), options); + CYTypeExpression(typed).Output(out, CYNoBFC); + value << ".pointerTo()(dlsym(RTLD_DEFAULT,'" << label.substr(1) << "'))"; + } else { + CYOptions options; + CYOutput out(*value.rdbuf(), options); + CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters, code)); + function->Output(out, CYNoBFC); + //std::cerr << value.str() << std::endl; + } } break; - default: { - return CXChildVisit_Recurse; - } break; + default: + result = CXChildVisit_Recurse; + goto skip; + break; + } { + CYKey &key(baton.keys[name]); + if (key.priority_ <= priority) { + key.priority_ = priority; + key.code_ = value.str(); + key.flags_ = flags; + } + } } catch (const CYException &error) { + CYPool pool; + //std::cerr << error.PoolCString(pool) << std::endl; } - baton.keys[name] = value.str(); - skip: - return CXChildVisit_Continue; + return result; } int main(int argc, const char *argv[]) { @@ -185,7 +702,7 @@ int main(int argc, const char *argv[]) { argv[--offset] = "-ObjC++"; #endif - CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_SkipFunctionBodies)); + CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord)); for (unsigned i(0), e(clang_getNumDiagnostics(unit)); i != e; ++i) { CXDiagnostic diagnostic(clang_getDiagnostic(unit, i)); @@ -198,11 +715,11 @@ int main(int argc, const char *argv[]) { clang_visitChildren(clang_getTranslationUnitCursor(unit), &CYChildVisit, &baton); for (CYKeyMap::const_iterator key(keys.begin()); key != keys.end(); ++key) { - std::string value(key->second); - for (size_t i(0), e(value.size()); i != e; ++i) - if (value[i] <= 0 || value[i] >= 0x7f || value[i] == '\n') + std::string code(key->second.code_); + for (size_t i(0), e(code.size()); i != e; ++i) + if (code[i] <= 0 || code[i] >= 0x7f || code[i] == '\n') goto skip; - std::cout << key->first << "|\"" << value << "\"" << std::endl; + std::cout << key->first << "|" << key->second.flags_ << "\"" << code << "\"" << std::endl; skip:; } clang_disposeTranslationUnit(unit);