From da4811c5ea4218179d9f50c99bceaa03cdcd855c Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Wed, 30 Jul 2014 13:24:25 +0200 Subject: [PATCH] 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. --- bin/app/data/src/header.h | 2 ++ src/lib/data/Storage.cpp | 4 +-- src/lib/data/Storage.h | 2 +- src/lib/data/parser/ParserClient.h | 2 +- src/lib/data/parser/cxx/ASTVisitor.cpp | 36 ++++++++--------------- src/lib/data/parser/cxx/ASTVisitor.h | 4 +-- src/lib/data/parser/cxx/utilityCxx.cpp | 29 ++++++++++--------- src/lib/utility/utilityString.cpp | 10 +++++++ src/lib/utility/utilityString.h | 2 ++ src/test/CxxParserTestSuite.h | 40 ++++++++++++++++++++++---- src/test/UtilityStringTestSuite.h | 25 ++++++++++++++++ 11 files changed, 106 insertions(+), 50 deletions(-) diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h index 8db34d1e..a23581e1 100644 --- a/bin/app/data/src/header.h +++ b/bin/app/data/src/header.h @@ -90,3 +90,5 @@ namespace } typedef A* D; + +D globalD; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 8565c46e..2e4aa13e 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -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); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index e90c7076..4caa445e 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -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( diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index 42f43006..01eebc7b 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -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, diff --git a/src/lib/data/parser/cxx/ASTVisitor.cpp b/src/lib/data/parser/cxx/ASTVisitor.cpp index 8f634bec..583dab5a 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib/data/parser/cxx/ASTVisitor.cpp @@ -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::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 ASTVisitor::getParameters(clang::FunctionDecl* declaration) const @@ -431,7 +418,8 @@ std::vector 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; diff --git a/src/lib/data/parser/cxx/ASTVisitor.h b/src/lib/data/parser/cxx/ASTVisitor.h index f82ce81c..0e6d1939 100644 --- a/src/lib/data/parser/cxx/ASTVisitor.h +++ b/src/lib/data/parser/cxx/ASTVisitor.h @@ -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 getParameters(clang::FunctionDecl* declaration) const; DataType qualTypeToDataType(clang::QualType qualType); diff --git a/src/lib/data/parser/cxx/utilityCxx.cpp b/src/lib/data/parser/cxx/utilityCxx.cpp index d6a959c4..e65b90aa 100644 --- a/src/lib/data/parser/cxx/utilityCxx.cpp +++ b/src/lib/data/parser/cxx/utilityCxx.cpp @@ -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()) + { + typeName = utility::substrAfter(qualType.getAsString(), ' '); + break; + } + else if (type->isPointerType()) { std::shared_ptr modifier = std::make_shared(); if (qualType.isConstQualified()) + { modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST); + } modifierStack.push(modifier); qualType = type->getPointeeType(); @@ -31,7 +39,9 @@ namespace utility { std::shared_ptr modifier = std::make_shared(); if (qualType.isConstQualified()) + { modifier->addQualifier(DataTypeQualifierList::QUALIFIER_CONST); + } modifierStack.push(modifier); qualType = clang::dyn_cast(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); } diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index 84d17e79..5e0f8afe 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -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 ResType; diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 185e5c1b..c884ddbf 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -12,6 +12,8 @@ namespace utility template> 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); } diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 1300906f..1d75b67c 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -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 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 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)); } diff --git a/src/test/UtilityStringTestSuite.h b/src/test/UtilityStringTestSuite.h index a5e7742f..15267ac8 100644 --- a/src/test/UtilityStringTestSuite.h +++ b/src/test/UtilityStringTestSuite.h @@ -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";