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;
D globalD;
+2 -2
View File
@@ -39,9 +39,9 @@ void Storage::logLocations() const
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);
addAccess(node, access);
+1 -1
View File
@@ -27,7 +27,7 @@ public:
// ParserClient implementation
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
);
virtual void onClassParsed(
+1 -1
View File
@@ -52,7 +52,7 @@ public:
virtual ~ParserClient();
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;
virtual void onClassParsed(
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;
}
bool ASTVisitor::VisitTypedefDecl(const clang::TypedefDecl* declaration)
bool ASTVisitor::VisitTypedefDecl(clang::TypedefDecl* declaration)
{
if (hasValidLocation(declaration))
{
m_client->onTypedefParsed(
getParseLocation(declaration->getSourceRange()),
getParseLocationForNamedDecl(declaration),
declaration->getQualifiedNameAsString(),
utility::qualTypeToDataType(declaration->getUnderlyingType()),
getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getUnderlyingType()),
convertAccessType(declaration->getAccess())
);
}
@@ -382,23 +382,21 @@ ParseVariable ASTVisitor::getParseVariable(clang::DeclaratorDecl* declaration) c
}
return ParseVariable(
getParseTypeUsage(declaration),
getParseTypeUsage(declaration->getTypeSourceInfo()->getTypeLoc(), declaration->getType()),
declaration->getQualifiedNameAsString(),
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 (loc.getNextTypeLoc())
while (typeLoc.getNextTypeLoc())
{
loc = loc.getNextTypeLoc();
typeLoc = typeLoc.getNextTypeLoc();
}
ParseLocation parseLocation = getParseLocation(loc.getSourceRange());
DataType dataType = utility::qualTypeToDataType(declaration->getType());
ParseLocation parseLocation = getParseLocation(typeLoc.getSourceRange());
DataType dataType = utility::qualTypeToDataType(type);
parseLocation.endColumnNumber += dataType.getRawTypeName().size() - 1;
@@ -410,19 +408,8 @@ ParseTypeUsage ASTVisitor::getParseTypeUsageOfReturnType(clang::FunctionDecl* de
// TODO: use FunctionDecl::getReturnTypeSourceRange() in newer clang version
const clang::TypeSourceInfo *TSI = declaration->getTypeSourceInfo();
const clang::FunctionTypeLoc FTL = TSI->getTypeLoc().IgnoreParens().getAs<clang::FunctionTypeLoc>();
clang::TypeLoc loc = FTL.getReturnLoc();
while (loc.getNextTypeLoc())
{
loc = loc.getNextTypeLoc();
}
ParseLocation parseLocation = getParseLocation(loc.getSourceRange());
DataType dataType = utility::qualTypeToDataType(declaration->getReturnType());
parseLocation.endColumnNumber += dataType.getRawTypeName().size() - 1;
return ParseTypeUsage(parseLocation, dataType);
return getParseTypeUsage(FTL.getReturnLoc(), declaration->getReturnType());
}
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++)
{
parameters.push_back(getParseTypeUsage(declaration->getParamDecl(i)));
clang::ParmVarDecl* paramDecl = declaration->getParamDecl(i);
parameters.push_back(getParseTypeUsage(paramDecl->getTypeSourceInfo()->getTypeLoc(), paramDecl->getType()));
}
return parameters;
+2 -2
View File
@@ -27,7 +27,7 @@ public:
// RecursiveASTVisitor implementation
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 VisitVarDecl(clang::VarDecl* declaration); // global variables and static fields
virtual bool VisitFieldDecl(clang::FieldDecl* declaration); // fields
@@ -51,7 +51,7 @@ private:
ParseLocation getParseLocationOfFunctionBody(clang::FunctionDecl* decl) const;
ParseLocation getParseLocationOfRecordBody(clang::CXXRecordDecl* decl) 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;
std::vector<ParseTypeUsage> getParameters(clang::FunctionDecl* declaration) const;
DataType qualTypeToDataType(clang::QualType qualType);
+15 -14
View File
@@ -6,6 +6,7 @@
#include "data/type/modifier/DataTypeModifierReference.h"
#include "data/type/DataTypeModifierStack.h"
#include "data/type/DataTypeQualifierList.h"
#include "utility/utilityString.h"
namespace utility
{
@@ -18,11 +19,18 @@ namespace utility
while (true)
{
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>();
if (qualType.isConstQualified())
{
modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
modifierStack.push(modifier);
qualType = type->getPointeeType();
@@ -31,7 +39,9 @@ namespace utility
{
std::shared_ptr<DataTypeModifier> modifier = std::make_shared<DataTypeModifierArray>();
if (qualType.isConstQualified())
{
modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
modifierStack.push(modifier);
qualType = clang::dyn_cast<clang::ArrayType>(type)->getElementType();
@@ -46,21 +56,10 @@ namespace utility
}
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.
size_t nameStartPosition = typeName.find(' ');
if (nameStartPosition != typeName.npos)
{
nameStartPosition += 1;
}
else
{
nameStartPosition = 0;
}
typeName = typeName.substr(nameStartPosition, typeName.size());
typeName = utility::substrAfter(qualType.getAsString(), ' ');
//m_typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information.
// typeName = qualType.getBaseTypeIdentifier()->getName(); // this one does not keep namespace information.
break;
}
else
@@ -71,7 +70,9 @@ namespace utility
}
if (qualType.isConstQualified())
{
qualifierList.addQualifier(DataTypeQualifierList::QUALIFIER_CONST);
}
return DataType(typeName, qualifierList, modifierStack);
}
+10
View File
@@ -2,6 +2,16 @@
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)
{
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>>
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);
}
+34 -6
View File
@@ -363,7 +363,7 @@ public:
);
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()
@@ -376,7 +376,7 @@ public:
);
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()
@@ -389,7 +389,7 @@ public:
);
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()
@@ -403,7 +403,35 @@ public:
);
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()
@@ -797,11 +825,11 @@ private:
{
public:
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
)
{
std::string str = addAccessPrefix(underlyingType.getFullTypeName() + " -> " + fullName, access);
std::string str = addAccessPrefix(underlyingType.dataType.getFullTypeName() + " -> " + fullName, access);
typedefs.push_back(addLocationSuffix(str, location));
}
+25
View File
@@ -51,6 +51,31 @@ public:
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()
{
const std::string foo = "foo";