Skip to content

Commit dc1fea5

Browse files
committed
Fixes for type bound procedures in Fortran
* Recognize procedures with "nopass" as static functions and with "final" as destructors. * Copy arguments (and documentation) for non-"generic" methods from the method implementation (when it is found in the same module/scope). * handle deferred procs (with abstract interface) * handle generic procedures (method overloading) by duplicating the generic method and copying the appropriate arguments to each one.
1 parent 96ec916 commit dc1fea5

6 files changed

+595
-5
lines changed

src/fortranscanner.l

+204-5
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ static inline void pop_state(yyscan_t yyscanner);
232232

233233
static void startScope(yyscan_t yyscanner,Entry *scope);
234234
static bool endScope(yyscan_t yyscanner,Entry *scope, bool isGlobalRoot=FALSE);
235+
static void copyEntry(std::shared_ptr<Entry> dest, const std::shared_ptr<Entry> &src);
235236
static void resolveModuleProcedures(yyscan_t yyscanner,Entry *current_root);
237+
static void resolveTypeBoundProcedures(Entry *scope);
236238
static void truncatePrepass(yyscan_t yyscanner,int index);
237239
static void pushBuffer(yyscan_t yyscanner,const QCString &buffer);
238240
static void popBuffer(yyscan_t yyscanner);
@@ -721,7 +723,7 @@ private {
721723

722724
<TypedefBodyContains>{ /* Type Bound Procedures */
723725
^{BS}PROCEDURE{ARGS}? {
724-
yyextra->current->type = QCString(yytext).simplifyWhiteSpace();
726+
yyextra->current->type = QCString(yytext).simplifyWhiteSpace().lower();
725727
}
726728
^{BS}final {
727729
yyextra->current->spec |= Entry::Final;
@@ -733,7 +735,7 @@ private {
733735
{COMMA} {
734736
}
735737
{ATTR_SPEC} {
736-
yyextra->currentModifiers |= QCString(yytext);
738+
yyextra->currentModifiers |= QCString(yytext).stripWhiteSpace();
737739
}
738740
{BS}"::"{BS} {
739741
}
@@ -742,14 +744,46 @@ private {
742744
yyextra->modifiers[yyextra->current_root][name.lower().str()] |= yyextra->currentModifiers;
743745
yyextra->current->section = Entry::FUNCTION_SEC;
744746
yyextra->current->name = name;
747+
// check for procedure(name)
748+
if (yyextra->current->type.find('(') != -1)
749+
{
750+
yyextra->current->args = extractFromParens(yyextra->current->type).stripWhiteSpace();
751+
}
752+
else
753+
{
754+
yyextra->current->args = name.lower(); // target procedure name if no => is given
755+
}
745756
yyextra->current->fileName = yyextra->fileName;
746757
yyextra->current->bodyLine = yyextra->lineNr;
747758
yyextra->current->startLine = yyextra->lineNr;
748759
addCurrentEntry(yyscanner,true);
749760
}
750761
{BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */
751-
QCString args = yytext;
752-
yyextra->last_entry->args = args.lower();
762+
QCString tmp = yytext;
763+
int i = tmp.find("=>");
764+
if( i != -1 )
765+
tmp.remove(0, i+2);
766+
tmp = tmp.simplifyWhiteSpace().lower();
767+
if( yyextra->last_entry->type == "generic")
768+
{
769+
// duplicate entries for each overloaded variant
770+
// (parse through medhod1,method2, methodN, ...
771+
//printf("Parsing through %s for generic method %s.\n", tmp.data(), last_entry->name.data());
772+
int i = tmp.find(",");
773+
while(i > 0)
774+
{
775+
copyEntry(yyextra->current, yyextra->last_entry);
776+
yyextra->current->name = yyextra->last_entry->name;
777+
yyextra->current->section = Entry::FUNCTION_SEC;
778+
yyextra->last_entry->args = tmp.left(i).stripWhiteSpace();
779+
//printf("Found %s.\n", last_entry->args.data());
780+
addCurrentEntry(yyscanner,true);
781+
tmp = tmp.remove(0,i+1).stripWhiteSpace();
782+
i = tmp.find(",");
783+
}
784+
}
785+
//printf("Target function: %s\n", tmp.data());
786+
yyextra->last_entry->args = tmp;
753787
}
754788
"\n" {
755789
yyextra->currentModifiers = SymbolModifiers();
@@ -1869,7 +1903,11 @@ static void copyEntry(std::shared_ptr<Entry> dest, const std::shared_ptr<Entry>
18691903
dest->args = src->args;
18701904
dest->argList = src->argList;
18711905
dest->doc = src->doc;
1906+
dest->docLine = src->docLine;
1907+
dest->docFile = src->docFile;
18721908
dest->brief = src->brief;
1909+
dest->briefLine= src->briefLine;
1910+
dest->briefFile= src->briefFile;
18731911
}
18741912

18751913
/** fill empty interface module procedures with info from
@@ -2251,6 +2289,13 @@ static void applyModifiers(Entry *ent, const SymbolModifiers& mdfs)
22512289
ent->protection = Public;
22522290
else if (mdfs.protection == SymbolModifiers::PRIVATE)
22532291
ent->protection = Private;
2292+
2293+
if (mdfs.nonoverridable)
2294+
ent->spec |= Entry::Final;
2295+
if (mdfs.nopass)
2296+
ent->stat = TRUE;
2297+
if (mdfs.deferred)
2298+
ent->virt = Pure;
22542299
}
22552300

22562301
/*! Starts the new scope in fortran program. Consider using this function when
@@ -2375,7 +2420,7 @@ static bool endScope(yyscan_t yyscanner,Entry *scope, bool isGlobalRoot)
23752420
// iterate variables: get and apply yyextra->modifiers
23762421
for (const auto &ce : scope->children())
23772422
{
2378-
if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC && ce->section != Entry::CLASS_SEC && ce->section != Entry::FUNCTION_SEC)
2423+
if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC && ce->section != Entry::CLASS_SEC)
23792424
continue;
23802425

23812426
//cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl;
@@ -2395,9 +2440,163 @@ static bool endScope(yyscan_t yyscanner,Entry *scope, bool isGlobalRoot)
23952440
// clear all yyextra->modifiers of the scope
23962441
yyextra->modifiers.erase(scope);
23972442

2443+
// resolve procedures in types
2444+
resolveTypeBoundProcedures(scope);
2445+
23982446
return TRUE;
23992447
}
24002448

2449+
/*! search for types with type bound procedures (e.g. methods)
2450+
* and try to resolve their arguments
2451+
*/
2452+
static void resolveTypeBoundProcedures(Entry *scope)
2453+
{
2454+
// map of all subroutines/functions
2455+
bool procMapCreated = false;
2456+
std::map<std::string,std::shared_ptr<Entry>> procMap;
2457+
2458+
// map of all abstract interfaces
2459+
bool interfMapCreated = false;
2460+
std::map<std::string,std::shared_ptr<Entry>> interfMap;
2461+
2462+
// iterate over all types
2463+
for(const auto &ce: scope->children())
2464+
{
2465+
if (ce->section != Entry::CLASS_SEC)
2466+
continue;
2467+
2468+
// handle non-"generic" non-"deferred" methods, copying the arguments from the implementation
2469+
std::map<std::string,std::shared_ptr<Entry>> methodMap;
2470+
for(auto &ct: ce->children())
2471+
{
2472+
if (ct->section != Entry::FUNCTION_SEC)
2473+
continue;
2474+
2475+
if (ct->type=="generic")
2476+
continue;
2477+
2478+
if (ct->virt == Pure)
2479+
continue;
2480+
2481+
// set up the procMap
2482+
if (!procMapCreated)
2483+
{
2484+
for(const auto &cf: scope->children())
2485+
{
2486+
if (cf->section == Entry::FUNCTION_SEC)
2487+
{
2488+
procMap.insert(std::make_pair(cf->name.str(), cf));
2489+
}
2490+
}
2491+
procMapCreated = true;
2492+
}
2493+
2494+
// found a (non-generic) method
2495+
QCString implName = ct->args;
2496+
if( procMap.find(implName.str()) != procMap.end() )
2497+
{
2498+
std::shared_ptr<Entry> proc = procMap[implName.str()];
2499+
ct->args = proc->args;
2500+
ct->argList = ArgumentList(proc->argList);
2501+
if (ct->brief.isEmpty())
2502+
{
2503+
ct->brief = proc->brief;
2504+
ct->briefLine = proc->briefLine;
2505+
ct->briefFile = proc->briefFile;
2506+
}
2507+
if (ct->doc.isEmpty())
2508+
{
2509+
ct->doc = proc->doc;
2510+
ct->docLine = proc->docLine;
2511+
ct->docFile = proc->docFile;
2512+
}
2513+
methodMap.insert(std::make_pair(ct->name.str(), ct));
2514+
}
2515+
}
2516+
2517+
// handle "deferred" methods (pure virtual functions), duplicating with arguments from the target abstract interface
2518+
for(auto &ct: ce->children())
2519+
{
2520+
if (ct->section != Entry::FUNCTION_SEC)
2521+
continue;
2522+
2523+
if (ct->virt != Pure)
2524+
continue;
2525+
2526+
// set up the procMap
2527+
if (!interfMapCreated)
2528+
{
2529+
for(const auto &cf: scope->children())
2530+
{
2531+
if (cf->section == Entry::CLASS_SEC && cf->spec & Entry::Interface && cf->type == "abstract")
2532+
{
2533+
std::shared_ptr<Entry> ci = cf->children().front();
2534+
interfMap.insert(std::make_pair(ci->name.str(), ci));
2535+
}
2536+
}
2537+
interfMapCreated = true;
2538+
}
2539+
2540+
// found a (non-generic) method
2541+
QCString implName = ct->args;
2542+
if( interfMap.find(implName.str())!= interfMap.end() )
2543+
{
2544+
std::shared_ptr<Entry> proc = interfMap[implName.str()];
2545+
ct->args = proc->args;
2546+
ct->argList = ArgumentList(proc->argList);
2547+
if (ct->brief.isEmpty())
2548+
{
2549+
ct->brief = proc->brief;
2550+
ct->briefLine = proc->briefLine;
2551+
ct->briefFile = proc->briefFile;
2552+
}
2553+
if (ct->doc.isEmpty())
2554+
{
2555+
ct->doc = proc->doc;
2556+
ct->docLine = proc->docLine;
2557+
ct->docFile = proc->docFile;
2558+
}
2559+
2560+
methodMap.insert(std::make_pair(ct->name.str(), ct));
2561+
}
2562+
}
2563+
2564+
// handle "generic" methods (that is function overloading!), duplicating with arguments from the target method of the type
2565+
{
2566+
for(auto &ct: ce->children())
2567+
{
2568+
if (ct->section != Entry::FUNCTION_SEC)
2569+
continue;
2570+
2571+
if (ct->type!="generic")
2572+
continue;
2573+
2574+
// found a generic method (already duplicated for each entry by the parser)
2575+
QCString methodName = ct->args;
2576+
if( methodMap.find(methodName.str()) != methodMap.end() )
2577+
{
2578+
std::shared_ptr<Entry> method = methodMap[methodName.str()];
2579+
ct->args = method->args;
2580+
ct->argList = ArgumentList(method->argList);
2581+
if (ct->brief.isEmpty())
2582+
{
2583+
ct->brief = method->brief;
2584+
ct->briefLine = method->briefLine;
2585+
ct->briefFile = method->briefFile;
2586+
}
2587+
if (ct->doc.isEmpty())
2588+
{
2589+
ct->doc = method->doc;
2590+
ct->docLine = method->docLine;
2591+
ct->docFile = method->docFile;
2592+
}
2593+
}
2594+
}
2595+
}
2596+
}
2597+
}
2598+
2599+
24012600
static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
24022601
{
24032602
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;

src/memberdef.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -4469,6 +4469,10 @@ void MemberDefImpl::_computeIsDestructor()
44694469
{
44704470
isDestructor=TRUE;
44714471
}
4472+
else if (getLanguage()==SrcLangExt_Fortran) // for Fortran
4473+
{
4474+
isDestructor = typeString()=="final";
4475+
}
44724476
else // other languages
44734477
{
44744478
isDestructor =

0 commit comments

Comments
 (0)