问题描述
我有种 CXCursor
的实例 CXCursor_CXXMethod
。我想了解该功能是否适用常量
或挥发性
,例如:
I have an instance of CXCursor
of kind CXCursor_CXXMethod
. I want to find out if the function is const
or volatile
, for example:
class Foo {
public:
void bar() const;
void baz() volatile;
void qux() const volatile;
};
我找不到任何libclang的文档中非常有用。我试图 clang_isConstQualifiedType
和 clang_isVolatileQualifiedType
但这些似乎总是返回 0
在C ++成员函数的类型。
I could not find anything useful in the documentation of libclang. I tried clang_isConstQualifiedType
and clang_isVolatileQualifiedType
but these always seem to return 0
on C++ member function types.
推荐答案
我能想到的两种方法:
使用 libclang
词法分析器
Using the libclang
lexer
出现在对我的作品;它使用了 libclang
标记生成器,以打散方法声明,然后记录的方法括号之外的任何关键字。
The code which appears in this SO answer works for me; it uses the libclang
tokenizer to break a method declaration apart, and then records any keywords outside of the method parentheses.
它做的不的访问code的AST,并尽可能我可以告诉不涉及语法分析器都没有。如果你确信code您调查是正确的C ++,我认为这种做法是安全的。
It does not access the AST of the code, and as far as I can tell doesn't involve the parser at all. If you are sure the code you investigate is proper C++, I believe this approach is safe.
的劣势的:该解决方案似乎没有考虑到preprocessing指令,因此code必须首先处理(例如,通过通过CPP
)。
Disadvantages: This solution does not appear to take into account preprocessing directives, so the code has to be processed first (e.g., passed through cpp
).
举例code(解析必须是第一个参数到您的程序,例如文件 ./ a.out的bla.cpp
)
Example code (the file to parse must be the first argument to your program, e.g. ./a.out bla.cpp
):
#include "clang-c/Index.h"
#include <string>
#include <set>
#include <iostream>
std::string GetClangString(CXString str)
{
const char* tmp = clang_getCString(str);
if (tmp == NULL) {
return "";
} else {
std::string translated = std::string(tmp);
clang_disposeString(str);
return translated;
}
}
void GetMethodQualifiers(CXTranslationUnit translationUnit,
std::set<std::string>& qualifiers,
CXCursor cursor) {
qualifiers.clear();
CXSourceRange range = clang_getCursorExtent(cursor);
CXToken* tokens;
unsigned int numTokens;
clang_tokenize(translationUnit, range, &tokens, &numTokens);
bool insideBrackets = false;
for (unsigned int i = 0; i < numTokens; i++) {
std::string token = GetClangString(clang_getTokenSpelling(translationUnit, tokens[i]));
if (token == "(") {
insideBrackets = true;
} else if (token == "{" || token == ";") {
break;
} else if (token == ")") {
insideBrackets = false;
} else if (clang_getTokenKind(tokens[i]) == CXToken_Keyword &&
!insideBrackets) {
qualifiers.insert(token);
}
}
clang_disposeTokens(translationUnit, tokens, numTokens);
}
int main(int argc, char *argv[]) {
CXIndex Index = clang_createIndex(0, 0);
CXTranslationUnit TU = clang_parseTranslationUnit(Index, 0,
argv, argc, 0, 0, CXTranslationUnit_None);
// Set the file you're interested in, and the code location:
CXFile file = clang_getFile(TU, argv[1]);
int line = 5;
int column = 6;
CXSourceLocation location = clang_getLocation(TU, file, line, column);
CXCursor cursor = clang_getCursor(TU, location);
std::set<std::string> qualifiers;
GetMethodQualifiers(TU, qualifiers, cursor);
for (std::set<std::string>::const_iterator i = qualifiers.begin(); i != qualifiers.end(); ++i) {
std::cout << *i << std::endl;
}
clang_disposeTranslationUnit(TU);
clang_disposeIndex(Index);
return 0;
}
使用的 libclang
统一符号解析(USR)
Using libclang
's Unified Symbol Resolution (USR)
该方法包括使用解析器,并提取从AST预选赛信息。
This approach involves using the parser itself, and extracting qualifier information from the AST.
的优点的:似乎为code。与preprocessor指令,至少对于简单的情况下工作。
Advantages: Seems to work for code with preprocessor directives, at least for simple cases.
的劣势的:我的解决方案解析USR,这是无证,并在未来可能会改变。不过,这是很容易编写单元测试,以防止这一点。
Disadvantages: My solution parses the USR, which is undocumented, and might change in the future. Still, it's easy to write a unit-test to guard against that.
看看 $(CLANG_SRC)/tools/libclang/CIndexUSRs.cpp
,它包含了code,它生成一个USR,因此,所包含的信息解析字符串USR要求。具体来说,线523-529(LLVM中3.1的源代码从下载)为预选赛的一部分。
Take a look at $(CLANG_SRC)/tools/libclang/CIndexUSRs.cpp
, it contains the code that generates a USR, and therefore contains the information required to parse the USR string. Specifically, lines 523-529 (in LLVM 3.1's source downloaded from www.llvm.org) for the qualifier part.
某处添加以下功能:
void parseUsrString(const std::string& usrString, bool* isVolatile, bool* isConst, bool *isRestrict) {
size_t bangLocation = usrString.find("#");
if (bangLocation == std::string::npos || bangLocation == usrString.length() - 1) {
*isVolatile = *isConst = *isRestrict = false;
return;
}
bangLocation++;
int x = usrString[bangLocation];
*isConst = x & 0x1;
*isVolatile = x & 0x4;
*isRestrict = x & 0x2;
}
和的main()
,
CXString usr = clang_getCursorUSR(cursor);
const char *usr_string = clang_getCString(usr);
std::cout << usr_string << "\n";
bool isVolatile, isConst, isRestrict;
parseUsrString(usr_string, &isVolatile, &isConst, &isRestrict);
printf("restrict, volatile, const: %d %d %d\n", isRestrict, isVolatile, isConst);
clang_disposeString(usr);
运行在美孚:: qux()
从
#define BLA const
class Foo {
public:
void bar() const;
void baz() volatile;
void qux() BLA volatile;
};
产生的预期效果。
produces the expected result of
c:@C@Foo@F@qux#5
restrict, volatile, const: 0 1 1
的买者的:你可能已经注意到了 libclang
的源suggets我的code应该 isVolatile = X'放大器; 0X2
,而不是为0x4
,所以它可能是你应该0X2替换为0x4的情况。这是可能我的实现(OS X)已经取代他们。
Caveat: you might have noticed that libclang
's source suggets my code should be isVolatile = x & 0x2
and not 0x4
, so it might be the case you should replace 0x4 with 0x2. It's possible my implementation (OS X) has them replaced.
这篇关于如何找出一个成员函数是const或volatile与libclang?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!