Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getDefs fails to resolve local function names if same global name exist. (Origin: bugzilla #656694) #4365

Open
doxygen opened this issue Jul 2, 2018 · 8 comments

Comments

@doxygen
Copy link
Owner

doxygen commented Jul 2, 2018

status NEW severity major in component general for ---
Reported in version 1.8.2-SVN on platform Other
Assigned to: Dimitri van Heesch

Original attachment names and IDs:

On 2011-08-16 20:02:36 +0000, Henrik wrote:

In case of multiple source files that define and implement same function
names, the resolution of the names in util.cpp method getDefs creates a link
to the first defined function. This leads to strange call/caller graphs,
where links are generated to otherwise unrelated source code.

After _MUCH_ tracing and debugging basically starting from the graph
generation and move backwards to the code.l and finally locating the problem
code in util.cpp. There is a lot of code in getDefs, (who is the happy
coder?), so I might not have covered all situations, but now doxygen
generates much better call/caller graphs for me.

The core of the fix is approx line 4090. Stop the loop if the currentFile
matches the file name of the member definition:

bool goodMatch=false;
while (md && !goodMatch)
{
  members.append(md);
  if(currentFile&&fd&&currentFile->getPath()==fd->getPath() &&
currentFile->localName()==fd->localName()) goodMatch=true;
}

Please consider applying or suggest a better fix.

Here is the patch with the debugging code left in.

Index: src/util.cpp
===================================================================
--- src/util.cpp	(revision 772)
+++ src/util.cpp	(working copy)
@@ -3714,7 +3766,7 @@
     FileDef *currentFile,
     bool checkCV
     )
-{
+{ bool debug=false;
   fd=0, md=0, cd=0, nd=0, gd=0;
   if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link
*/
 
@@ -3733,8 +3785,10 @@
     scopeName=scopeName.left(is); 
     pm=im+2;
   }
-  //printf("result after scope corrections scope=%s name=%s\n",
-  //          scopeName.data(),memberName.data());
+
+  //if(debug)
+  //printf("--- --- util.cpp getDefs: result after scope corrections
scope=%s, name=%s, current file %s\n",
+  //
scopeName.data(),memberName.data(),currentFile->localName().data());
 
   QCString mName=memberName;
   QCString mScope;
@@ -3754,7 +3808,7 @@
   //printf("mScope=`%s' mName=`%s'\n",mScope.data(),mName.data());
 
   MemberName *mn = Doxygen::memberNameSDict->find(mName);
-  //printf("mName=%s mn=%p\n",mName.data(),mn);
+  //if(debug) printf("--- --- mName=%s mn=%p\n",mName.data(),mn);
 
   if ((!forceEmptyScope || scopeName.isEmpty()) && // this was changed for
bug638856, forceEmptyScope => empty scopeName
       mn && !(scopeName.isEmpty() && mScope.isEmpty()))
@@ -3774,7 +3828,8 @@
       }
 
       ClassDef *fcd=getResolvedClass(Doxygen::globalScope,0,className);
