data: Parsing Typedefs with ParseTypeUsage

With this change typedefs have two TokenLocations, one for the TypeName and one for the UnderlyingType. When the
typedef is used with a variable the typedef is referenced now and not the underlying type.
This commit is contained in:
Eberhard Graether
2014-07-30 13:24:25 +02:00
parent 96df63055a
commit da4811c5ea
11 changed files with 106 additions and 50 deletions
+2
View File
@@ -90,3 +90,5 @@ namespace
} }
typedef A* D; typedef A* D;
D globalD;
+2 -2
View File
@@ -39,9 +39,9 @@ void Storage::logLocations() const
void Storage::onTypedefParsed( void Storage::onTypedefParsed(
const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, AccessType access const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& underlyingType, AccessType access
){ ){
log("typedef", fullName + " -> " + underlyingType.getFullTypeName(), location); log("typedef", fullName + " -> " + underlyingType.dataType.getFullTypeName(), location);
Node* node = m_graph.createNodeHierarchy(Node::NODE_TYPEDEF, fullName); Node* node = m_graph.createNodeHierarchy(Node::NODE_TYPEDEF, fullName);
addAccess(node, access); addAccess(node, access);
+1 -1
View File
@@ -27,7 +27,7 @@ public:
// ParserClient implementation // ParserClient implementation
virtual void onTypedefParsed( virtual void onTypedefParsed(
const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& underlyingType,
AccessType access AccessType access
); );
virtual void onClassParsed( virtual void onClassParsed(
+1 -1
View File
@@ -52,7 +52,7 @@ public:
virtual ~ParserClient(); virtual ~ParserClient();
virtual void onTypedefParsed( virtual void onTypedefParsed(
const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& underlyingType,
AccessType access) = 0; AccessType access) = 0;
virtual void onClassParsed( virtual void onClassParsed(
const ParseLocation& location, const std::string& fullName, AccessType access, const ParseLocation& location, const std::string& fullName, AccessType access,
+12 -24
View File
@@ -22,14 +22,14 @@ bool ASTVisitor::VisitStmt(const clang::Stmt* statement)
return true; return true;
} }
bool ASTVisitor::VisitTypedefDecl(const clang::TypedefDecl* declaration) bool ASTVisitor::VisitTypedefDecl(clang::TypedefDecl* declaration)
{ {
if (hasValidLocation(declaration)) if (hasValidLocation(declaration))
{ {
m_client->onTypedefParsed( m_client->onTypedefParsed(
getParseLocation(declaration->getSourceRange()), getParseLocationForNamedDecl(declaration),
declaration->getQualifiedNameAsString(), declaration->getQualifiedNameAsString(),
utility::qualTypeToDataType(declaration->getUnderlyingType()), getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getUnderlyingType()),
convertAccessType(declaration->getAccess()) convertAccessType(declaration->getAccess())
); );
} }
@@ -382,23 +382,21 @@ ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) c
} }
return ParseVariable( return ParseVariable(
getParseTypeUsage(declaration), getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getType()),
declaration->getQualifiedNameAsString(), declaration->getQualifiedNameAsString(),
isStatic isStatic
); );
} }
ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::DeclaratorDecl* declaration) const ParseTypeUsage ASTVisitor::getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const
{ {
clang::TypeLoc loc = declaration->getTypeSourceInfo()->getTypeLoc(); while (typeLoc.getNextTypeLoc())
while (loc.getNextTypeLoc())
{ {
loc = loc.getNextTypeLoc(); typeLoc = typeLoc.getNextTypeLoc();
} }
ParseLocation parseLocation = getParseLocation(loc.getSourceRange()); ParseLocation parseLocation = getParseLocation(typeLoc.getSourceRange());
DataType dataType = utility::qualTypeToDataType(declaration->getType()); DataType dataType = utility::qualTypeToDataType(type);
parseLocation.endColumnNumber += dataType.getRawTypeName().size() - 1; parseLocation.endColumnNumber += dataType.getRawTypeName().size() - 1;
@@ -410,19 +408,8 @@ ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* de
// TODO: use FunctionDecl::getReturnTypeSourceRange() in newer clang version // TODO: use FunctionDecl::getReturnTypeSourceRange() in newer clang version
const clang::TypeSourceInfo *TSI = declaration->getTypeSourceInfo(); const clang::TypeSourceInfo *TSI = declaration->getTypeSourceInfo();
const clang::FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs<clang::FunctionTypeLoc>(); const clang::FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs<clang::FunctionTypeLoc>();
clang::TypeLoc loc = FTL.getReturnLoc();
while (loc.getNextTypeLoc()) return getParseTypeUsage(FTL.getReturnLoc(), declaration->getReturnType());
{
loc = loc.getNextTypeLoc();
}
ParseLocation parseLocation = getParseLocation(loc.getSourceRange());
DataType dataType = utility::qualTypeToDataType(declaration->getReturnType());
parseLocation.endColumnNumber += dataType.getRawTypeName().size() - 1;
return ParseTypeUsage(parseLocation, dataType);
} }
std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* declaration) const std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* declaration) const
@@ -431,7 +418,8 @@ std::vector<ParseTypeUsage> ASTVisitor::getParameters(clang::FunctionDecl* decla
for (unsigned i = 0; i < declaration->getNumParams(); i++) for (unsigned i = 0; i < declaration->getNumParams(); i++)
{ {
parameters.push_back(getParseTypeUsage(declaration->getParamDecl(i))); clang::ParmVarDecl* paramDecl = declaration->getParamDecl(i);
parameters.push_back(getParseTypeUsage(paramDecl->getTypeSourceInfo()->getTypeLoc(), paramDecl->getType()));
} }
return parameters; return parameters;
+2 -2
View File
@@ -27,7 +27,7 @@ public:
// RecursiveASTVisitor implementation // RecursiveASTVisitor implementation
virtual bool VisitStmt(const clang::Stmt* statement); // avoid visiting virtual bool VisitStmt(const clang::Stmt* statement); // avoid visiting
virtual bool VisitTypedefDecl(const clang::TypedefDecl* declaration); // typedefs virtual bool VisitTypedefDecl(clang::TypedefDecl* declaration); // typedefs
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* declaration); // structs, classes and inheritance virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* declaration); // structs, classes and inheritance
virtual bool VisitVarDecl(clang::VarDecl* declaration); // global variables and static fields virtual bool VisitVarDecl(clang::VarDecl* declaration); // global variables and static fields
virtual bool VisitFieldDecl(clang::FieldDecl* declaration); // fields virtual bool VisitFieldDecl(clang::FieldDecl* declaration); // fields
@@ -51,7 +51,7 @@ private:
ParseLocation getParseLocationOfFunctionBody(clang::FunctionDecl* decl) const; ParseLocation getParseLocationOfFunctionBody(clang::FunctionDecl* decl) const;
ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const; ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) const;
ParseVariable getParseVariable(clang::DeclaratorDecl* declaration) const; ParseVariable getParseVariable(clang::DeclaratorDecl* declaration) const;
ParseTypeUsage getParseTypeUsage(clang::DeclaratorDecl* declaration) const; ParseTypeUsage getParseTypeUsage(clang::TypeLoc typeLoc, const clang::QualType& type) const;
ParseTypeUsage getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const; ParseTypeUsage getParseTypeUsageOfReturnType(clang::FunctionDecl* declaration) const;
std::vector<ParseTypeUsage> getParameters(clang::FunctionDecl* declaration) const; std::vector<ParseTypeUsage> getParameters(clang::FunctionDecl* declaration) const;
DataType qualTypeToDataType(clang::QualType qualType); DataType qualTypeToDataType(clang::QualType qualType);
+15 -14
View File
@@ -6,6 +6,7 @@
#include "data/type/modifier/DataTypeModifierReference.h" #include "data/type/modifier/DataTypeModifierReference.h"
#include "data/type/DataTypeModifierStack.h" #include "data/type/DataTypeModifierStack.h"
#include "data/type/DataTypeQualifierList.h" #include "data/type/DataTypeQualifierList.h"
#include "utility/utilityString.h"
namespace utility namespace utility
{ {
@@ -18,11 +19,18 @@ namespace utility
while (true) while (true)
{ {
const clang::Type* type = qualType.getTypePtr(); const clang::Type* type = qualType.getTypePtr();
if (type->isPointerType()) if (type->getAs<clang::TypedefType>())
{
typeName = utility::substrAfter(qualType.getAsString(), ' ');
break;
}
else if (type->isPointerType())
{ {
std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierPointer>(); std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierPointer>();
if (qualType.isConstQualified()) if (qualType.isConstQualified())
{
modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST); modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
modifierStack.push(modifier); modifierStack.push(modifier);
qualType = type->getPointeeType(); qualType = type->getPointeeType();
@@ -31,7 +39,9 @@ namespace utility
{ {
std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierArray>(); std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierArray>();
if (qualType.isConstQualified()) if (qualType.isConstQualified())
{
modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST); modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
modifierStack.push(modifier); modifierStack.push(modifier);
qualType = clang::dyn_cast<clang::ArrayType>(type)->getElementType(); qualType = clang::dyn_cast<clang::ArrayType>(type)->getElementType();
@@ -46,21 +56,10 @@ namespace utility
} }
else if (type->isStructureOrClassType() || type->isEnumeralType()) else if (type->isStructureOrClassType() || type->isEnumeralType())
{ {
typeName = qualType.getAsString();
// we are working on the string here to not lose the namespace information stored in the name. // we are working on the string here to not lose the namespace information stored in the name.
size_t nameStartPosition = typeName.find(' '); typeName = utility::substrAfter(qualType.getAsString(), ' ');
if (nameStartPosition != typeName.npos)
{
nameStartPosition += 1;
}
else
{
nameStartPosition = 0;
}
typeName = typeName.substr(nameStartPosition, typeName.size());
//m_typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information. // typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information.
break; break;
} }
else else
@@ -71,7 +70,9 @@ namespace utility
} }
if (qualType.isConstQualified()) if (qualType.isConstQualified())
{
qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST); qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
return DataType(typeName, qualifierList, modifierStack); return DataType(typeName, qualifierList, modifierStack);
} }
+10
View File
@@ -2,6 +2,16 @@
namespace utility namespace utility
{ {
std::string substrAfter(const std::string& str, char delimiter)
{
size_t pos = str.find(delimiter);
if (pos != std::string::npos)
{
return str.substr(pos + 1, str.size());
}
return str;
}
bool isPrefix(const std::string& prefix, const std::string& text) bool isPrefix(const std::string& prefix, const std::string& text)
{ {
typedef std::pair<std::string::const_iterator, std::string::const_iterator> ResType; typedef std::pair<std::string::const_iterator, std::string::const_iterator> ResType;
+2
View File
@@ -12,6 +12,8 @@ namespace utility
template<typename ContainerType = std::vector<std::string>> template<typename ContainerType = std::vector<std::string>>
ContainerType split(const std::string& str, const std::string& delimiter); ContainerType split(const std::string& str, const std::string& delimiter);
std::string substrAfter(const std::string& str, char delimiter);
bool isPrefix(const std::string& prefix, const std::string& text); bool isPrefix(const std::string& prefix, const std::string& text);
} }
+34 -6
View File
@@ -363,7 +363,7 @@ public:
); );
TS_ASSERT_EQUALS(client->typedefs.size(), 1); TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> uint <1:1 1:22>"); TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> uint <1:22 1:25>");
} }
void test_cxx_parser_finds_typedef_in_named_namespace() void test_cxx_parser_finds_typedef_in_named_namespace()
@@ -376,7 +376,7 @@ public:
); );
TS_ASSERT_EQUALS(client->typedefs.size(), 1); TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> test::uint <3:2 3:23>"); TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> test::uint <3:23 3:26>");
} }
void test_cxx_parser_finds_typedef_in_anonymous_namespace() void test_cxx_parser_finds_typedef_in_anonymous_namespace()
@@ -389,7 +389,7 @@ public:
); );
TS_ASSERT_EQUALS(client->typedefs.size(), 1); TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> (anonymous namespace)::uint <3:2 3:23>"); TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> (anonymous namespace)::uint <3:23 3:26>");
} }
void test_cxx_parser_finds_typedef_that_uses_type_defined_in_named_namespace() void test_cxx_parser_finds_typedef_that_uses_type_defined_in_named_namespace()
@@ -403,7 +403,35 @@ public:
); );
TS_ASSERT_EQUALS(client->typedefs.size(), 1); TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "test::TestStruct -> globalTestStruct <5:1 5:26>"); TS_ASSERT_EQUALS(client->typedefs[0], "test::TestStruct -> globalTestStruct <5:26 5:41>");
}
void test_cxx_parser_finds_global_variable_with_typedef_type()
{
std::shared_ptr<TestParserClient> client = parseCode(
"typedef unsigned int uint;\n"
"uint number;\n"
);
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int -> uint <1:22 1:25>");
TS_ASSERT_EQUALS(client->globalVariables.size(), 1);
TS_ASSERT_EQUALS(client->globalVariables[0], "uint number <2:6 2:11>");
}
void test_cxx_parser_finds_global_variable_with_qualified_typedef_type()
{
std::shared_ptr<TestParserClient> client = parseCode(
"typedef unsigned int* uint;\n"
"const uint* number;\n"
);
TS_ASSERT_EQUALS(client->typedefs.size(), 1);
TS_ASSERT_EQUALS(client->typedefs[0], "unsigned int * -> uint <1:23 1:26>");
TS_ASSERT_EQUALS(client->globalVariables.size(), 1);
TS_ASSERT_EQUALS(client->globalVariables[0], "uint const * number <2:13 2:18>");
} }
void test_cxx_parser_finds_public_inheritance() void test_cxx_parser_finds_public_inheritance()
@@ -797,11 +825,11 @@ private:
{ {
public: public:
virtual void onTypedefParsed( virtual void onTypedefParsed(
const ParseLocation& location, const std::string& fullName, const DataType& underlyingType, const ParseLocation& location, const std::string& fullName, const ParseTypeUsage& underlyingType,
AccessType access AccessType access
) )
{ {
std::string str = addAccessPrefix(underlyingType.getFullTypeName() + " -> " + fullName, access); std::string str = addAccessPrefix(underlyingType.dataType.getFullTypeName() + " -> " + fullName, access);
typedefs.push_back(addLocationSuffix(str, location)); typedefs.push_back(addLocationSuffix(str, location));
} }
+25
View File
@@ -51,6 +51,31 @@ public:
TS_ASSERT_EQUALS(result[3], "C"); TS_ASSERT_EQUALS(result[3], "C");
} }
void test_substr_after_with_single_delimiter_occurence()
{
TS_ASSERT_EQUALS(utility::substrAfter("foo bar", ' '), "bar");
}
void test_substr_after_with_multiple_delimiter_occurences()
{
TS_ASSERT_EQUALS(utility::substrAfter("foo bar foo", ' '), "bar foo");
}
void test_substr_after_with_no_delimiter_occurence()
{
TS_ASSERT_EQUALS(utility::substrAfter("foobar", ' '), "foobar");
}
void test_substr_after_with_delimiter_at_start()
{
TS_ASSERT_EQUALS(utility::substrAfter(" foobar", ' '), "foobar");
}
void test_substr_after_with_delimiter_at_end()
{
TS_ASSERT_EQUALS(utility::substrAfter("foobar ", ' '), "");
}
void test_empty_string_is_detected_as_prefix_of_any_other_string() void test_empty_string_is_detected_as_prefix_of_any_other_string()
{ {
const std::string foo = "foo"; const std::string foo = "foo";