-      //printf("Trying class scope %s: %p\n",className.data(),fcd);
+      if(debug) printf("--- --- Trying class scope %s: isLinkable %i,
maxInheritanceDepth
%i\n",className.data(),(fcd&&fcd->isLinkable()),maxInheritanceDepth);
+
       // todo: fill in correct fileScope!
       if (fcd &&  // is it a documented class
           fcd->isLinkable() 
@@ -3821,7 +3876,7 @@
         {
           delete argList; argList=0;
         }
-        if (mdist==maxInheritanceDepth && args && strcmp(args,"()")==0)
+        if (mdist==maxInheritanceDepth && args && strcmp(args,"()")==0) //
XXX
           // no exact match found, but if args="()" an arbitrary member
will do
         {
           //printf("  >Searching for arbitrary member\n");
@@ -3919,11 +3974,12 @@
 
 
   // maybe an namespace, file or group member ?
+  //if(debug)
   //printf("Testing for global symbol scopeName=`%s' mScope=`%s' ::
mName=`%s'\n",
   //              scopeName.data(),mScope.data(),mName.data());
   if ((mn=Doxygen::functionNameSDict->find(mName))) // name is known
   {
-    //printf("  >symbol name found\n");
+    //if(debug) printf("  >symbol name %s found\n",mName.data());
     NamespaceDef *fnd=0;
     int scopeOffset=scopeName.length();
     do
@@ -3943,14 +3999,14 @@
           fnd->isLinkable()
          )
       {
-        //printf("Function inside existing namespace
`%s'\n",namespaceName.data());
+        //if(debug) printf("Function inside existing namespace
`%s'\n",namespaceName.data());
         bool found=FALSE;
         MemberListIterator mmli(*mn);
         MemberDef *mmd;
         for (mmli.toFirst();((mmd=mmli.current()) && !found);++mmli)
         {
-          //printf("mmd->getNamespaceDef()=%p fnd=%p\n",
-          //    mmd->getNamespaceDef(),fnd);
+          //if(debug) printf("mmd->getNamespaceDef()=%p
fnd=%p\n",mmd->getNamespaceDef(),fnd);
+
           if (mmd->getNamespaceDef()==fnd /* && mmd->isLinkable() */ )
           { // namespace is found
             bool match=TRUE;
@@ -3963,7 +4019,7 @@
               match=matchArguments2(
                   mmd->getOuterScope(),mmd->getFileDef(),mmdAl.pointer(),
                   fnd,mmd->getFileDef(),argList,
-                  checkCV); 
+                  checkCV);
             }
             if (match)
             {
@@ -3997,12 +4053,14 @@
           {
             md=0; // avoid returning things we cannot link to
             nd=0;
+            if (debug) printf("--- --a util.cpp getDefs returns FALSE");
             return FALSE; // match found but not linkable
           }
           else
           {
             gd=md->getGroupDef();
             if (gd && gd->isLinkable()) nd=0; else gd=0;
+            if (debug) printf("--- --b util.cpp getDefs returns TRUE");
             return TRUE;
           }
         }
@@ -4031,11 +4089,16 @@
       {
         // no exact match found, but if args="()" an arbitrary 
         // member will do
+    	bool goodMatch=false;
         md=mn->last();
-        while (md /* && md->isLinkable()*/)
+        while (md /* && md->isLinkable()*/ &&!goodMatch)
         {
-          //printf("Found member `%s'\n",md->name().data());
-          //printf("member is linkable
md->name()=`%s'\n",md->name().data());
+          if (debug)
+          {
+           printf("--- *** util.cpp getDefs Found member %s
",md->name().data());
+            printf("member is linkable md->name()=%s ",md->name().data());
+            printf("file=%s\n",md->getFileDef()->localName().data());
+          }
           fd=md->getFileDef();
           gd=md->getGroupDef();
           if (
@@ -4043,6 +4106,7 @@
              )
           {
             members.append(md);
+            if(currentFile&&fd&&currentFile->getPath()==fd->getPath() &&
currentFile->localName()==fd->localName()) goodMatch=true;
           }
           md=mn->prev();
         }
@@ -4057,6 +4121,7 @@
         fd=md->getFileDef();
         gd=md->getGroupDef();
         //printf("fd=%p gd=%p
gd->isLinkable()=%d\n",fd,gd,gd->isLinkable());
+        if (debug) printf("--- --c util.cpp getDefs returns TRUE. File =
%s, CurrentFile=%s
\n",fd->localName().data(),currentFile->localName().data());
         if (gd && gd->isLinkable()) fd=0; else gd=0;
         return TRUE;
       }
@@ -4064,6 +4129,8 @@
   }
 
   // no nothing found
+  if (debug) printf("--- --d util.cpp getDefs returns FALSE");
+
   return FALSE;
 }

On 2011-08-17 21:24:07 +0000, Henrik wrote:

Created attachment 194085
util.cpp getDefs: stop loop if filename matches currentFile

This is a patch against latest in SVN with just the change.

On 2011-10-04 17:41:27 +0000, Henrik wrote:

Created attachment 198236
Resolving duplicated external names in util.cpp/getDefs

This patch implements the following two strategies for resolving duplicated
names. First, is the name is defined in current file, use the local name.
Secondly try to match the names using the prototype definition.

On 2012-01-11 18:01:46 +0000, Henrik wrote:

Any comments to this patch?

On 2012-11-18 11:08:01 +0000, Dimitri van Heesch wrote:

Changed version 'latest' to '1.8.2-SVN' so I can remove 'latest' as an
option as it is a moving target.
@jrwrigh
Copy link

jrwrigh commented Jan 8, 2020

Any movement/updates on this? Still a problem for me right now. I'm running doxygen 1.8.16

Obviously the patch is going to be out of date, but I may be able to work on something like this if it's simply taking the attached patch and fixing it up to match the modern functionality.

@jrwrigh
Copy link

jrwrigh commented Jan 8, 2020

Fixing this would resolve #3676, #5448, #979, and #3676 (note this last one is already closed by user).

Also, if this gets updated, probably good to update the related StackOverflow question as well.

Also, if this should be moved to a separate issue, let me know.

@fredleb
Copy link

fredleb commented May 7, 2020

The same problem exist for C++ enums.

If you have several of them with the same name, they get concatenated into a single one visible in the doc only in the first parsed file...

@mcandre
Copy link

mcandre commented Nov 19, 2020

A doc tool that blows up on duplicate entity names, rather than providing simple tools for users to help the doc generator to disambiguate, would not be a very practical tool for medium to large projects.

@Digicrat
Copy link

I'm hitting the same/similar problem for C typedef structs. Only one of the definitions is documented (and not the one I need).

Annoyingly, even the PERLMOD output I'm trying to use for some custom parsing doesn't list the duplicate entry.

@albert-github
Copy link
Collaborator

@Digicrat

  • the perlmod is not one of the output formats that is, in my view, used often and as far as I can see not a lot of changes / corrections have specifically been made in the recent past for perlmod.

  • the

    I'm hitting the same/similar problem for C typedef structs. Only one of the definitions is documented (and not the one I need).

    is a bit vague:

    • Can you please attach a, small, self contained example (source+configuration file in a tar or zip) that allows us to reproduce the problem? Please don't add external links as they might not be persistent.
    • Please also specify the full doxygen version used (doxygen -v).

@Digicrat
Copy link

Digicrat commented May 26, 2021

I previously saw this issue with Doxygen 1.8.x, currently on 1.9.1 with the same issue.

The following header files (also attached) represent a minimal contrived test case (this particular example could obviously be written in a saner way, but similar situations are sometimes unavoidable in complex projects, particularly those that include third-party auto-generated code) for both the missing duplicate struct and duplicate function issues. While I wouldn't expect Doxygen to necessarily link to the correct version of the definition in the HTML output, I would expect it's full listing of types (and the file-specific page for html output) to include the duplicate typedef/function in all output formats.

Doxygen file created with "doxygen -g" with the following changes:

  • OPTIMIZE_OUTPUT_FOR_C = YES
  • GENERATE_PERLMOD = YES
  • EXTRACT_STATIC = YES

file1.h


#ifdef SOME_COND

typedef struct foo_t {
   int a;
   int b;
   float c;
} foo_t;

static inline void fnfoo(foot_t *foo, int a, int b, float c) {
   foo->a = a;
   foo->b = b;
   foo->c = c;
}

#endif

file2.h


#ifndef SOME_COND

typedef struct foo_t {
   int a;
   int b;
   float c;
   double extra_a;
   float extra_b;
} foo_t;

static inline void fnfoo(foot_t *foo, int a, int b, float c, double d, float e) {
   foo->a = a;
   foo->b = b;
   foo->c = c;
   foo->extra_a = d;
   foo->extra_b = e;
}


#endif

doxy_conflicting_types.tar.gz

@albert-github
Copy link
Collaborator

I your initial comment you wrote:

Only one of the definitions is documented (and not the one I need).

When looking at the output (html and perlmod) of file1.h and file2.h I see that the information of file2.h is present.
This is, in my opinion logical as in the file file1.h we see:

#ifdef SOME_COND

and in file2.h:

#ifndef SOME_COND

and there is no evidence that SOME_COND is set anywhere.

So as far as I can see your problem is usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants